marko/runtime/vdom/vdom.js
2017-01-20 13:40:21 -07:00

139 lines
3.8 KiB
JavaScript

var VNode = require('./VNode');
var VComment = require('./VComment');
var VDocumentFragment = require('./VDocumentFragment');
var VElement = require('./VElement');
var VText = require('./VText');
var defaultDocument = typeof document != 'undefined' && document;
var specialHtmlRegexp = /[&<]/;
var range;
function virtualizeChildNodes(node, vdomParent) {
var curChild = node.firstChild;
while(curChild) {
vdomParent.$__appendChild(virtualize(curChild));
curChild = curChild.nextSibling;
}
}
function virtualize(node) {
switch(node.nodeType) {
case 1:
var attributes = node.attributes;
var attrCount = attributes.length;
var attrs;
if (attrCount) {
attrs = {};
for (var i=0; i<attrCount; i++) {
var attr = attributes[i];
var attrName;
if (attr.namespaceURI === 'http://www.w3.org/1999/xlink' && attr.localName === 'href') {
attrName = 'xlink:href';
} else {
attrName = attr.name;
}
attrs[attrName] = attr.value;
}
}
var vdomEL = new VElement(node.nodeName, attrs);
if (vdomEL.$__isTextArea) {
vdomEL.$__value = node.value;
} else {
virtualizeChildNodes(node, vdomEL);
}
return vdomEL;
case 3:
return new VText(node.nodeValue);
case 8:
return new VComment(node.nodeValue);
case 11:
var vdomDocFragment = new VDocumentFragment();
virtualizeChildNodes(node, vdomDocFragment);
return vdomDocFragment;
}
}
function virtualizeHTML(html, doc) {
if (!specialHtmlRegexp.test(html)) {
return new VText(html);
}
if (!range && doc.createRange) {
range = doc.createRange();
range.selectNode(doc.body);
}
var vdomFragment;
var fragment;
if (range && range.createContextualFragment) {
fragment = range.createContextualFragment(html);
vdomFragment = virtualize(fragment);
} else {
var container = doc.createElement('body');
container.innerHTML = html;
vdomFragment = new VDocumentFragment();
var curChild = container.firstChild;
while(curChild) {
vdomFragment.$__appendChild(virtualize(curChild));
curChild = curChild.nextSibling;
}
}
return vdomFragment;
}
var Node_prototype = VNode.prototype;
/**
* Shorthand method for creating and appending a Text node with a given value
* @param {String} value The text value for the new Text node
*/
Node_prototype.t = function(value) {
var type = typeof value;
var vdomNode;
if (type !== 'string') {
if (value == null) {
value = '';
} else if (type === 'object') {
if (value.toHTML) {
vdomNode = virtualizeHTML(value.toHTML(), document);
}
}
}
this.$__appendChild(vdomNode || new VText(value.toString()));
return this.$__finishChild();
};
/**
* Shorthand method for creating and appending a Comment node with a given value
* @param {String} value The value for the new Comment node
*/
Node_prototype.c = function(value) {
this.$__appendChild(new VComment(value));
return this.$__finishChild();
};
Node_prototype.$__appendDocumentFragment = function() {
return this.$__appendChild(new VDocumentFragment());
};
exports.$__VComment = VComment;
exports.$__VDocumentFragment = VDocumentFragment;
exports.$__VElement = VElement;
exports.$__VText = VText;
exports.$__virtualize = virtualize;
exports.$__virtualizeHTML = virtualizeHTML;
exports.$__defaultDocument = defaultDocument;