diff --git a/webodf/tools/odfRng2Config.js b/webodf/tools/odfRng2Config.js
index a48bb1ce4..1b2f1d81e 100644
--- a/webodf/tools/odfRng2Config.js
+++ b/webodf/tools/odfRng2Config.js
@@ -22,28 +22,73 @@
* @source: https://github.com/kogmbh/WebODF/
*/
-function aggregate(callback) {
- return function (collection, individual) {
- return collection.concat(callback(individual));
- };
-}
+"use strict";
-function toArray(nodeList) {
- "use strict";
- return Array.prototype.slice.call(nodeList);
+var rngns = "http://relaxng.org/ns/structure/1.0";
+
+/**
+ * Check if a node is an element in the rng namespace and the given localName.
+ * @param {!string} localName
+ * @param {!Node} node
+ * @return {!boolean}
+ */
+function isRng(localName, node) {
+ if (node.nodeType !== 1) {
+ return false;
+ }
+ if (node.namespaceURI !== rngns) {
+ return false;
+ }
+ if (node.localName !== localName) {
+ return false;
+ }
+ return true;
}
-function getName(node) {
- return node && node.getAttribute("name");
+/**
+ * @param {!Node} node
+ * @return {?Element}
+ */
+function getFirstElementNode(node) {
+ node = node.firstChild;
+ while (node && node.nodeType !== 1) {
+ node = node.nextSibling;
+ }
+ return node;
}
+/**
+ * Return all explicit names for an or element.
+ * and return nothing.
+ *
+ * @param {!Node} node
+ * @return {!Array.}
+ */
function getNames(node) {
- var name = getName(node);
- return name ? [name] : toArray(node.getElementsByTagName("name")).map(function (node) {
- return node.textContent;
- });
+ var names = [];
+ if (node.hasAttribute("name")) {
+ names.push(node.getAttribute("name"));
+ } else {
+ node = getFirstElementNode(node);
+ if (isRng("choice", node)) {
+ node = getFirstElementNode(node);
+ }
+ while (node) {
+ if (isRng("name", node)) {
+ names.push(node.textContent);
+ }
+ node = node.nextSibling;
+ }
+ }
+ return names;
}
+/**
+ * Increase length of string by adding spaces.
+ * @param {!string} str
+ * @param {!number} length
+ * @return {!string}
+ */
function pad(str, length) {
while (str.length < length) {
str += " ";
@@ -52,58 +97,174 @@ function pad(str, length) {
}
/**
- * Extract container node information out of the supplied RNG schema document.
- * This only does extremely simplistic parsing.
- *
- * @constructor
- * @param {!Document} document
+ * Get all the elements from an RNG grammar.
+ * @param {!Element} grammar
+ * @return {!Object.}
*/
-function ExtractContainerInfo(document) {
- /**
- * @param {!Node} node
- * @return {!Array.}
- */
- function findParentElements(node) {
- var refs;
-
- while (node && /(define|element)/.test(node.localName) === false) {
- node = node.parentNode;
+function getDefines(grammar) {
+ var defines = {},
+ c = grammar.firstChild;
+ while (c) {
+ if (c.nodeType === 1 && isRng("define", c)) {
+ defines[c.getAttribute("name")] = c;
}
+ c = c.nextSibling;
+ }
+ return defines;
+}
- if (node) {
- if (node.localName === "element") {
- return [node];
+/**
+ * Information about an attribute or element.
+ * @constructor
+ */
+function Info() {
+ /**@type {!Object.}*/
+ this.refs = {};
+ /**@type {!boolean}*/
+ this.text = false;
+ /**@type {!boolean}*/
+ this.data = false;
+ /**@type {!boolean}*/
+ this.value = false;
+ /**@type {!Array. to that of or .
+ * @param {!Info} info
+ * @param {!string} ref
+ * @param {!Object.} defines
+ * @return {undefined}
+ */
+function addDefine(info, ref, defines) {
+ var define = defines[ref],
+ c;
+ if (define) {
+ info.text = info.text || define.text;
+ info.data = info.data || define.data;
+ info.value = info.value || define.value;
+ define.childElements.forEach(function (ce) {
+ if (info.childElements.indexOf(ce) === -1) {
+ info.childElements.push(ce);
}
- refs = toArray(document.querySelectorAll("ref[name='" + getName(node) + "']"));
- return refs.reduce(aggregate(findParentElements), []);
- }
- return [];
+ });
+ define.attributes.forEach(function (a) {
+ if (info.attributes.indexOf(a) === -1) {
+ info.attributes.push(a);
+ }
+ });
}
+}
- this.getTextElements = function() {
- return toArray(document.getElementsByTagName("text")).reduce(aggregate(findParentElements), []);
- };
+/**
+ * Add information from elements to the set of or
+ * elements.
+ * @param {!Object.} infos
+ * @param {!Object.} defines
+ * @return {undefined}
+ */
+function resolveDefines(infos, defines) {
+ Object.keys(infos).forEach(function (name) {
+ var info = infos[name];
+ Object.keys(info.refs).forEach(function (ref) {
+ addDefine(info, ref, defines);
+ });
+ });
+}
+
+/**
+ * Recursively collect information from all elements in an RNG grammar.
+ * If a is encountered, the corresponding is traversed.
+ * This is done only once for each .
+ *
+ * @param {!Element} e
+ * @param {!Object.