mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-20 15:27:32 +09:00
180 lines
6.1 KiB
JavaScript
180 lines
6.1 KiB
JavaScript
/* -*- 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;
|
|
};
|
|
})();
|