1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2024-06-25 23:03:15 +00:00
TiddlyWiki5/core/modules/utils/fakedom.js
Jermolene b1ecf81b0c Tentative improvements to highlight plugin problems
We now use highlight.js in raw HTML mode on the server, rather than
trying to use it with the fakedom. This causes problems with fakedoms
inability to get textContent for a node that has been created by
assigning innerHTML. So we extend the fakedom to allow the original
text content to be saved.

See #2778 for discussion.
2017-02-21 13:09:32 +00:00

289 lines
6.2 KiB
JavaScript
Executable File

/*\
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_TextNode = function(text) {
bumpSequenceNumber(this);
this.textContent = text + "";
};
Object.defineProperty(TW_TextNode.prototype, "nodeType", {
get: function() {
return 3;
}
});
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.defineProperty(TW_Element.prototype, "nodeType", {
get: function() {
return 1;
}
});
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";
}
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<attr.length; a++) {
v = this.attributes[attr[a]];
if(v !== undefined) {
output.push(" ",attr[a],"=\"",$tw.utils.htmlEncode(v),"\"");
}
}
}
if(this.style) {
var style = [];
for(var s in this.style) {
style.push(s + ":" + this.style[s] + ";");
}
if(style.length > 0) {
output.push(" style=\"",style.join(""),"\"")
}
}
output.push(">");
if($tw.config.htmlVoidElements.indexOf(this.tag) === -1) {
output.push(this.innerHTML);
output.push("</",this.tag,">");
}
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.htmlEncode(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) {
console.log(booboo)
throw "Cannot get textContent on a raw TW_Element";
} 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) {
throw "Cannot get formattedTextContent on a raw TW_Element";
} 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;
})();