Add <edit:script> and custom replacement functions; keep track of which spec each imported definitions file comes from.
authorCameron McCormack <cam@mcc.id.au>
Sun, 07 Apr 2013 16:03:59 +1000
changeset 78 6b530890be51
parent 77 c442b4de16ac
child 79 acecf885de3c
Add <edit:script> and custom replacement functions; keep track of which spec each imported definitions file comes from.
publish/config.js
publish/definitions.js
publish/processing.js
--- a/publish/config.js	Sat Apr 06 16:49:30 2013 +1100
+++ b/publish/config.js	Sun Apr 07 16:03:59 2013 +1000
@@ -145,13 +145,21 @@
   this.attributeIndex = attr(root, 'attributeindex', 'href');
   this.propertyIndex = attr(root, 'propertyindex', 'href');
 
-  var definitionsFilenamesAndBases = [];
+  var definitionInfos = [];
   for (var n = root.firstChild; n; n = n.nextSibling) {
     if (n.nodeName == 'definitions') {
-      definitionsFilenamesAndBases.push([n.getAttribute('href'), n.getAttribute('base') || null]);
+      definitionInfos.push({
+        href: n.getAttribute('href'),
+        base: n.getAttribute('base') || null,
+        specid: n.getAttribute('specid') || null,
+        mainspec: n.getAttribute('mainspec') || null
+      });
     }
   }
-  this.definitions = definitions.load(definitionsFilenamesAndBases.reverse());
+  var allDefinitions = definitions.load(definitionInfos);
+  this.definitions = allDefinitions.definitions;
+  this.definitionsBySpec = allDefinitions.definitionsBySpec;
+  this.definitionMainSpecs = allDefinitions.mainSpecs;
 
   this.resources = [];
   for (var n = root.firstChild; n; n = n.nextSibling) {
--- a/publish/definitions.js	Sat Apr 06 16:49:30 2013 +1100
+++ b/publish/definitions.js	Sun Apr 07 16:03:59 2013 +1000
@@ -299,7 +299,7 @@
   return (element || attribute || property).formatLink(omitQuotes);
 };
 
-function loadInto(filename, base, defs) {
+function loadInto(filename, base, specid, defs) {
   var doc = utils.parseXML(filename);
 
   // XXX Handle <import>.
@@ -315,14 +315,16 @@
       commonAttributes: utils.splitList(e.getAttribute('attributes')),
       interfaces: utils.splitList(e.getAttribute('interfaces')),
       specificAttributes: [],
-      categories: { }
+      categories: { },
+      specid: specid
     });
 
     forEachChild(e, 'attribute', function(c) {
       element.specificAttributes.push(new Attribute({
         name: c.getAttribute('name'),
         href: utils.resolveURL(base, c.getAttribute('href')),
-        animatable: c.getAttribute('animatable') == 'yes'
+        animatable: c.getAttribute('animatable') == 'yes',
+        specid: specid
       }));
     });
 
@@ -337,7 +339,8 @@
     var category = new ElementCategory({
       name: ec.getAttribute('name'),
       href: utils.resolveURL(base, ec.getAttribute('href')),
-      elements: utils.splitList(ec.getAttribute('elements'))
+      elements: utils.splitList(ec.getAttribute('elements')),
+      specid: specid
     });
 
     defs.elementCategories[category.name] = category;
@@ -347,7 +350,8 @@
     var attribute = new Attribute({
       name: a.getAttribute('name'),
       href: utils.resolveURL(base, a.getAttribute('href')),
-      animatable: a.getAttribute('animatable') == 'yes'
+      animatable: a.getAttribute('animatable') == 'yes',
+      specid: specid
     });
     if (a.hasAttribute('elements')) {
       attribute.elements = utils.set(utils.splitList(a.getAttribute('elements')));
@@ -363,14 +367,16 @@
       href: utils.resolveURL(base, ac.getAttribute('href')),
       attributes: [],
       commonAttributes: utils.splitList(ac.getAttribute('attributes')),
-      presentationAttributes: utils.splitList(ac.getAttribute('presentationattributes'))
+      presentationAttributes: utils.splitList(ac.getAttribute('presentationattributes')),
+      specid: specid
     });
 
     forEachChild(ac, 'attribute', function(a) {
       category.attributes.push(new Attribute({
         name: a.getAttribute('name'),
         href: utils.resolveURL(base, a.getAttribute('href')),
-        animatable: a.getAttribute('animatable') == 'yes'
+        animatable: a.getAttribute('animatable') == 'yes',
+        specid: specid
       }));
     });
 
@@ -381,6 +387,7 @@
     var property = new Property({
       name: p.getAttribute('name'),
       href: utils.resolveURL(base, p.getAttribute('href')),
+      specid: specid
     });
 
     defs.properties[property.name] = property;
@@ -388,7 +395,8 @@
     var presentationAttribute = new Attribute({
       name: property.name,
       href: property.href,
-      property: property.name
+      property: property.name,
+      specid: specid
     });
     defs.presentationAttributes[property.name] = presentationAttribute;
   });
@@ -397,6 +405,7 @@
     var intf = new Interface({
       name: i.getAttribute('name'),
       href: utils.resolveURL(base, i.getAttribute('href')),
+      specid: specid
     });
 
     defs.interfaces[intf.name] = intf;
@@ -406,6 +415,7 @@
     var symbol = new Symbol({
       name: s.getAttribute('name'),
       href: utils.resolveURL(base, s.getAttribute('href')),
+      specid: specid
     });
 
     defs.symbols[symbol.name] = symbol;
@@ -415,6 +425,7 @@
     var term = new Term({
       name: t.getAttribute('name'),
       href: utils.resolveURL(base, t.getAttribute('href')),
+      specid: specid
     });
 
     if (t.firstChild) {
@@ -425,14 +436,15 @@
   });
 }
 
-function resolve(defs) {
+function resolve(defs, mainspecDefs) {
   for (var name in defs.elements) {
     var element = defs.elements[name];
     element.attributes = { };
     element.attributeOrder = [];
     for (var i = 0; i < element.attributeCategories.length; i++) {
       var catName = element.attributeCategories[i];
-      var cat = defs.attributeCategories[catName];
+      var cat = defs.attributeCategories[catName] ||
+                mainspecDefs && mainspecDefs.attributeCategories[catName];
       if (cat) {
         for (var j = 0; j < cat.attributes.length; j++) {
           element.attributes[cat.attributes[j].name] = cat.attributes[j];
@@ -440,6 +452,15 @@
         }
       }
     }
+    if (mainspecDefs) {
+      for (var i = 0; i < mainspecDefs.commonAttributesForElements.length; i++) {
+        var attr = mainspecDefs.commonAttributesForElements[i];
+        if (attr.elements[element.name]) {
+          element.attributes[attr.name] = attr;
+          element.attributeOrder.push(attr.name);
+        }
+      }
+    }
     for (var i = 0; i < defs.commonAttributesForElements.length; i++) {
       var attr = defs.commonAttributesForElements[i];
       if (attr.elements[element.name]) {
@@ -449,8 +470,10 @@
     }
     for (var i = 0; i < element.commonAttributes.length; i++) {
       var attrName = element.commonAttributes[i];
-      if (defs.commonAttributes[attrName]) {
-        element.attributes[attrName] = defs.commonAttributes[attrName];
+      var commonAttribute = defs.commonAttributes[attrName] ||
+                            mainspecDefs && mainspecDefs.commonAttributes[attrName];
+      if (commonAttribute) {
+        element.attributes[attrName] = commonAttribute;
         element.attributeOrder.push(attrName);
       }
     }
@@ -461,20 +484,55 @@
     }
   }
 
+  if (mainspecDefs) {
+    for (var name in mainspecDefs.elementCategories) {
+      var cat = mainspecDefs.elementCategories[name];
+      for (var i = 0; i < cat.elements.length; i++) {
+        var eltName = cat.elements[i];
+        if (defs.elements[eltName]) {
+          defs.elements[eltName].categories[name] = cat;
+        }
+      }
+    }
+  }
   for (var name in defs.elementCategories) {
     var cat = defs.elementCategories[name];
     for (var i = 0; i < cat.elements.length; i++) {
       var eltName = cat.elements[i];
-      defs.elements[eltName].categories[name] = cat;
+      var elt = defs.elements[eltName] ||
+                mainspecDefs && mainspecDefs.elements[eltName];
+      if (elt) {
+        elt.categories[name] = cat;
+      }
     }
   }
 }
 
-exports.load = function(filenamesAndBases) {
+exports.load = function(infos) {
   var defs = new Definitions();
-  for (var i = 0; i < filenamesAndBases.length; i++) {
-    loadInto(filenamesAndBases[i][0], filenamesAndBases[i][1], defs);
+  var defsBySpec = { };
+  var mainSpecs = { };
+  infos.reverse();
+  for (var i = 0; i < infos.length; i++) {
+    var href = infos[i].href;
+    var base = infos[i].base;
+    var specid = infos[i].specid;
+    loadInto(href, base, specid, defs);
+    if (specid) {
+      defsBySpec[specid] = new Definitions();
+      loadInto(href, base, specid, defsBySpec[specid]);
+    }
+  }
+  for (var i = 0; i < infos.length; i++) {
+    var specid = infos[i].specid;
+    if (specid) {
+      var mainspec = infos[i].mainspec;
+      resolve(defsBySpec[specid], mainspec && defsBySpec[mainspec]);
+      if (mainspec) {
+        mainSpecs[specid] = mainspec;
+      }
+    }
   }
   resolve(defs);
-  return defs;
+  return { definitions: defs, definitionsBySpec: defsBySpec, mainSpecs: mainSpecs };
 };
--- a/publish/processing.js	Sat Apr 06 16:49:30 2013 +1100
+++ b/publish/processing.js	Sun Apr 07 16:03:59 2013 +1000
@@ -670,32 +670,48 @@
   return utils.replace(n, n.ownerDocument.createTextNode(conf.shortTitle));
 }
 
+function doScript(conf, page, n) {
+  with ({ processing: exports,
+          utils: utils,
+          namespaces: namespaces }) {
+    eval(n.textContent);
+  }
+}
+
+var replacementFunctions = {
+  minitoc: doMiniTOC,
+  fulltoc: doFullTOC,
+  completeidl: doCompleteIDL,
+  interface: doInterface,
+  example: doExample,
+  includefile: doIncludeFile,
+  elementsummary: doElementSummary,
+  maturity: doLongMaturity,
+  date: doDate,
+  thisversion: doThisVersion,
+  latestversion: doLatestVersion,
+  includelatesteditorsdraft: doIncludeLatestEditorsDraft,
+  previousversion: doPreviousVersion,
+  copyright: doCopyright,
+  locallink: doLocalLink,
+  attributetable: doAttributeTable,
+  elementindex: doElementIndex,
+  elementcategory: doElementCategory,
+  attributecategory: doAttributeCategory,
+  elementswithattributecategory: doElementsWithAttributeCategory,
+  whenpublished: doWhenPublished,
+  shorttitle: doShortTitle,
+  script: doScript
+};
+
+exports.defineReplacement = function(elementName, fn) {
+  if (replacementFunctions[elementName]) {
+    throw 'replacement function for <edit:' + elementName + '> already defined';
+  }
+  replacementFunctions[elementName] = fn;
+};
+
 exports.processReplacements = function(conf, page, doc) {
-  var replacementFunctions = {
-    minitoc: doMiniTOC,
-    fulltoc: doFullTOC,
-    completeidl: doCompleteIDL,
-    interface: doInterface,
-    example: doExample,
-    includefile: doIncludeFile,
-    elementsummary: doElementSummary,
-    maturity: doLongMaturity,
-    date: doDate,
-    thisversion: doThisVersion,
-    latestversion: doLatestVersion,
-    includelatesteditorsdraft: doIncludeLatestEditorsDraft,
-    previousversion: doPreviousVersion,
-    copyright: doCopyright,
-    locallink: doLocalLink,
-    attributetable: doAttributeTable,
-    elementindex: doElementIndex,
-    elementcategory: doElementCategory,
-    attributecategory: doAttributeCategory,
-    elementswithattributecategory: doElementsWithAttributeCategory,
-    whenpublished: doWhenPublished,
-    shorttitle: doShortTitle
-  };
-
   utils.forEachNode(doc, function(n) {
     if (n.nodeType == n.ELEMENT_NODE &&
         n.namespaceURI == namespaces.edit &&