summaryrefslogtreecommitdiffstats
path: root/mailnews/base/util/JXON.js
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/base/util/JXON.js')
-rw-r--r--mailnews/base/util/JXON.js180
1 files changed, 180 insertions, 0 deletions
diff --git a/mailnews/base/util/JXON.js b/mailnews/base/util/JXON.js
new file mode 100644
index 000000000..509c9b5d8
--- /dev/null
+++ b/mailnews/base/util/JXON.js
@@ -0,0 +1,180 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// This is a modification of the JXON parsers found on the page
+// <https://developer.mozilla.org/en-US/docs/JXON>
+
+var EXPORTED_SYMBOLS = ["JXON"];
+
+var JXON = new (function() {
+ const sValueProp = "value"; /* you can customize these values */
+ const sAttributesProp = "attr";
+ const sAttrPref = "@";
+ const sElementListPrefix = "$";
+ const sConflictSuffix = "_"; // used when there's a name conflict with special JXON properties
+ const aCache = [];
+ const rIsNull = /^\s*$/;
+ const rIsBool = /^(?:true|false)$/i;
+
+ function parseText(sValue) {
+ //if (rIsNull.test(sValue))
+ // return null;
+ if (rIsBool.test(sValue))
+ return sValue.toLowerCase() === "true";
+ if (isFinite(sValue))
+ return parseFloat(sValue);
+ if (isFinite(Date.parse(sValue)))
+ return new Date(sValue);
+ return sValue;
+ };
+
+ function EmptyTree() {
+ }
+ EmptyTree.prototype = {
+ toString : function () {
+ return "null";
+ },
+ valueOf : function () {
+ return null;
+ },
+ };
+
+ function objectify(vValue) {
+ if (vValue === null)
+ return new EmptyTree();
+ else if (vValue instanceof Object)
+ return vValue;
+ else
+ return new vValue.constructor(vValue); // What does this? copy?
+ };
+
+ function createObjTree(oParentNode, nVerb, bFreeze, bNesteAttr) {
+ const nLevelStart = aCache.length;
+ const bChildren = oParentNode.hasChildNodes();
+ const bAttributes = oParentNode.attributes &&
+ oParentNode.attributes.length;
+ const bHighVerb = Boolean(nVerb & 2);
+
+ var sProp = 0;
+ var vContent = 0;
+ var nLength = 0;
+ var sCollectedTxt = "";
+ var vResult = bHighVerb ? {} : /* put here the default value for empty nodes: */ true;
+
+ if (bChildren) {
+ for (var oNode, nItem = 0; nItem < oParentNode.childNodes.length; nItem++) {
+ oNode = oParentNode.childNodes.item(nItem);
+ if (oNode.nodeType === 4) // CDATASection
+ sCollectedTxt += oNode.nodeValue;
+ else if (oNode.nodeType === 3) // Text
+ sCollectedTxt += oNode.nodeValue;
+ else if (oNode.nodeType === 1) // Element
+ aCache.push(oNode);
+ }
+ }
+
+ const nLevelEnd = aCache.length;
+ const vBuiltVal = parseText(sCollectedTxt);
+
+ if (!bHighVerb && (bChildren || bAttributes))
+ vResult = nVerb === 0 ? objectify(vBuiltVal) : {};
+
+ for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) {
+ sProp = aCache[nElId].nodeName;
+ if (sProp == sValueProp || sProp == sAttributesProp)
+ sProp = sProp + sConflictSuffix;
+ vContent = createObjTree(aCache[nElId], nVerb, bFreeze, bNesteAttr);
+ if (!vResult.hasOwnProperty(sProp)) {
+ vResult[sProp] = vContent;
+ vResult[sElementListPrefix + sProp] = [];
+ }
+ vResult[sElementListPrefix + sProp].push(vContent);
+ nLength++;
+ }
+
+ if (bAttributes) {
+ const nAttrLen = oParentNode.attributes.length;
+ const sAPrefix = bNesteAttr ? "" : sAttrPref;
+ const oAttrParent = bNesteAttr ? {} : vResult;
+
+ for (var oAttrib, nAttrib = 0; nAttrib < nAttrLen; nLength++, nAttrib++) {
+ oAttrib = oParentNode.attributes.item(nAttrib);
+ oAttrParent[sAPrefix + oAttrib.name] = parseText(oAttrib.value);
+ }
+
+ if (bNesteAttr) {
+ if (bFreeze)
+ Object.freeze(oAttrParent);
+ vResult[sAttributesProp] = oAttrParent;
+ nLength -= nAttrLen - 1;
+ }
+ }
+
+ if (nVerb === 3 || (nVerb === 2 || nVerb === 1 && nLength > 0) && sCollectedTxt)
+ vResult[sValueProp] = vBuiltVal;
+ else if (!bHighVerb && nLength === 0 && sCollectedTxt)
+ vResult = vBuiltVal;
+
+ if (bFreeze && (bHighVerb || nLength > 0))
+ Object.freeze(vResult);
+
+ aCache.length = nLevelStart;
+
+ return vResult;
+ };
+
+ function loadObjTree(oXMLDoc, oParentEl, oParentObj) {
+ var vValue, oChild;
+
+ if (oParentObj instanceof String || oParentObj instanceof Number ||
+ oParentObj instanceof Boolean)
+ oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toString())); /* verbosity level is 0 */
+ else if (oParentObj.constructor === Date)
+ oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toGMTString()));
+
+ for (var sName in oParentObj) {
+ vValue = oParentObj[sName];
+ if (isFinite(sName) || vValue instanceof Function)
+ continue; /* verbosity level is 0 */
+ if (sName === sValueProp) {
+ if (vValue !== null && vValue !== true) {
+ oParentEl.appendChild(oXMLDoc.createTextNode(
+ vValue.constructor === Date ? vValue.toGMTString() : String(vValue)));
+ }
+ } else if (sName === sAttributesProp) { /* verbosity level is 3 */
+ for (var sAttrib in vValue)
+ oParentEl.setAttribute(sAttrib, vValue[sAttrib]);
+ } else if (sName.charAt(0) === sAttrPref) {
+ oParentEl.setAttribute(sName.slice(1), vValue);
+ } else if (vValue.constructor === Array) {
+ for (var nItem = 0; nItem < vValue.length; nItem++) {
+ oChild = oXMLDoc.createElement(sName);
+ loadObjTree(oXMLDoc, oChild, vValue[nItem]);
+ oParentEl.appendChild(oChild);
+ }
+ } else {
+ oChild = oXMLDoc.createElement(sName);
+ if (vValue instanceof Object)
+ loadObjTree(oXMLDoc, oChild, vValue);
+ else if (vValue !== null && vValue !== true)
+ oChild.appendChild(oXMLDoc.createTextNode(vValue.toString()));
+ oParentEl.appendChild(oChild);
+ }
+ }
+ };
+
+ this.build = function(oXMLParent, nVerbosity /* optional */, bFreeze /* optional */, bNesteAttributes /* optional */) {
+ const _nVerb = arguments.length > 1 &&
+ typeof nVerbosity === "number" ? nVerbosity & 3 :
+ /* put here the default verbosity level: */ 1;
+ return createObjTree(oXMLParent, _nVerb, bFreeze || false,
+ arguments.length > 3 ? bNesteAttributes : _nVerb === 3);
+ };
+
+ this.unbuild = function(oObjTree) {
+ const oNewDoc = document.implementation.createDocument("", "", null);
+ loadObjTree(oNewDoc, oNewDoc, oObjTree);
+ return oNewDoc;
+ };
+})();