Improved SVG handling and tag name normalization by doing more in the compiler

This commit is contained in:
Patrick Steele-Idem 2017-03-09 15:23:27 -07:00
parent 5f423c704d
commit 4056a61f5a
44 changed files with 390 additions and 246 deletions

View File

@ -8,20 +8,37 @@ var generateVDOMCode = require('./vdom/generateCode');
var vdomUtil = require('../../util/vdom');
function beforeGenerateCode(event) {
if (event.node.tagName === 'script') {
event.context.pushFlag('SCRIPT_BODY');
var tagName = event.node.tagName;
var context = event.context;
var tagDef = typeof tagName === 'string' ? context.getTagDef(tagName) : undefined;
if (tagDef && tagDef.htmlType === 'svg') {
context.pushFlag('SVG');
}
if (event.node.tagName === 'style') {
event.context.pushFlag('STYLE_BODY');
if (tagName === 'script') {
context.pushFlag('SCRIPT_BODY');
}
if (tagName === 'style') {
context.pushFlag('STYLE_BODY');
}
}
function afterGenerateCode(event) {
if (event.node.tagName === 'script') {
event.context.popFlag('SCRIPT_BODY');
var tagName = event.node.tagName;
var context = event.context;
var tagDef = typeof tagName === 'string' ? context.getTagDef(tagName) : undefined;
if (tagDef && tagDef.htmlType === 'svg') {
context.popFlag('SVG');
}
if (event.node.tagName === 'style') {
event.context.popFlag('STYLE_BODY');
if (tagName === 'script') {
context.popFlag('SCRIPT_BODY');
}
if (tagName === 'style') {
context.popFlag('STYLE_BODY');
}
}
@ -188,4 +205,4 @@ class HtmlElement extends Node {
}
}
module.exports = HtmlElement;
module.exports = HtmlElement;

View File

@ -3,6 +3,9 @@
const Node = require('../../Node');
const vdomUtil = require('../../../util/vdom');
var FLAG_IS_SVG = 1;
var FLAG_IS_TEXTAREA = 2;
function finalizeCreateArgs(createArgs, builder) {
var length = createArgs.length;
var lastArg;
@ -24,6 +27,12 @@ function finalizeCreateArgs(createArgs, builder) {
return createArgs;
}
const maybeSVG = {
'a': true,
'script': true,
'style': true
};
class HtmlElementVDOM extends Node {
constructor(def) {
super('HtmlElementVDOM');
@ -35,6 +44,9 @@ class HtmlElementVDOM extends Node {
this.body = def.body;
this.dynamicAttributes = def.dynamicAttributes;
this.isSVG = false;
this.isTextArea = false;
this.isChild = false;
this.createElementId = undefined;
this.attributesArg = undefined;
@ -47,6 +59,39 @@ class HtmlElementVDOM extends Node {
vdomUtil.registerOptimizer(context);
let tagName = this.tagName;
if (tagName.type === 'Literal' && typeof tagName.value === 'string') {
let tagDef = context.getTagDef(tagName.value);
if (tagDef) {
if (tagDef.htmlType === 'svg') {
this.isSVG = true;
} else {
if (maybeSVG[tagName.value] && context.isFlagSet('SVG')) {
this.isSVG = true;
} else {
this.tagName = tagName = builder.literal(tagName.value.toUpperCase());
if (tagName.value === 'TEXTAREA') {
this.isTextArea = true;
}
}
}
}
} else {
if (context.isFlagSet('SVG')) {
this.isSVG = true;
} else {
this.tagName = builder.functionCall(
builder.memberExpression(
tagName,
builder.identifier('toUpperCase')),
[]);
}
}
let attributes = this.attributes;
let dynamicAttributes = this.dynamicAttributes;
@ -122,12 +167,13 @@ class HtmlElementVDOM extends Node {
let body = this.body;
let attributesArg = this.attributesArg;
let nextConstId = this.nextConstId;
let tagName = this.tagName;
let childCount = body && body.length;
let createArgs = new Array(4); // tagName, attributes, childCount, const ID
let createArgs = new Array(5); // tagName, attributes, childCount, const ID, flags
createArgs[0] = this.tagName;
createArgs[0] = tagName;
if (attributesArg) {
createArgs[1] = attributesArg;
@ -141,6 +187,20 @@ class HtmlElementVDOM extends Node {
createArgs[3] = nextConstId;
}
var flags = 0;
if (this.isSVG) {
flags |= FLAG_IS_SVG;
}
if (this.isTextArea) {
flags |= FLAG_IS_TEXTAREA;
}
if (flags) {
createArgs[4] = builder.literal(flags);
}
// Remove trailing undefined arguments and convert non-trailing
// undefined elements to a literal null node
createArgs = finalizeCreateArgs(createArgs, builder);

View File

@ -624,6 +624,10 @@ class TagLoader {
html(value) {
this.tag.html = value === true;
}
htmlType(value) {
this.tag.htmlType = value;
}
}
function isSupportedProperty(name) {

View File

@ -17,23 +17,7 @@ var COMMENT_NODE = 8;
* @return {boolean}
*/
function compareNodeNames(fromEl, toEl) {
var fromNodeName = fromEl.nodeName;
var toNodeName = toEl.nodeName;
if (fromNodeName === toNodeName) {
return true;
}
if (toEl.actualize &&
fromNodeName.charCodeAt(0) < 91 && /* from tag name is upper case */
toNodeName.charCodeAt(0) > 90 /* target tag name is lower case */) {
// If the target element is a virtual DOM node then we may need to normalize the tag name
// before comparing. Normal HTML elements that are in the "http://www.w3.org/1999/xhtml"
// are converted to upper case
return fromNodeName === toNodeName.toUpperCase();
} else {
return false;
}
return fromEl.nodeName === toEl.nodeName;
}
/**

View File

@ -46,7 +46,7 @@ var proto = AsyncVDOMBuilder.prototype = {
$__isOut: true,
$__document: defaultDocument,
element: function(name, attrs, childCount) {
element: function(name, attrs, childCount, constId, flags) {
var element = new VElement(name, attrs, childCount);
var parent = this.$__parent;
@ -112,8 +112,8 @@ var proto = AsyncVDOMBuilder.prototype = {
return this;
},
beginElement: function(name, attrs) {
var element = new VElement(name, attrs);
beginElement: function(name, attrs, childCount, constId, flags) {
var element = new VElement(name, attrs, childCount, constId, flags);
var parent = this.$__parent;
if (parent) {
parent.$__appendChild(element);

View File

@ -18,8 +18,6 @@ VDocumentFragment.prototype = {
$__DocumentFragment: true,
$__nsAware: true,
$__cloneNode: function() {
return new VDocumentFragmentClone(this);
},

View File

@ -1,6 +1,10 @@
var VNode = require('./VNode');
var inherit = require('raptor-util/inherit');
var extend = require('raptor-util/extend');
var FLAG_IS_SVG = 1;
var FLAG_IS_TEXTAREA = 2;
var defineProperty = Object.defineProperty;
var NS_XLINK = 'http://www.w3.org/1999/xlink';
@ -45,23 +49,7 @@ function VElementClone(other) {
this.$__nextSibling = undefined;
}
function VElement(tagName, attrs, childCount, constId) {
var namespaceURI;
var isTextArea;
switch(tagName) {
case 'svg':
namespaceURI = 'http://www.w3.org/2000/svg';
break;
case 'math':
namespaceURI = 'http://www.w3.org/1998/Math/MathML';
break;
case 'textarea':
case 'TEXTAREA':
isTextArea = true;
break;
}
function VElement(tagName, attrs, childCount, constId, flags) {
this.$__VNode(childCount);
if (constId) {
@ -71,9 +59,20 @@ function VElement(tagName, attrs, childCount, constId) {
attrs[ATTR_MARKO_CONST] = constId;
}
var namespaceURI;
var isTextArea;
if (flags) {
isTextArea = flags & FLAG_IS_TEXTAREA;
if (flags & FLAG_IS_SVG) {
namespaceURI = 'http://www.w3.org/2000/svg';
}
}
this.$__attributes = attrs || EMPTY_OBJECT;
this.$__isTextArea = isTextArea;
this.namespaceURI = namespaceURI;
this.$__namespaceURI = namespaceURI;
this.nodeName = tagName;
this.$__value = undefined;
this.$__constId = constId;
@ -84,8 +83,6 @@ VElement.prototype = {
nodeType: 1,
$__nsAware: true,
$__cloneNode: function() {
return new VElementClone(this);
},
@ -97,8 +94,8 @@ VElement.prototype = {
* @param {int|null} attrCount The number of attributes (or `null` if not known)
* @param {int|null} childCount The number of child nodes (or `null` if not known)
*/
e: function(tagName, attrs, childCount, constId) {
var child = this.$__appendChild(new VElement(tagName, attrs, childCount, constId));
e: function(tagName, attrs, childCount, constId, flags) {
var child = this.$__appendChild(new VElement(tagName, attrs, childCount, constId, flags));
if (childCount === 0) {
return this.$__finishChild();
@ -122,7 +119,7 @@ VElement.prototype = {
actualize: function(doc) {
var el;
var namespaceURI = this.namespaceURI;
var namespaceURI = this.$__namespaceURI;
var tagName = this.nodeName;
if (namespaceURI) {

View File

@ -1,17 +1,5 @@
/* jshint newcap:false */
function assignNamespace(node, namespaceURI) {
node.namespaceURI = namespaceURI;
var curChild = node.$__firstChild;
while(curChild) {
if (curChild.$__nsAware) {
assignNamespace(curChild, namespaceURI);
}
curChild = curChild.$__nextSibling;
}
}
function VNode() {}
VNode.prototype = {
@ -73,12 +61,6 @@ VNode.prototype = {
throw TypeError();
}
} else {
var namespaceURI;
if (child.$__nsAware && (namespaceURI = this.namespaceURI) && !child.namespaceURI) {
assignNamespace(child, namespaceURI);
}
var lastChild = this.$__lastChild;
child.$__parentNode = this;

View File

@ -5,8 +5,9 @@ var VElement = require('./VElement');
var VText = require('./VText');
var defaultDocument = typeof document != 'undefined' && document;
var FLAG_IS_TEXTAREA = 2;
var specialHtmlRegexp = /[&<]/;
var range;
function virtualizeChildNodes(node, vdomParent) {
var curChild = node.firstChild;
@ -41,15 +42,23 @@ function virtualize(node) {
}
}
var vdomEL = new VElement(node.nodeName, attrs);
var flags = 0;
if (vdomEL.$__isTextArea) {
vdomEL.$__value = node.value;
} else {
virtualizeChildNodes(node, vdomEL);
var tagName = node.nodeName;
if (tagName === 'TEXTAREA') {
flags |= FLAG_IS_TEXTAREA;
}
return vdomEL;
var vdomEl = new VElement(tagName, attrs, null, null, flags);
vdomEl.$__namespaceURI = node.namespaceURI;
if (vdomEl.$__isTextArea) {
vdomEl.$__value = node.value;
} else {
virtualizeChildNodes(node, vdomEl);
}
return vdomEl;
case 3:
return new VText(node.nodeValue);
case 8:
@ -66,27 +75,14 @@ function virtualizeHTML(html, doc) {
return new VText(html);
}
if (!range && doc.createRange) {
range = doc.createRange();
range.selectNode(doc.body);
}
var container = doc.createElement('body');
container.innerHTML = html;
var vdomFragment = new VDocumentFragment();
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;
}
var curChild = container.firstChild;
while(curChild) {
vdomFragment.$__appendChild(virtualize(curChild));
curChild = curChild.nextSibling;
}
return vdomFragment;

View File

@ -1,83 +1,80 @@
{
"taglib-id": "marko-svg",
"<a>": { "html": true },
"<altGlyph>": { "html": true },
"<altGlyphDef>": { "html": true },
"<altGlyphItem>": { "html": true },
"<animate>": { "html": true },
"<animateColor>": { "html": true },
"<animateMotion>": { "html": true },
"<animateTransform>": { "html": true },
"<circle>": { "html": true },
"<clipPath>": { "html": true },
"<color-profile>": { "html": true },
"<cursor>": { "html": true },
"<defs>": { "html": true },
"<desc>": { "html": true },
"<ellipse>": { "html": true },
"<feBlend>": { "html": true },
"<feColorMatrix>": { "html": true },
"<feComponentTransfer>": { "html": true },
"<feComposite>": { "html": true },
"<feConvolveMatrix>": { "html": true },
"<feDiffuseLighting>": { "html": true },
"<feDisplacementMap>": { "html": true },
"<feDistantLight>": { "html": true },
"<feFlood>": { "html": true },
"<feFuncA>": { "html": true },
"<feFuncB>": { "html": true },
"<feFuncG>": { "html": true },
"<feFuncR>": { "html": true },
"<feGaussianBlur>": { "html": true },
"<feImage>": { "html": true },
"<feMerge>": { "html": true },
"<feMergeNode>": { "html": true },
"<feMorphology>": { "html": true },
"<feOffset>": { "html": true },
"<fePointLight>": { "html": true },
"<feSpecularLighting>": { "html": true },
"<feSpotLight>": { "html": true },
"<feTile>": { "html": true },
"<feTurbulence>": { "html": true },
"<filter>": { "html": true },
"<font>": { "html": true },
"<font-face>": { "html": true },
"<font-face-format>": { "html": true },
"<font-face-name>": { "html": true },
"<font-face-src>": { "html": true },
"<font-face-uri>": { "html": true },
"<foreignObject>": { "html": true },
"<g>": { "html": true },
"<glyph>": { "html": true },
"<glyphRef>": { "html": true },
"<hkern>": { "html": true },
"<image>": { "html": true },
"<line>": { "html": true },
"<linearGradient>": { "html": true },
"<marker>": { "html": true },
"<mask>": { "html": true },
"<metadata>": { "html": true },
"<missing-glyph>": { "html": true },
"<mpath>": { "html": true },
"<path>": { "html": true },
"<pattern>": { "html": true },
"<polygon>": { "html": true },
"<polyline>": { "html": true },
"<radialGradient>": { "html": true },
"<rect>": { "html": true },
"<script>": { "html": true },
"<set>": { "html": true },
"<stop>": { "html": true },
"<style>": { "html": true },
"<svg>": { "html": true },
"<switch>": { "html": true },
"<symbol>": { "html": true },
"<text>": { "html": true },
"<textPath>": { "html": true },
"<title>": { "html": true },
"<tref>": { "html": true },
"<tspan>": { "html": true },
"<use>": { "html": true },
"<view>": { "html": true },
"<vkern>": { "html": true }
}
"<altGlyph>": { "html": true, "htmlType": "svg" },
"<altGlyphDef>": { "html": true, "htmlType": "svg" },
"<altGlyphItem>": { "html": true, "htmlType": "svg" },
"<animate>": { "html": true, "htmlType": "svg" },
"<animateColor>": { "html": true, "htmlType": "svg" },
"<animateMotion>": { "html": true, "htmlType": "svg" },
"<animateTransform>": { "html": true, "htmlType": "svg" },
"<circle>": { "html": true, "htmlType": "svg" },
"<clipPath>": { "html": true, "htmlType": "svg" },
"<color-profile>": { "html": true, "htmlType": "svg" },
"<cursor>": { "html": true, "htmlType": "svg" },
"<defs>": { "html": true, "htmlType": "svg" },
"<desc>": { "html": true, "htmlType": "svg" },
"<ellipse>": { "html": true, "htmlType": "svg" },
"<feBlend>": { "html": true, "htmlType": "svg" },
"<feColorMatrix>": { "html": true, "htmlType": "svg" },
"<feComponentTransfer>": { "html": true, "htmlType": "svg" },
"<feComposite>": { "html": true, "htmlType": "svg" },
"<feConvolveMatrix>": { "html": true, "htmlType": "svg" },
"<feDiffuseLighting>": { "html": true, "htmlType": "svg" },
"<feDisplacementMap>": { "html": true, "htmlType": "svg" },
"<feDistantLight>": { "html": true, "htmlType": "svg" },
"<feFlood>": { "html": true, "htmlType": "svg" },
"<feFuncA>": { "html": true, "htmlType": "svg" },
"<feFuncB>": { "html": true, "htmlType": "svg" },
"<feFuncG>": { "html": true, "htmlType": "svg" },
"<feFuncR>": { "html": true, "htmlType": "svg" },
"<feGaussianBlur>": { "html": true, "htmlType": "svg" },
"<feImage>": { "html": true, "htmlType": "svg" },
"<feMerge>": { "html": true, "htmlType": "svg" },
"<feMergeNode>": { "html": true, "htmlType": "svg" },
"<feMorphology>": { "html": true, "htmlType": "svg" },
"<feOffset>": { "html": true, "htmlType": "svg" },
"<fePointLight>": { "html": true, "htmlType": "svg" },
"<feSpecularLighting>": { "html": true, "htmlType": "svg" },
"<feSpotLight>": { "html": true, "htmlType": "svg" },
"<feTile>": { "html": true, "htmlType": "svg" },
"<feTurbulence>": { "html": true, "htmlType": "svg" },
"<filter>": { "html": true, "htmlType": "svg" },
"<font>": { "html": true, "htmlType": "svg" },
"<font-face>": { "html": true, "htmlType": "svg" },
"<font-face-format>": { "html": true, "htmlType": "svg" },
"<font-face-name>": { "html": true, "htmlType": "svg" },
"<font-face-src>": { "html": true, "htmlType": "svg" },
"<font-face-uri>": { "html": true, "htmlType": "svg" },
"<foreignObject>": { "html": true, "htmlType": "svg" },
"<g>": { "html": true, "htmlType": "svg" },
"<glyph>": { "html": true, "htmlType": "svg" },
"<glyphRef>": { "html": true, "htmlType": "svg" },
"<hkern>": { "html": true, "htmlType": "svg" },
"<image>": { "html": true, "htmlType": "svg" },
"<line>": { "html": true, "htmlType": "svg" },
"<linearGradient>": { "html": true, "htmlType": "svg" },
"<marker>": { "html": true, "htmlType": "svg" },
"<mask>": { "html": true, "htmlType": "svg" },
"<metadata>": { "html": true, "htmlType": "svg" },
"<missing-glyph>": { "html": true, "htmlType": "svg" },
"<mpath>": { "html": true, "htmlType": "svg" },
"<path>": { "html": true, "htmlType": "svg" },
"<pattern>": { "html": true, "htmlType": "svg" },
"<polygon>": { "html": true, "htmlType": "svg" },
"<polyline>": { "html": true, "htmlType": "svg" },
"<radialGradient>": { "html": true, "htmlType": "svg" },
"<rect>": { "html": true, "htmlType": "svg" },
"<set>": { "html": true, "htmlType": "svg" },
"<stop>": { "html": true, "htmlType": "svg" },
"<svg>": { "html": true, "htmlType": "svg" },
"<switch>": { "html": true, "htmlType": "svg" },
"<symbol>": { "html": true, "htmlType": "svg" },
"<text>": { "html": true, "htmlType": "svg" },
"<textPath>": { "html": true, "htmlType": "svg" },
"<title>": { "html": true, "htmlType": "svg" },
"<tref>": { "html": true, "htmlType": "svg" },
"<tspan>": { "html": true, "htmlType": "svg" },
"<use>": { "html": true, "htmlType": "svg" },
"<view>": { "html": true, "htmlType": "svg" },
"<vkern>": { "html": true, "htmlType": "svg" }
}

View File

@ -0,0 +1,11 @@
"use strict";
var marko_template = module.exports = require("marko/vdom").t();
function render(input, out) {
var data = input;
out.e((foo ? "foo" : "bar").toUpperCase(), null, 0);
}
marko_template._ = render;

View File

@ -0,0 +1 @@
<${foo ? 'foo' : 'bar'}/>

View File

@ -6,9 +6,9 @@ var marko_template = module.exports = require("marko/vdom").t(),
marko_createElement = marko_helpers.e,
marko_const = marko_helpers.const,
marko_const_nextId = marko_const("295cea"),
marko_node0 = marko_createElement("div", null, 1, marko_const_nextId())
marko_node0 = marko_createElement("DIV", null, 1, marko_const_nextId())
.t("No colors!"),
marko_node1 = marko_createElement("div", null, 1, marko_const_nextId())
marko_node1 = marko_createElement("DIV", null, 1, marko_const_nextId())
.t("No colors!");
function render(input, out) {
@ -21,10 +21,10 @@ function render(input, out) {
out.t("! ");
if (input.colors.length) {
out.be("ul");
out.be("UL");
marko_forEach(input.colors, function(color) {
out.e("li", null, 1)
out.e("LI", null, 1)
.t(color);
});
@ -34,10 +34,10 @@ function render(input, out) {
}
if (input.colors.length) {
out.be("ul");
out.be("UL");
marko_forEach(input.colors, function(color) {
out.e("li", null, 1)
out.e("LI", null, 1)
.t(color);
});

View File

@ -0,0 +1,23 @@
"use strict";
var marko_template = module.exports = require("marko/vdom").t(),
marko_helpers = require("marko/runtime/vdom/helpers"),
marko_createElement = marko_helpers.e,
marko_const = marko_helpers.const,
marko_const_nextId = marko_const("5e5668"),
marko_node0 = marko_createElement("svg", {
width: "140",
height: "30"
}, 1, marko_const_nextId(), 1)
.e("a", {
"xlink:href": "https://developer.mozilla.org/en-US/docs/SVG",
target: "_blank"
}, 0, null, 1);
function render(input, out) {
var data = input;
out.n(marko_node0);
}
marko_template._ = render;

View File

@ -0,0 +1,5 @@
<svg width="140" height="30">
<a xlink:href="https://developer.mozilla.org/en-US/docs/SVG"
target="_blank">
</a>
</svg>

After

Width:  |  Height:  |  Size: 130 B

View File

@ -0,0 +1,22 @@
"use strict";
var marko_template = module.exports = require("marko/vdom").t(),
marko_attrs0 = {
width: "140",
height: "30"
},
marko_attrs1 = {
width: "200",
height: "200"
};
function render(input, out) {
var data = input;
var isCircle = true;
out.e("svg", marko_attrs0, 1, null, 1)
.e(isCircle ? "circle" : "square", marko_attrs1, 0, null, 1);
}
marko_template._ = render;

View File

@ -0,0 +1,5 @@
$ var isCircle = true;
<svg width="140" height="30">
<${isCircle ? 'circle' : 'square'} width=200 height=200/>
</svg>

View File

@ -0,0 +1,24 @@
"use strict";
var marko_template = module.exports = require("marko/vdom").t(),
marko_helpers = require("marko/runtime/vdom/helpers"),
marko_createElement = marko_helpers.e,
marko_const = marko_helpers.const,
marko_const_nextId = marko_const("f72432"),
marko_node0 = marko_createElement("svg", {
viewBox: "0 0 200 200",
xmlns: "http://www.w3.org/2000/svg"
}, 1, marko_const_nextId(), 1)
.e("circle", {
cx: "100",
cy: "100",
r: "100"
}, 0, null, 1);
function render(input, out) {
var data = input;
out.n(marko_node0);
}
marko_template._ = render;

View File

@ -0,0 +1,3 @@
<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="100" r="100"/>
</svg>

After

Width:  |  Height:  |  Size: 110 B

View File

@ -8,7 +8,7 @@ var marko_template = module.exports = require("marko/vdom").t(),
function render(input, out) {
var data = input;
out.e("div", {
out.e("DIV", {
"class": marko_classAttr(marko_classList([
"foo",
{

View File

@ -5,7 +5,7 @@ var marko_template = module.exports = require("marko/vdom").t();
function render(input, out) {
var data = input;
out.e("div", {
out.e("DIV", {
foo: "bar",
hello: "world"
}, 3)

View File

@ -10,7 +10,7 @@ function render(input, out) {
hello: "world"
};
out.e("div", attrs, 3)
out.e("DIV", attrs, 3)
.t("Hello ")
.t(name)
.t("!");

View File

@ -7,7 +7,7 @@ var marko_template = module.exports = require("marko/vdom").t(),
marko_createElement = marko_helpers.e,
marko_const = marko_helpers.const,
marko_const_nextId = marko_const("cee604"),
marko_node0 = marko_createElement("a", {
marko_node0 = marko_createElement("A", {
href: "foo"
}, 1, marko_const_nextId())
.t("Body content");
@ -15,7 +15,7 @@ var marko_template = module.exports = require("marko/vdom").t(),
function render(input, out) {
var data = input;
out.be("div");
out.be("DIV");
test_hello_tag({
name: "World",

View File

@ -5,7 +5,7 @@ var marko_template = module.exports = require("marko/vdom").t(),
marko_createElement = marko_helpers.e,
marko_const = marko_helpers.const,
marko_const_nextId = marko_const("a51026"),
marko_node0 = marko_createElement("div", null, 0, marko_const_nextId());
marko_node0 = marko_createElement("DIV", null, 0, marko_const_nextId());
function render(input, out) {
var data = input;

View File

@ -8,7 +8,7 @@ var marko_template = module.exports = require("marko/vdom").t(),
function render(input, out) {
var data = input;
out.e("div", marko_attrs0, 3)
out.e("DIV", marko_attrs0, 3)
.t("Hello ")
.t(name)
.t("!");

View File

@ -6,22 +6,22 @@ var marko_template = module.exports = require("marko/vdom").t(),
marko_createElement = marko_helpers.e,
marko_const = marko_helpers.const,
marko_const_nextId = marko_const("9e11e1"),
marko_node0 = marko_createElement("div", null, 1, marko_const_nextId())
marko_node0 = marko_createElement("DIV", null, 1, marko_const_nextId())
.t("No colors!");
function render(input, out) {
var data = input;
out.e("h1", null, 3)
out.e("H1", null, 3)
.t("Hello ")
.t(input.name)
.t("!");
if (input.colors.length) {
out.be("ul");
out.be("UL");
marko_forEach(input.colors, function(color) {
out.e("li", null, 1)
out.e("LI", null, 1)
.t(color);
});

View File

@ -5,7 +5,7 @@ var marko_template = module.exports = require("marko/vdom").t(),
marko_createElement = marko_helpers.e,
marko_const = marko_helpers.const,
marko_const_nextId = marko_const("6d8f0e"),
marko_node0 = marko_createElement("div", {
marko_node0 = marko_createElement("DIV", {
"class": "hello",
onclick: "onClick()"
}, 1, marko_const_nextId())
@ -14,8 +14,8 @@ var marko_template = module.exports = require("marko/vdom").t(),
function render(input, out) {
var data = input;
out.e("span", null, 2)
.e("h1", null, 3)
out.e("SPAN", null, 2)
.e("H1", null, 3)
.t("Hello ")
.t(input.name)
.t("!")

View File

@ -5,7 +5,7 @@ var marko_template = module.exports = require("marko/vdom").t(),
marko_createElement = marko_helpers.e,
marko_const = marko_helpers.const,
marko_const_nextId = marko_const("0524f9"),
marko_node0 = marko_createElement("div", {
marko_node0 = marko_createElement("DIV", {
"class": "hello",
onclick: "onClick()"
}, 1, marko_const_nextId())

View File

@ -1,16 +1,18 @@
var expect = require('chai').expect;
module.exports = function(helpers) {
var svg = helpers.vdom.createElement('svg');
var SVG_FLAGS = 1; // SVG
var svg = helpers.vdom.createElement('svg', null /* attrs */, null /* child count */, null /*constid*/, SVG_FLAGS);
var docFragment = helpers.vdom.createDocumentFragment();
svg.$__appendChild(docFragment);
expect(docFragment.namespaceURI).to.equal('http://www.w3.org/2000/svg');
expect(svg.$__namespaceURI).to.equal('http://www.w3.org/2000/svg');
var docFragmentClone = docFragment.$__cloneNode();
expect(docFragmentClone.namespaceURI).to.equal('http://www.w3.org/2000/svg');
expect(docFragmentClone.nextSibling).to.equal(undefined);
expect(docFragmentClone.parentNode).to.equal(undefined);
return svg;
};
};

View File

@ -1,6 +1,8 @@
var expect = require('chai').expect;
module.exports = function(helpers) {
var SVG_FLAGS = 1; // SVG
var el = helpers.vdom.createElement('div', {
'class': 'foo',
'onclick': 'doSomething()'
@ -8,7 +10,7 @@ module.exports = function(helpers) {
.e('svg', {
width: '100',
height: '100'
}, 1)
}, 1, null, SVG_FLAGS)
.e('circle', {
'cx': '50',
'cy': '50',
@ -17,12 +19,12 @@ module.exports = function(helpers) {
'stroke-width': '4',
'fill': 'yellow',
'xlink:href': 'http://ebay.com/'
}, 0);
}, 0, null, SVG_FLAGS);
var clone = el.$__cloneNode();
expect(clone).to.not.equal(el);
expect(clone.nodeName).to.equal('div');
expect(clone.hasAttributeNS(null, 'class')).to.equal(true);
expect(clone.$__hasAttribute('class')).to.equal(true);
expect(clone.firstChild).to.equal(el.firstChild);
var root = helpers.vdom.createElement('div', { class: 'root' });
@ -33,4 +35,4 @@ module.exports = function(helpers) {
expect(clone.$__parentNode).to.equal(root);
return root;
};
};

View File

@ -3,7 +3,7 @@ var expect = require('chai').expect;
module.exports = function(helpers) {
var virtualEl = helpers.vdom.createElement('option', { selected: '' });
expect(virtualEl.hasAttributeNS(null, 'selected')).to.equal(true);
expect(virtualEl.$__hasAttribute('selected')).to.equal(true);
return virtualEl.actualize(helpers.document);
};
};

View File

@ -3,7 +3,7 @@ var expect = require('chai').expect;
module.exports = function(helpers) {
var virtualEl = helpers.vdom.createElement('option', { selected: false });
expect(virtualEl.hasAttributeNS(null, 'selected')).to.equal(false);
expect(virtualEl.$__hasAttribute('selected')).to.equal(false);
return virtualEl.actualize(helpers.document);
};
};

View File

@ -3,7 +3,7 @@ var expect = require('chai').expect;
module.exports = function(helpers) {
var virtualEl = helpers.vdom.createElement('option', { selected: null });
expect(virtualEl.hasAttributeNS(null, 'selected')).to.equal(false);
expect(virtualEl.$__hasAttribute('selected')).to.equal(false);
return virtualEl.actualize(helpers.document);
};
};

View File

@ -3,7 +3,7 @@ var expect = require('chai').expect;
module.exports = function(helpers) {
var virtualEl = helpers.vdom.createElement('option', { selected: 0 });
expect(virtualEl.hasAttributeNS(null, 'selected')).to.equal(true);
expect(virtualEl.$__hasAttribute('selected')).to.equal(true);
return virtualEl.actualize(helpers.document);
};
};

View File

@ -3,7 +3,7 @@ var expect = require('chai').expect;
module.exports = function(helpers) {
var virtualEl = helpers.vdom.createElement('option', { selected: 1 });
expect(virtualEl.hasAttributeNS(null, 'selected')).to.equal(true);
expect(virtualEl.$__hasAttribute('selected')).to.equal(true);
return virtualEl.actualize(helpers.document);
};
};

View File

@ -3,7 +3,7 @@ var expect = require('chai').expect;
module.exports = function(helpers) {
var virtualEl = helpers.vdom.createElement('option', { selected: true });
expect(virtualEl.hasAttributeNS(null, 'selected')).to.equal(true);
expect(virtualEl.$__hasAttribute('selected')).to.equal(true);
return virtualEl.actualize(helpers.document);
};
};

View File

@ -3,7 +3,7 @@ var expect = require('chai').expect;
module.exports = function(helpers) {
var virtualEl = helpers.vdom.createElement('option', { selected: undefined });
expect(virtualEl.hasAttributeNS(null, 'selected')).to.equal(false);
expect(virtualEl.$__hasAttribute('selected')).to.equal(false);
return virtualEl.actualize(helpers.document);
};
};

View File

@ -1,13 +1,15 @@
module.exports = function(helpers) {
var linearGradient = helpers.vdom.createElement('linearGradient', { x1: "0%", y1: "0%", x2: "100%", y2: "0%" });
linearGradient.$__appendChild(helpers.vdom.createElement('stop', { offset: "0%", style: "stop-color:rgb(255,255,0);stop-opacity:1" }));
var FLAGS = 1; // SVG
var linearGradient = helpers.vdom.createElement('linearGradient', { x1: "0%", y1: "0%", x2: "100%", y2: "0%" }, null, null, FLAGS);
linearGradient.$__appendChild(helpers.vdom.createElement('stop', { offset: "100%", style: "stop-color:rgb(255,0,0);stop-opacity:1" }));
linearGradient.$__appendChild(helpers.vdom.createElement('stop', { offset: "0%", style: "stop-color:rgb(255,255,0);stop-opacity:1" }, null, null, FLAGS));
var svg = helpers.vdom.createElement('svg', { height: "150", width: "400" });
linearGradient.$__appendChild(helpers.vdom.createElement('stop', { offset: "100%", style: "stop-color:rgb(255,0,0);stop-opacity:1" }, null, null, FLAGS));
var svg = helpers.vdom.createElement('svg', { height: "150", width: "400" }, null, null, FLAGS);
svg.$__appendChild(linearGradient);
return svg;
};
};

View File

@ -1,6 +1,8 @@
module.exports = function(helpers) {
var FLAGS = 1;
return helpers.vdom.createElement('div', { class: 'foo', onclick: 'doSomething()' }, 1 /* childCount */)
.e('svg', { width: '100', height: '100'}, 1)
.e('svg', { width: '100', height: '100'}, 1, undefined, FLAGS)
.e('circle', {
'cx': '50',
'cy': '50',
@ -9,5 +11,5 @@ module.exports = function(helpers) {
'stroke-width': '4',
'fill': 'yellow',
'xlink:href': 'http://ebay.com/'
}, 0);
};
}, 0, undefined, FLAGS);
};

View File

@ -1,11 +1,12 @@
var expect = require('chai').expect;
module.exports = function(helpers) {
var TEXTAREA_FLAGS = 2;
expect(function() {
helpers.vdom.createElement('textarea', 0 /* attrCount */, 2 /* childCount */)
helpers.vdom.createElement('textarea', 0 /* attrCount */, 2 /* childCount */, null /* constid */, TEXTAREA_FLAGS)
.e('div', 0, 0)
.t('bar');
}).to.throw('');
return null;
};
};

View File

@ -1,11 +1,13 @@
var expect = require('chai').expect;
module.exports = function(helpers) {
var textarea = helpers.vdom.createElement('textarea', null, 2 /* childCount */)
var FLAGS = 2; // TEXTAREA
var textarea = helpers.vdom.createElement('textarea', null, 2 /* childCount */, null, FLAGS)
.t('foo')
.t('bar');
expect(textarea.value).to.equal('foobar');
return textarea;
};
};

View File

@ -24,9 +24,11 @@ function vdomToHTML(node, options) {
function serializeElHelper(el, indent) {
var tagName = el.nodeName;
if (el.namespaceURI === 'http://www.w3.org/2000/svg') {
var elNamespaceURI = el.namespaceURI || el.$__namespaceURI;
if (elNamespaceURI === 'http://www.w3.org/2000/svg') {
tagName = 'svg:' + tagName;
} else if (el.namespaceURI === 'http://www.w3.org/1998/Math/MathML') {
} else if (elNamespaceURI === 'http://www.w3.org/1998/Math/MathML') {
tagName = 'math:' + tagName;
}
@ -114,4 +116,4 @@ function vdomToHTML(node, options) {
return html;
}
module.exports = vdomToHTML;
module.exports = vdomToHTML;

View File

@ -20,9 +20,11 @@ function toHTML(node) {
function serializeElHelper(el, indent) {
var tagName = el.nodeName;
if (el.namespaceURI === 'http://www.w3.org/2000/svg') {
var elNamespaceURI = el.namespaceURI || el.$__namespaceURI;
if (elNamespaceURI === 'http://www.w3.org/2000/svg') {
tagName = 'svg:' + tagName;
} else if (el.namespaceURI === 'http://www.w3.org/1998/Math/MathML') {
} else if (elNamespaceURI === 'http://www.w3.org/1998/Math/MathML') {
tagName = 'math:' + tagName;
}
@ -108,4 +110,4 @@ function toHTML(node) {
return html;
}
module.exports = toHTML;
module.exports = toHTML;

View File

@ -14,8 +14,8 @@ var VDocumentFragment = vdom.$__VDocumentFragment;
var vdomHelpers = {
createElement: function(tagName, attrs, childCount, constId) {
return new VElement(tagName, attrs, childCount, constId);
createElement: function(tagName, attrs, childCount, constId, flags) {
return new VElement(tagName, attrs, childCount, constId, flags);
},
createText: function(value) {
return new VText(value);
@ -29,7 +29,7 @@ var vdomHelpers = {
VElement: VElement
};
describe('marko-vdom', () => {
describe('vdom-create', () => {
require('./autotest').scanDir(
path.join(__dirname, 'autotests/vdom-create'),
function(dir, helpers, done) {