/*\ title: $:/core/modules/utils/fakedom.js type: application/javascript module-type: global A barebones implementation of DOM interfaces needed by the rendering mechanism. \*/ (function(){ /*jslint node: true, browser: true */ /*global $tw: false */ "use strict"; // Sequence number used to enable us to track objects for testing var sequenceNumber = null; var bumpSequenceNumber = function(object) { if(sequenceNumber !== null) { object.sequenceNumber = sequenceNumber++; } }; var TW_Node = function (){ throw TypeError("Illegal constructor"); }; Object.defineProperty(TW_Node.prototype, 'ELEMENT_NODE', { get: function() { return 1; } }); Object.defineProperty(TW_Node.prototype, 'TEXT_NODE', { get: function() { return 3; } }); var TW_TextNode = function(text) { bumpSequenceNumber(this); this.textContent = text + ""; }; Object.setPrototypeOf(TW_TextNode,TW_Node.prototype); Object.defineProperty(TW_TextNode.prototype, "nodeType", { get: function() { return this.TEXT_NODE; } }); Object.defineProperty(TW_TextNode.prototype, "formattedTextContent", { get: function() { return this.textContent.replace(/(\r?\n)/g,""); } }); var TW_Element = function(tag,namespace) { bumpSequenceNumber(this); this.isTiddlyWikiFakeDom = true; this.tag = tag; this.attributes = {}; this.isRaw = false; this.children = []; this._style = {}; this.namespaceURI = namespace || "http://www.w3.org/1999/xhtml"; }; Object.setPrototypeOf(TW_Element,TW_Node.prototype); Object.defineProperty(TW_Element.prototype, "style", { get: function() { return this._style; }, set: function(str) { var self = this; str = str || ""; $tw.utils.each(str.split(";"),function(declaration) { var parts = declaration.split(":"), name = $tw.utils.trim(parts[0]), value = $tw.utils.trim(parts[1]); if(name && value) { self._style[$tw.utils.convertStyleNameToPropertyName(name)] = value; } }); } }); Object.defineProperty(TW_Element.prototype, "nodeType", { get: function() { return this.ELEMENT_NODE; } }); TW_Element.prototype.getAttribute = function(name) { if(this.isRaw) { throw "Cannot getAttribute on a raw TW_Element"; } return this.attributes[name]; }; TW_Element.prototype.setAttribute = function(name,value) { if(this.isRaw) { throw "Cannot setAttribute on a raw TW_Element"; } if(name === "style") { this.style = value; } else { this.attributes[name] = value + ""; } }; TW_Element.prototype.setAttributeNS = function(namespace,name,value) { this.setAttribute(name,value); }; TW_Element.prototype.removeAttribute = function(name) { if(this.isRaw) { throw "Cannot removeAttribute on a raw TW_Element"; } if($tw.utils.hop(this.attributes,name)) { delete this.attributes[name]; } }; TW_Element.prototype.appendChild = function(node) { this.children.push(node); node.parentNode = this; }; TW_Element.prototype.insertBefore = function(node,nextSibling) { if(nextSibling) { var p = this.children.indexOf(nextSibling); if(p !== -1) { this.children.splice(p,0,node); node.parentNode = this; } else { this.appendChild(node); } } else { this.appendChild(node); } }; TW_Element.prototype.removeChild = function(node) { var p = this.children.indexOf(node); if(p !== -1) { this.children.splice(p,1); } }; TW_Element.prototype.hasChildNodes = function() { return !!this.children.length; }; Object.defineProperty(TW_Element.prototype, "childNodes", { get: function() { return this.children; } }); Object.defineProperty(TW_Element.prototype, "firstChild", { get: function() { return this.children[0]; } }); TW_Element.prototype.addEventListener = function(type,listener,useCapture) { // Do nothing }; Object.defineProperty(TW_Element.prototype, "tagName", { get: function() { return this.tag || ""; } }); Object.defineProperty(TW_Element.prototype, "className", { get: function() { return this.attributes["class"] || ""; }, set: function(value) { this.attributes["class"] = value + ""; } }); Object.defineProperty(TW_Element.prototype, "value", { get: function() { return this.attributes.value || ""; }, set: function(value) { this.attributes.value = value + ""; } }); Object.defineProperty(TW_Element.prototype, "outerHTML", { get: function() { var output = [],attr,a,v; output.push("<",this.tag); if(this.attributes) { attr = []; for(a in this.attributes) { attr.push(a); } attr.sort(); for(a=0; a 0) { output.push(" style=\"",style.join(""),"\""); } } output.push(">"); if($tw.config.htmlVoidElements.indexOf(this.tag) === -1) { output.push(this.innerHTML); output.push(""); } return output.join(""); } }); Object.defineProperty(TW_Element.prototype, "innerHTML", { get: function() { if(this.isRaw) { return this.rawHTML; } else { var b = []; $tw.utils.each(this.children,function(node) { if(node instanceof TW_Element) { b.push(node.outerHTML); } else if(node instanceof TW_TextNode) { b.push($tw.utils.htmlTextEncode(node.textContent)); } }); return b.join(""); } }, set: function(value) { this.isRaw = true; this.rawHTML = value; this.rawTextContent = null; } }); Object.defineProperty(TW_Element.prototype, "textInnerHTML", { set: function(value) { if(this.isRaw) { this.rawTextContent = value; } else { throw "Cannot set textInnerHTML of a non-raw TW_Element"; } } }); Object.defineProperty(TW_Element.prototype, "textContent", { get: function() { if(this.isRaw) { if(this.rawTextContent === null) { return ""; } else { return this.rawTextContent; } } else { var b = []; $tw.utils.each(this.children,function(node) { b.push(node.textContent); }); return b.join(""); } }, set: function(value) { this.children = [new TW_TextNode(value)]; } }); Object.defineProperty(TW_Element.prototype, "formattedTextContent", { get: function() { if(this.isRaw) { return ""; } else { var b = [], isBlock = $tw.config.htmlBlockElements.indexOf(this.tag) !== -1; if(isBlock) { b.push("\n"); } if(this.tag === "li") { b.push("* "); } $tw.utils.each(this.children,function(node) { b.push(node.formattedTextContent); }); if(isBlock) { b.push("\n"); } return b.join(""); } } }); var document = { setSequenceNumber: function(value) { sequenceNumber = value; }, createElementNS: function(namespace,tag) { return new TW_Element(tag,namespace); }, createElement: function(tag) { return new TW_Element(tag); }, createTextNode: function(text) { return new TW_TextNode(text); }, compatMode: "CSS1Compat", // For KaTeX to know that we're not a browser in quirks mode isTiddlyWikiFakeDom: true }; exports.fakeDocument = document; })();