mirror of
https://github.com/marko-js/marko.git
synced 2025-12-08 19:26:05 +00:00
This commit is contained in:
parent
3622cc4421
commit
0e9fe17735
@ -1,7 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
var attr = require('../../../../runtime/html/attr');
|
||||
var escapeXmlAttr = require('../../../../runtime/html/escapeXml').attr;
|
||||
var runtimeHtmlHelpers = require('../../../../runtime/html/helpers');
|
||||
var attr = runtimeHtmlHelpers.a;
|
||||
var escapeXmlAttr = runtimeHtmlHelpers.xa;
|
||||
|
||||
function isStringLiteral(node) {
|
||||
return node.type === 'Literal' && typeof node.value === 'string';
|
||||
@ -76,12 +77,11 @@ function generateCodeForExpressionAttr(name, value, escape, codegen) {
|
||||
if (isStringLiteral(part)) {
|
||||
part.value = escapeXmlAttr(part.value);
|
||||
} else if (part.type === 'Literal') {
|
||||
|
||||
} else if (isNoEscapeXml(part)) {
|
||||
part = codegen.builder.functionCall(context.helper('str'), [part]);
|
||||
} else {
|
||||
if (escape !== false) {
|
||||
part = codegen.builder.functionCall(context.helper('escapeXmlAttr'), [part]);
|
||||
part = builder.functionCall(context.helper('escapeXmlAttr'), [part]);
|
||||
}
|
||||
}
|
||||
addHtml(part);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
var escapeXml = require('../../../../runtime/html/escapeXml');
|
||||
var escapeXml = require('../../../../runtime/html/helpers').x;
|
||||
var Literal = require('../..//Literal');
|
||||
|
||||
module.exports = function(node, codegen) {
|
||||
|
||||
@ -21,16 +21,6 @@ class TextVDOM extends Node {
|
||||
|
||||
vdomUtil.registerOptimizer(context);
|
||||
|
||||
var args = this.arguments;
|
||||
|
||||
for (var i=0, len=args.length; i<len; i++) {
|
||||
var arg = args[i];
|
||||
if (arg.type !== 'Literal') {
|
||||
this.strFuncId = context.helper('str');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -70,7 +60,6 @@ class TextVDOM extends Node {
|
||||
let escape = this.escape;
|
||||
|
||||
var funcName = escape ? 't' : 'h';
|
||||
var strFuncId = this.strFuncId;
|
||||
|
||||
function writeTextArgs() {
|
||||
writer.write('(');
|
||||
@ -84,15 +73,7 @@ class TextVDOM extends Node {
|
||||
writer.writeIndent();
|
||||
}
|
||||
|
||||
if (arg.type === 'Literal') {
|
||||
writer.write(arg);
|
||||
} else {
|
||||
writer.write(strFuncId);
|
||||
writer.write('(');
|
||||
writer.write(arg);
|
||||
writer.write(')');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
writer.write(')');
|
||||
|
||||
@ -57,7 +57,6 @@ function generateNodesForArray(nodes, context, options) {
|
||||
let nextNodeId = 0;
|
||||
let nextAttrsId = 0;
|
||||
|
||||
var optimizeTextNodes = options.optimizeTextNodes !== false;
|
||||
var optimizeStaticNodes = options.optimizeStaticNodes !== false;
|
||||
|
||||
function generateStaticNode(node) {
|
||||
@ -112,31 +111,6 @@ function generateNodesForArray(nodes, context, options) {
|
||||
finalNodes.push(node);
|
||||
}
|
||||
|
||||
} else if (node.type === 'TextVDOM') {
|
||||
if (optimizeTextNodes) {
|
||||
let firstTextNode = node;
|
||||
|
||||
// We will need to merge the text nodes into a single node
|
||||
while(++i<nodes.length) {
|
||||
let currentTextNode = nodes[i];
|
||||
if (currentTextNode.type === 'TextVDOM') {
|
||||
if (!firstTextNode.append(currentTextNode)) {
|
||||
// If the current text node was not appendable then
|
||||
// we will stop. We can only merge text nodes that are compatible
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// firstTextNode.isStatic = false;
|
||||
finalNodes.push(firstTextNode);
|
||||
continue;
|
||||
} else {
|
||||
finalNodes.push(node);
|
||||
}
|
||||
|
||||
} else {
|
||||
finalNodes.push(node);
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@
|
||||
"jsdom": "^9.6.0",
|
||||
"jshint": "^2.5.0",
|
||||
"lasso": "^2.4.1",
|
||||
"lasso-marko": "^2.0.4",
|
||||
"lasso-marko": "^2.1.0",
|
||||
"mkdirp": "^0.5.1",
|
||||
"mocha": "^2.3.3",
|
||||
"mocha-phantomjs": "^4.1.0",
|
||||
|
||||
1
runtime/document-provider.js
Normal file
1
runtime/document-provider.js
Normal file
@ -0,0 +1 @@
|
||||
exports.document = typeof document != 'undefined' && document;
|
||||
@ -1,6 +1,5 @@
|
||||
'use strict';
|
||||
var isArray = Array.isArray;
|
||||
var load = require('./loader');
|
||||
|
||||
function classListHelper(arg, classNames) {
|
||||
var len;
|
||||
@ -93,21 +92,20 @@ LoopStatus.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* Internal helper method to prevent null/undefined from being written out
|
||||
* when writing text that resolves to null/undefined
|
||||
* @private
|
||||
*/
|
||||
s: function(str) {
|
||||
exports.s = function strHelper(str) {
|
||||
return (str == null) ? '' : str.toString();
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal helper method to handle loops with a status variable
|
||||
* @private
|
||||
*/
|
||||
fv: function (array, callback) {
|
||||
exports.fv = function forEachStatusVariableHelper(array, callback) {
|
||||
if (!array) {
|
||||
return;
|
||||
}
|
||||
@ -122,13 +120,13 @@ module.exports = {
|
||||
var o = array[loopStatus.i];
|
||||
callback(o, loopStatus);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal helper method to handle loops without a status variable
|
||||
* @private
|
||||
*/
|
||||
f: function forEach(array, callback) {
|
||||
exports.f = function forEachHelper(array, callback) {
|
||||
if (isArray(array)) {
|
||||
for (var i=0; i<array.length; i++) {
|
||||
callback(array[i]);
|
||||
@ -137,12 +135,12 @@ module.exports = {
|
||||
// Also allow the first argument to be a custom iterator function
|
||||
array(callback);
|
||||
}
|
||||
},
|
||||
};
|
||||
/**
|
||||
* Internal helper method for looping over the properties of any object
|
||||
* @private
|
||||
*/
|
||||
fp: function (o, func) {
|
||||
exports.fp = function forEachPropertyHelper(o, func) {
|
||||
if (!o) {
|
||||
return;
|
||||
}
|
||||
@ -158,12 +156,12 @@ module.exports = {
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to load a custom tag
|
||||
*/
|
||||
t: function (renderer, targetProperty, isRepeated, hasNestedTags) {
|
||||
exports.t = function loadTagHelper(renderer, targetProperty, isRepeated, hasNestedTags) {
|
||||
if (renderer) {
|
||||
renderer = resolveRenderer(renderer);
|
||||
}
|
||||
@ -196,7 +194,7 @@ module.exports = {
|
||||
} else {
|
||||
return renderer;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Merges object properties
|
||||
@ -204,14 +202,14 @@ module.exports = {
|
||||
* @param {[type]} source [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
m: function(into, source) {
|
||||
exports.m = function mergeHelper(into, source) {
|
||||
for (var k in source) {
|
||||
if (source.hasOwnProperty(k) && !into.hasOwnProperty(k)) {
|
||||
into[k] = source[k];
|
||||
}
|
||||
}
|
||||
return into;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* classList(a, b, c, ...)
|
||||
@ -220,14 +218,12 @@ module.exports = {
|
||||
* classList('a', undefined, 'b') --> 'a b'
|
||||
*
|
||||
*/
|
||||
cl: function() {
|
||||
exports.cl = function classListHelper() {
|
||||
return classList(arguments);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Loads a template (__helpers.l --> marko_loadTemplate(path))
|
||||
*/
|
||||
l: load,
|
||||
|
||||
i: require('./include')
|
||||
};
|
||||
exports.l = require('./loader');
|
||||
exports.i = require('./include');
|
||||
@ -2,11 +2,9 @@
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var StringWriter = require('./StringWriter');
|
||||
var BufferedWriter = require('./BufferedWriter');
|
||||
var attr = require('./attr');
|
||||
var escapeXml = require('./escapeXml');
|
||||
var extend = require('raptor-util/extend');
|
||||
|
||||
var defaultDocument = typeof document != 'undefined' && document;
|
||||
var documentProvider = require('../document-provider');
|
||||
var helpers;
|
||||
|
||||
var voidWriter = { write:function(){} };
|
||||
|
||||
@ -412,12 +410,10 @@ var proto = AsyncStream.prototype = {
|
||||
return new AsyncStream(this.global);
|
||||
},
|
||||
|
||||
beginElement: function(name, attrs) {
|
||||
beginElement: function(name, elementAttrs) {
|
||||
|
||||
var str = '<' + name;
|
||||
for (var attrName in attrs) {
|
||||
str += attr(attrName, attrs[attrName]);
|
||||
}
|
||||
helpers.as(elementAttrs);
|
||||
|
||||
str += '>';
|
||||
|
||||
@ -436,7 +432,7 @@ var proto = AsyncStream.prototype = {
|
||||
},
|
||||
|
||||
text: function(str) {
|
||||
this.write(escapeXml(str));
|
||||
this.write(helpers.x(str));
|
||||
},
|
||||
|
||||
getNode: function(doc) {
|
||||
@ -446,7 +442,7 @@ var proto = AsyncStream.prototype = {
|
||||
var html = this.getOutput();
|
||||
|
||||
if (!doc) {
|
||||
doc = this.document || defaultDocument;
|
||||
doc = documentProvider.document;
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
@ -505,3 +501,5 @@ proto.w = proto.write;
|
||||
extend(proto, require('../OutMixins'));
|
||||
|
||||
module.exports = AsyncStream;
|
||||
|
||||
helpers = require('./helpers');
|
||||
@ -1,13 +0,0 @@
|
||||
var escapeXmlAttr = require('./escapeXml').attr;
|
||||
|
||||
module.exports = function(name, value, shouldEscape) {
|
||||
if (typeof value === 'string') {
|
||||
return ' ' + name + '="' + (shouldEscape !== false ? escapeXmlAttr(value) : value) + '"';
|
||||
} else if (value === true) {
|
||||
return ' ' + name;
|
||||
} else if (value == null || value === false) {
|
||||
return '';
|
||||
} else {
|
||||
return ' ' + name + '="' + value.toString() + '"';
|
||||
}
|
||||
};
|
||||
@ -1,35 +0,0 @@
|
||||
var elTest = /[&<]/;
|
||||
var elTestReplace = /[&<]/g;
|
||||
var attrTest = /[&<\"\n]/;
|
||||
var attrReplace = /[&<\"\n]/g;
|
||||
var replacements = {
|
||||
'<': '<',
|
||||
'&': '&',
|
||||
'"': '"',
|
||||
'\n': ' ' //Preserve new lines so that they don't get normalized as space
|
||||
};
|
||||
|
||||
function replaceChar(match) {
|
||||
return replacements[match];
|
||||
}
|
||||
|
||||
function escapeXml(str) {
|
||||
// check for most common case first
|
||||
if (typeof str === 'string') {
|
||||
return elTest.test(str) ? str.replace(elTestReplace, replaceChar) : str;
|
||||
}
|
||||
|
||||
return (str == null) ? '' : str.toString();
|
||||
}
|
||||
|
||||
function escapeXmlAttr(str) {
|
||||
if (typeof str === 'string') {
|
||||
return attrTest.test(str) ? str.replace(attrReplace, replaceChar) : str;
|
||||
}
|
||||
|
||||
return (str == null) ? '' : str.toString();
|
||||
}
|
||||
|
||||
|
||||
module.exports = escapeXml;
|
||||
escapeXml.attr = escapeXmlAttr;
|
||||
@ -1,28 +1,96 @@
|
||||
'use strict';
|
||||
var escapeXml = require('./escapeXml');
|
||||
var escapeXmlAttr = escapeXml.attr;
|
||||
var attr = require('./attr');
|
||||
require('raptor-polyfill/string/startsWith');
|
||||
|
||||
var warp10 = require('warp10');
|
||||
var extend = require('raptor-util/extend');
|
||||
|
||||
var STYLE_ATTR = 'style';
|
||||
var CLASS_ATTR = 'class';
|
||||
var escapeEndingScriptTagRegExp = /<\//g;
|
||||
|
||||
var commonHelpers = require('../helpers');
|
||||
var elTest = /[&<]/;
|
||||
var elTestReplace = /[&<]/g;
|
||||
var attrTest = /[&<\"\n]/;
|
||||
var attrReplace = /[&<\"\n]/g;
|
||||
var stringifiedAttrTest = /[&\'\n]/;
|
||||
var stringifiedAttrReplace = /[&\'\n]/g;
|
||||
|
||||
var classList;
|
||||
|
||||
var replacements = {
|
||||
'<': '<',
|
||||
'&': '&',
|
||||
'"': '"',
|
||||
'\'': ''',
|
||||
'\n': ' ' //Preserve new lines so that they don't get normalized as space
|
||||
};
|
||||
|
||||
function replaceChar(match) {
|
||||
return replacements[match];
|
||||
}
|
||||
|
||||
function escapeStr(str, regexpTest, regexpReplace) {
|
||||
return regexpTest.test(str) ? str.replace(regexpReplace, replaceChar) : str;
|
||||
}
|
||||
|
||||
function escapeXmlHelper(value, regexpTest, regexpReplace) {
|
||||
// check for most common case first
|
||||
if (typeof value === 'string') {
|
||||
return escapeStr(value, regexpTest, regexpReplace);
|
||||
} else if (value == null) {
|
||||
return '';
|
||||
} else if (typeof value === 'object') {
|
||||
var safeHTML = value.safeHTML;
|
||||
if (safeHTML != null) {
|
||||
return value.safeHTML;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
} else if (value === true || value === false || typeof value === 'number') {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
return escapeStr(value.toString(), regexpTest, regexpReplace);
|
||||
}
|
||||
|
||||
function escapeXml(value) {
|
||||
return escapeXmlHelper(value, elTest, elTestReplace);
|
||||
}
|
||||
|
||||
function escapeXmlAttr(value) {
|
||||
return escapeXmlHelper(value, attrTest, attrReplace);
|
||||
}
|
||||
|
||||
function attr(name, value, shouldEscape) {
|
||||
if (typeof value === 'string') {
|
||||
return ' ' + name + '="' + (shouldEscape !== false ? escapeStr(value, attrTest, attrReplace) : value) + '"';
|
||||
} else if (value === true) {
|
||||
return ' ' + name;
|
||||
} else if (value == null || value === false) {
|
||||
return '';
|
||||
} else if (typeof value === 'object') {
|
||||
if (name.startsWith('data-_')) {
|
||||
value = warp10.stringify(value);
|
||||
} else {
|
||||
value = JSON.stringify(value);
|
||||
}
|
||||
return ' ' + name + "='" + escapeStr(value, stringifiedAttrTest, stringifiedAttrReplace) + "'";
|
||||
} else {
|
||||
return ' ' + name + '=' + value; // number (doesn't need quotes)
|
||||
}
|
||||
}
|
||||
|
||||
var classList = commonHelpers.cl;
|
||||
|
||||
module.exports = extend({
|
||||
/**
|
||||
* Internal method to escape special XML characters
|
||||
* @private
|
||||
*/
|
||||
x: escapeXml,
|
||||
exports.x = escapeXml;
|
||||
/**
|
||||
* Internal method to escape special XML characters within an attribute
|
||||
* @private
|
||||
*/
|
||||
xa: escapeXmlAttr,
|
||||
exports.xa = escapeXmlAttr;
|
||||
|
||||
/**
|
||||
* Escapes the '</' sequence in the body of a <script> body to avoid the `<script>` being
|
||||
@ -39,21 +107,21 @@ module.exports = extend({
|
||||
* prematurely ended and a new script tag could then be started that could then execute
|
||||
* arbitrary code.
|
||||
*/
|
||||
xs: function(val) {
|
||||
exports.xs = function(val) {
|
||||
return (typeof val === 'string') ? val.replace(escapeEndingScriptTagRegExp, '\\u003C/') : val;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal method to render a single HTML attribute
|
||||
* @private
|
||||
*/
|
||||
a: attr,
|
||||
exports.a = attr;
|
||||
|
||||
/**
|
||||
* Internal method to render multiple HTML attributes based on the properties of an object
|
||||
* @private
|
||||
*/
|
||||
as: function(arg) {
|
||||
exports.as = function(arg) {
|
||||
if (typeof arg === 'object') {
|
||||
var out = '';
|
||||
for (var attrName in arg) {
|
||||
@ -64,7 +132,7 @@ module.exports = extend({
|
||||
return arg;
|
||||
}
|
||||
return '';
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal helper method to handle the "style" attribute. The value can either
|
||||
@ -73,7 +141,7 @@ module.exports = extend({
|
||||
* sa('color: red; font-weight: bold') ==> ' style="color: red; font-weight: bold"'
|
||||
* sa({color: 'red', 'font-weight': 'bold'}) ==> ' style="color: red; font-weight: bold"'
|
||||
*/
|
||||
sa: function(style) {
|
||||
exports.sa = function(style) {
|
||||
if (!style) {
|
||||
return '';
|
||||
}
|
||||
@ -94,7 +162,7 @@ module.exports = extend({
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal helper method to handle the "class" attribute. The value can either
|
||||
@ -104,7 +172,7 @@ module.exports = extend({
|
||||
* ca({foo: true, bar: false, baz: true}) ==> ' class="foo baz"'
|
||||
* ca(['foo', 'bar']) ==> ' class="foo bar"'
|
||||
*/
|
||||
ca: function(classNames) {
|
||||
exports.ca = function(classNames) {
|
||||
if (!classNames) {
|
||||
return '';
|
||||
}
|
||||
@ -114,7 +182,12 @@ module.exports = extend({
|
||||
} else {
|
||||
return attr(CLASS_ATTR, classList(classNames), false);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
inline: require('./')._inline
|
||||
}, commonHelpers);
|
||||
|
||||
|
||||
var commonHelpers = require('../helpers');
|
||||
classList = commonHelpers.cl;
|
||||
extend(exports, commonHelpers);
|
||||
|
||||
exports.inline = require('./')._inline;
|
||||
@ -12,7 +12,7 @@ exports.c = function createTemplate(path) {
|
||||
return new Template(path);
|
||||
};
|
||||
|
||||
var AsyncStream = require('./AsyncStream');
|
||||
var AsyncStream;
|
||||
|
||||
function createOut(globalData) {
|
||||
return new AsyncStream(globalData);
|
||||
@ -161,6 +161,10 @@ exports.Template = Template;
|
||||
helpers = require('./helpers');
|
||||
exports.helpers = helpers;
|
||||
|
||||
|
||||
|
||||
AsyncStream = require('./AsyncStream');
|
||||
|
||||
exports.enableAsyncStackTrace = AsyncStream.enableAsyncStackTrace;
|
||||
|
||||
require('../')._setRuntime(exports);
|
||||
@ -1,4 +1,6 @@
|
||||
'use strict';
|
||||
var documentProvider = require('./document-provider');
|
||||
|
||||
var runtime;
|
||||
|
||||
function setRuntime(_runtime) {
|
||||
@ -6,13 +8,18 @@ function setRuntime(_runtime) {
|
||||
}
|
||||
exports._setRuntime = setRuntime;
|
||||
|
||||
var load = require('./loader');
|
||||
|
||||
|
||||
function createOut(globalData) {
|
||||
return runtime.createOut(globalData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to associate a DOM Document with marko. This is needed
|
||||
* to parse HTML fragments to insert into the VDOM tree.
|
||||
*/
|
||||
exports.setDocument = function(newDoc) {
|
||||
documentProvider.document = newDoc;
|
||||
};
|
||||
|
||||
exports.createOut = createOut;
|
||||
exports.load = load;
|
||||
exports.load = require('./loader');
|
||||
exports.events = require('./events');
|
||||
@ -4,11 +4,8 @@ var DocumentFragment = require('./DocumentFragment');
|
||||
var Comment = require('./Comment');
|
||||
var Text = require('./Text');
|
||||
var extend = require('raptor-util/extend');
|
||||
|
||||
var virtualize = require('./virtualize');
|
||||
var specialHtmlRegexp = /[&<]/;
|
||||
var defaultDocument = typeof document != 'undefined' && document;
|
||||
|
||||
var virtualizeHTML = require('./virtualizeHTML');
|
||||
var documentProvider = require('../document-provider');
|
||||
|
||||
function State(tree) {
|
||||
this.remaining = 1;
|
||||
@ -39,8 +36,6 @@ function AsyncVDOMBuilder(globalData, parentNode, state) {
|
||||
this._sync = false;
|
||||
}
|
||||
|
||||
var range;
|
||||
|
||||
var proto = AsyncVDOMBuilder.prototype = {
|
||||
isAsyncVDOMBuilder: true,
|
||||
|
||||
@ -71,6 +66,22 @@ var proto = AsyncVDOMBuilder.prototype = {
|
||||
},
|
||||
|
||||
text: function(text) {
|
||||
var type = typeof text;
|
||||
|
||||
if (type !== 'string') {
|
||||
if (text == null) {
|
||||
return;
|
||||
} else if (type === 'object') {
|
||||
var safeHTML = text.safeHTML;
|
||||
if (safeHTML) {
|
||||
var html = typeof safeHTML === 'function' ? text.safeHTML() : safeHTML;
|
||||
return this.html(html);
|
||||
}
|
||||
} else {
|
||||
text = text.toString();
|
||||
}
|
||||
}
|
||||
|
||||
var parent = this._parent;
|
||||
if (parent) {
|
||||
var lastChild = parent.lastChild;
|
||||
@ -88,39 +99,9 @@ var proto = AsyncVDOMBuilder.prototype = {
|
||||
},
|
||||
|
||||
html: function(html) {
|
||||
if (!specialHtmlRegexp.test(html)) {
|
||||
return this.text(html);
|
||||
}
|
||||
|
||||
var document = this.document;
|
||||
|
||||
if (!range && document.createRange) {
|
||||
range = document.createRange();
|
||||
range.selectNode(document.body);
|
||||
}
|
||||
|
||||
var vdomFragment;
|
||||
|
||||
var fragment;
|
||||
if (range && range.createContextualFragment) {
|
||||
fragment = range.createContextualFragment(html);
|
||||
vdomFragment = virtualize(fragment);
|
||||
} else {
|
||||
var container = document.createElement('body');
|
||||
container.innerHTML = html;
|
||||
|
||||
var curChild = container.firstChild;
|
||||
if (curChild) {
|
||||
vdomFragment = new DocumentFragment();
|
||||
while(curChild) {
|
||||
vdomFragment.appendChild(virtualize(curChild));
|
||||
curChild = curChild.nextSibling;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vdomFragment) {
|
||||
this.node(vdomFragment);
|
||||
if (html != null) {
|
||||
var vdomNode = virtualizeHTML(html, documentProvider.document);
|
||||
this.node(vdomNode);
|
||||
}
|
||||
|
||||
return this;
|
||||
@ -291,7 +272,7 @@ var proto = AsyncVDOMBuilder.prototype = {
|
||||
var vdomTree = this.getOutput();
|
||||
|
||||
if (!doc) {
|
||||
doc = this.document || defaultDocument;
|
||||
doc = documentProvider.document;
|
||||
}
|
||||
|
||||
node = vdomTree.actualize(doc);
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
require('raptor-polyfill/string/startsWith');
|
||||
var inherit = require('raptor-util/inherit');
|
||||
var extend = require('raptor-util/extend');
|
||||
var Text = require('./Text');
|
||||
var Comment = require('./Comment');
|
||||
var Node = require('./Node');
|
||||
var documentProvider = require('../document-provider');
|
||||
var virtualizeHTML;
|
||||
|
||||
var NS_XLINK = 'http://www.w3.org/1999/xlink';
|
||||
var ATTR_HREF = 'href';
|
||||
@ -20,6 +23,16 @@ function removePreservedAttributes(attrs) {
|
||||
return attrs;
|
||||
}
|
||||
|
||||
function convertAttrValue(type, value) {
|
||||
if (value === true) {
|
||||
return '';
|
||||
} else if (type === 'object') {
|
||||
return JSON.stringify(value);
|
||||
} else {
|
||||
return value.toString();
|
||||
}
|
||||
}
|
||||
|
||||
function HTMLElementClone(other) {
|
||||
extend(this, other);
|
||||
this.parentNode = undefined;
|
||||
@ -136,6 +149,19 @@ HTMLElement.prototype = {
|
||||
if (attrValue == null || attrValue === false) {
|
||||
targetNode.removeAttribute(attrName);
|
||||
} else if (oldAttrs[attrName] !== attrValue) {
|
||||
|
||||
if (attrName.startsWith('data-_')) {
|
||||
// Special attributes aren't copied to the real DOM. They are only
|
||||
// kept in the virtual attributes map
|
||||
continue;
|
||||
}
|
||||
|
||||
var type = typeof attrValue;
|
||||
|
||||
if (type !== 'string') {
|
||||
attrValue = convertAttrValue(type, attrValue);
|
||||
}
|
||||
|
||||
targetNode.setAttribute(attrName, attrValue);
|
||||
}
|
||||
}
|
||||
@ -182,6 +208,20 @@ HTMLElement.prototype = {
|
||||
* @param {String} value The text value for the new Text node
|
||||
*/
|
||||
t: function(value) {
|
||||
var type = typeof value;
|
||||
|
||||
if (type !== 'string') {
|
||||
if (value == null) {
|
||||
value = '';
|
||||
} else if (type === 'object') {
|
||||
var safeHTML = value.safeHTML;
|
||||
var vdomNode = virtualizeHTML(safeHTML || '', documentProvider.document);
|
||||
this.appendChild(vdomNode);
|
||||
return this._finishChild();
|
||||
} else {
|
||||
value = value.toString();
|
||||
}
|
||||
}
|
||||
this.appendChild(new Text(value));
|
||||
return this._finishChild();
|
||||
},
|
||||
@ -221,9 +261,17 @@ HTMLElement.prototype = {
|
||||
for (var attrName in attributes) {
|
||||
var attrValue = attributes[attrName];
|
||||
|
||||
if (attrName.startsWith('data-_')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (attrValue !== false && attrValue != null) {
|
||||
if (attrValue === true) {
|
||||
attrValue = '';
|
||||
var type = typeof attrValue;
|
||||
|
||||
if (type !== 'string') {
|
||||
// Special attributes aren't copied to the real DOM. They are only
|
||||
// kept in the virtual attributes map
|
||||
attrValue = convertAttrValue(type, attrValue);
|
||||
}
|
||||
|
||||
if (attrName === 'xlink:href') {
|
||||
@ -314,3 +362,5 @@ Object.defineProperty(proto, 'disabled', {
|
||||
});
|
||||
|
||||
module.exports = HTMLElement;
|
||||
|
||||
virtualizeHTML = require('./virtualizeHTML');
|
||||
@ -1,19 +1,3 @@
|
||||
/*
|
||||
* Copyright 2011 eBay Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var HTMLElement = require('./HTMLElement');
|
||||
@ -23,26 +7,27 @@ var extend = require('raptor-util/extend');
|
||||
|
||||
var classList = commonHelpers.cl;
|
||||
|
||||
module.exports = extend({
|
||||
e: function(tagName, attrs, childCount, constId) {
|
||||
exports.e = function(tagName, attrs, childCount, constId) {
|
||||
return new HTMLElement(tagName, attrs, childCount, constId);
|
||||
},
|
||||
t: function(value) {
|
||||
};
|
||||
|
||||
exports.t = function(value) {
|
||||
return new Text(value);
|
||||
},
|
||||
const: function(id) {
|
||||
};
|
||||
|
||||
exports.const = function(id) {
|
||||
var i=0;
|
||||
return function() {
|
||||
return id + (i++);
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper for generating the string for a style attribute
|
||||
* @param {[type]} style [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
sa: function(style) {
|
||||
exports.sa = function(style) {
|
||||
if (!style) {
|
||||
return null;
|
||||
}
|
||||
@ -63,7 +48,7 @@ module.exports = extend({
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal helper method to handle the "class" attribute. The value can either
|
||||
@ -73,7 +58,7 @@ module.exports = extend({
|
||||
* ca({foo: true, bar: false, baz: true}) ==> ' class="foo baz"'
|
||||
* ca(['foo', 'bar']) ==> ' class="foo bar"'
|
||||
*/
|
||||
ca: function(classNames) {
|
||||
exports.ca = function(classNames) {
|
||||
if (!classNames) {
|
||||
return null;
|
||||
}
|
||||
@ -83,7 +68,8 @@ module.exports = extend({
|
||||
} else {
|
||||
return classList(classNames);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
inline: require('./')._inline
|
||||
}, commonHelpers);
|
||||
exports.inline = require('./')._inline;
|
||||
|
||||
extend(exports, commonHelpers);
|
||||
@ -136,14 +136,6 @@ exports.Template = Template;
|
||||
|
||||
exports._inline = createInlineMarkoTemplate;
|
||||
|
||||
/**
|
||||
* Used to associate a DOM Document with marko. This is needed
|
||||
* to parse HTML fragments to insert into the VDOM tree.
|
||||
*/
|
||||
exports.setDocument = function(newDoc) {
|
||||
AsyncVDOMBuilder.prototype.document = newDoc;
|
||||
};
|
||||
|
||||
|
||||
helpers = require('./helpers');
|
||||
exports.helpers = helpers;
|
||||
|
||||
37
runtime/vdom/virtualizeHTML.js
Normal file
37
runtime/vdom/virtualizeHTML.js
Normal file
@ -0,0 +1,37 @@
|
||||
var Text = require('./Text');
|
||||
var DocumentFragment = require('./DocumentFragment');
|
||||
var virtualize = require('./virtualize');
|
||||
var specialHtmlRegexp = /[&<]/;
|
||||
|
||||
var range;
|
||||
|
||||
module.exports = function virtualizeHTML(html, doc) {
|
||||
if (!specialHtmlRegexp.test(html)) {
|
||||
return new Text(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 DocumentFragment();
|
||||
|
||||
var curChild = container.firstChild;
|
||||
while(curChild) {
|
||||
vdomFragment.appendChild(virtualize(curChild));
|
||||
curChild = curChild.nextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
return vdomFragment;
|
||||
};
|
||||
1
test/autotests/render/attr-number/expected.html
Normal file
1
test/autotests/render/attr-number/expected.html
Normal file
@ -0,0 +1 @@
|
||||
<div data-foo=1></div>
|
||||
2
test/autotests/render/attr-number/template.marko
Normal file
2
test/autotests/render/attr-number/template.marko
Normal file
@ -0,0 +1,2 @@
|
||||
<div data-foo=1>
|
||||
</div>
|
||||
5
test/autotests/render/attr-number/test.js
Normal file
5
test/autotests/render/attr-number/test.js
Normal file
@ -0,0 +1,5 @@
|
||||
exports.templateData = {
|
||||
message: {
|
||||
safeHTML: '<span>Hello World</span>'
|
||||
}
|
||||
};
|
||||
1
test/autotests/render/attr-object-dynamic/expected.html
Normal file
1
test/autotests/render/attr-object-dynamic/expected.html
Normal file
@ -0,0 +1 @@
|
||||
<div value='{"hello":"world's"}'></div>
|
||||
1
test/autotests/render/attr-object-dynamic/template.marko
Normal file
1
test/autotests/render/attr-object-dynamic/template.marko
Normal file
@ -0,0 +1 @@
|
||||
<div value=data.myObject/>
|
||||
3
test/autotests/render/attr-object-dynamic/test.js
Normal file
3
test/autotests/render/attr-object-dynamic/test.js
Normal file
@ -0,0 +1,3 @@
|
||||
exports.templateData = {
|
||||
myObject: {hello: 'world\'s'}
|
||||
};
|
||||
1
test/autotests/render/attr-object/expected.html
Normal file
1
test/autotests/render/attr-object/expected.html
Normal file
@ -0,0 +1 @@
|
||||
<div data-hello='{"foo":"bar"}'></div>
|
||||
1
test/autotests/render/attr-object/template.marko
Normal file
1
test/autotests/render/attr-object/template.marko
Normal file
@ -0,0 +1 @@
|
||||
<div data-hello={foo: 'bar'}/>
|
||||
2
test/autotests/render/attr-object/test.js
Normal file
2
test/autotests/render/attr-object/test.js
Normal file
@ -0,0 +1,2 @@
|
||||
exports.templateData = {};
|
||||
exports.vdomSkip = false;
|
||||
@ -0,0 +1 @@
|
||||
<div data-_onclick='{"o":{"name":"parent","child":{}},"$$":[{"l":["child","parent"],"r":[]}]}'></div>
|
||||
@ -0,0 +1 @@
|
||||
<div data-_onclick=data.parent/>
|
||||
@ -0,0 +1,14 @@
|
||||
var parent = {
|
||||
name: 'parent'
|
||||
};
|
||||
|
||||
var child = {
|
||||
parent: parent
|
||||
};
|
||||
|
||||
parent.child = child;
|
||||
|
||||
exports.templateData = {
|
||||
parent: parent
|
||||
};
|
||||
exports.vdomSkip = true;
|
||||
@ -0,0 +1 @@
|
||||
<div data-_onclick='{"foo":"bar"}'></div>
|
||||
@ -0,0 +1 @@
|
||||
<div data-_onclick=data.specialData/>
|
||||
@ -0,0 +1,6 @@
|
||||
exports.templateData = {
|
||||
specialData: {
|
||||
foo: 'bar'
|
||||
}
|
||||
};
|
||||
exports.vdomSkip = true;
|
||||
@ -0,0 +1 @@
|
||||
<div data-_onclick='{"foo":"bar"}'></div>
|
||||
@ -0,0 +1 @@
|
||||
<div data-_onclick={ foo: 'bar' }/>
|
||||
@ -0,0 +1,6 @@
|
||||
exports.templateData = {
|
||||
specialData: {
|
||||
foo: 'bar'
|
||||
}
|
||||
};
|
||||
exports.vdomSkip = true;
|
||||
1
test/autotests/render/safeHTML-value/expected.html
Normal file
1
test/autotests/render/safeHTML-value/expected.html
Normal file
@ -0,0 +1 @@
|
||||
<div><span>Hello World</span></div>
|
||||
3
test/autotests/render/safeHTML-value/template.marko
Normal file
3
test/autotests/render/safeHTML-value/template.marko
Normal file
@ -0,0 +1,3 @@
|
||||
<div>
|
||||
${data.message}
|
||||
</div>
|
||||
5
test/autotests/render/safeHTML-value/test.js
Normal file
5
test/autotests/render/safeHTML-value/test.js
Normal file
@ -0,0 +1,5 @@
|
||||
exports.templateData = {
|
||||
message: {
|
||||
safeHTML: '<span>Hello World</span>'
|
||||
}
|
||||
};
|
||||
@ -4,7 +4,6 @@ module.exports = template;
|
||||
|
||||
var marko_helpers = require("marko/runtime/vdom/helpers"),
|
||||
marko_classList = marko_helpers.cl,
|
||||
marko_str = marko_helpers.s,
|
||||
marko_classAttr = marko_helpers.ca;
|
||||
|
||||
function render(data, out) {
|
||||
@ -13,10 +12,10 @@ function render(data, out) {
|
||||
bar: true,
|
||||
baz: false
|
||||
}))
|
||||
}, 1)
|
||||
.t("Hello " +
|
||||
marko_str(name) +
|
||||
"!");
|
||||
}, 3)
|
||||
.t("Hello ")
|
||||
.t(name)
|
||||
.t("!");
|
||||
}
|
||||
|
||||
template._ = render;
|
||||
|
||||
@ -2,17 +2,14 @@ var template = require("marko/vdom").c(__filename);
|
||||
|
||||
module.exports = template;
|
||||
|
||||
var marko_helpers = require("marko/runtime/vdom/helpers"),
|
||||
marko_str = marko_helpers.s;
|
||||
|
||||
function render(data, out) {
|
||||
out.e("div", {
|
||||
foo: "bar",
|
||||
hello: "world"
|
||||
}, 1)
|
||||
.t("Hello " +
|
||||
marko_str(name) +
|
||||
"!");
|
||||
}, 3)
|
||||
.t("Hello ")
|
||||
.t(name)
|
||||
.t("!");
|
||||
}
|
||||
|
||||
template._ = render;
|
||||
|
||||
@ -2,19 +2,16 @@ var template = require("marko/vdom").c(__filename);
|
||||
|
||||
module.exports = template;
|
||||
|
||||
var marko_helpers = require("marko/runtime/vdom/helpers"),
|
||||
marko_str = marko_helpers.s;
|
||||
|
||||
function render(data, out) {
|
||||
var attrs = {
|
||||
foo: "bar",
|
||||
hello: "world"
|
||||
};
|
||||
|
||||
out.e("div", attrs, 1)
|
||||
.t("Hello " +
|
||||
marko_str(name) +
|
||||
"!");
|
||||
out.e("div", attrs, 3)
|
||||
.t("Hello ")
|
||||
.t(name)
|
||||
.t("!");
|
||||
}
|
||||
|
||||
template._ = render;
|
||||
|
||||
@ -2,17 +2,15 @@ var template = require("marko/vdom").c(__filename);
|
||||
|
||||
module.exports = template;
|
||||
|
||||
var marko_helpers = require("marko/runtime/vdom/helpers"),
|
||||
marko_str = marko_helpers.s,
|
||||
marko_attrs0 = {
|
||||
var marko_attrs0 = {
|
||||
"class": "foo"
|
||||
};
|
||||
|
||||
function render(data, out) {
|
||||
out.e("div", marko_attrs0, 1)
|
||||
.t("Hello " +
|
||||
marko_str(name) +
|
||||
"!");
|
||||
out.e("div", marko_attrs0, 3)
|
||||
.t("Hello ")
|
||||
.t(name)
|
||||
.t("!");
|
||||
}
|
||||
|
||||
template._ = render;
|
||||
|
||||
@ -2,15 +2,14 @@ var template = require("marko/vdom").c(__filename);
|
||||
|
||||
module.exports = template;
|
||||
|
||||
var marko_helpers = require("marko/runtime/vdom/helpers"),
|
||||
marko_str = marko_helpers.s;
|
||||
|
||||
function render(data, out) {
|
||||
out.t("Hello " +
|
||||
marko_str(name) +
|
||||
"! ");
|
||||
out.t("Hello ");
|
||||
|
||||
out.h(marko_str(message));
|
||||
out.t(name);
|
||||
|
||||
out.t("! ");
|
||||
|
||||
out.h(message);
|
||||
}
|
||||
|
||||
template._ = render;
|
||||
|
||||
@ -3,7 +3,6 @@ var template = require("marko/vdom").c(__filename);
|
||||
module.exports = template;
|
||||
|
||||
var marko_helpers = require("marko/runtime/vdom/helpers"),
|
||||
marko_str = marko_helpers.s,
|
||||
marko_forEach = marko_helpers.f,
|
||||
marko_createElement = marko_helpers.e,
|
||||
marko_const = marko_helpers.const,
|
||||
@ -12,17 +11,17 @@ var marko_helpers = require("marko/runtime/vdom/helpers"),
|
||||
.t("No colors!");
|
||||
|
||||
function render(data, out) {
|
||||
out.e("h1", null, 1)
|
||||
.t("Hello " +
|
||||
marko_str(data.name) +
|
||||
"!");
|
||||
out.e("h1", null, 3)
|
||||
.t("Hello ")
|
||||
.t(data.name)
|
||||
.t("!");
|
||||
|
||||
if (data.colors.length) {
|
||||
out.be("ul");
|
||||
|
||||
marko_forEach(data.colors, function(color) {
|
||||
out.e("li", null, 1)
|
||||
.t(marko_str(color));
|
||||
.t(color);
|
||||
});
|
||||
|
||||
out.ee();
|
||||
|
||||
@ -3,7 +3,6 @@ var template = require("marko/vdom").c(__filename);
|
||||
module.exports = template;
|
||||
|
||||
var marko_helpers = require("marko/runtime/vdom/helpers"),
|
||||
marko_str = marko_helpers.s,
|
||||
marko_createElement = marko_helpers.e,
|
||||
marko_const = marko_helpers.const,
|
||||
marko_const_nextId = marko_const("69a896"),
|
||||
@ -15,10 +14,10 @@ var marko_helpers = require("marko/runtime/vdom/helpers"),
|
||||
|
||||
function render(data, out) {
|
||||
out.e("span", null, 2)
|
||||
.e("h1", null, 1)
|
||||
.t("Hello " +
|
||||
marko_str(data.name) +
|
||||
"!")
|
||||
.e("h1", null, 3)
|
||||
.t("Hello ")
|
||||
.t(data.name)
|
||||
.t("!")
|
||||
.n(marko_node0);
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
module.exports = require('marko/widgets').defineComponent({
|
||||
createOut: require('marko/html').createOut,
|
||||
|
||||
renderer: function(input, out) {
|
||||
out.write('Hello ' + input.name + '!');
|
||||
out.text('Hello ' + input.name + '!');
|
||||
}
|
||||
});
|
||||
@ -6,7 +6,7 @@ module.exports = function(helpers) {
|
||||
var forElId = label.getAttribute('for');
|
||||
var inputEl = document.getElementById(forElId);
|
||||
|
||||
expect(forElId).to.exist;
|
||||
expect(!!forElId).to.equal(true);
|
||||
expect(inputEl.value).to.equal('test');
|
||||
expect(label.getAttribute('for-ref')).to.equal(null);
|
||||
};
|
||||
|
||||
@ -3,7 +3,7 @@ var expect = require('chai').expect;
|
||||
module.exports = function(helpers) {
|
||||
var widget = helpers.mount(require('./index'), {});
|
||||
|
||||
expect(widget.__document).to.exist;
|
||||
expect(widget.__document != null).to.equal(true);
|
||||
expect(widget.__document).to.equal(document);
|
||||
|
||||
var contentWidget = widget.renderIntoIframe();
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
module.exports = require('marko/widgets').defineComponent({
|
||||
createOut: require('marko/html').createOut,
|
||||
|
||||
renderer: function(input, out) {
|
||||
out.write('Hello ' + input.name + '!');
|
||||
out.text('Hello ' + input.name + '!');
|
||||
}
|
||||
});
|
||||
@ -10,5 +10,5 @@ module.exports = function(helpers) {
|
||||
|
||||
widget.destroy();
|
||||
|
||||
expect(widget.update()).to.be.undefined;
|
||||
expect(widget.update() === undefined).to.equal(true);
|
||||
};
|
||||
@ -1,5 +1,7 @@
|
||||
{
|
||||
"dependencies": [
|
||||
"require: ./components/**/*.js"
|
||||
"require: ./components/app-async/widget",
|
||||
"require: ./components/app-hello/widget",
|
||||
"require: ./components/app-init-async/widget"
|
||||
]
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
var template = require('marko').load(require.resolve('./template.marko'));
|
||||
var template = require('./template.marko');
|
||||
|
||||
module.exports = function(input, out) {
|
||||
var asyncOut = out.beginAsync();
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"dependencies": [
|
||||
"require: ./components/**/*.js"
|
||||
"require: ./components/app-foo"
|
||||
]
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"dependencies": [
|
||||
"require: ./components/**/*.js"
|
||||
"require: ./components/app-simple"
|
||||
]
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
{
|
||||
"dependencies": [
|
||||
"require: ./components/**/*.js"
|
||||
"require: ./components/app-foo",
|
||||
"require: ./components/app-bar"
|
||||
]
|
||||
}
|
||||
@ -1,5 +1,7 @@
|
||||
{
|
||||
"dependencies": [
|
||||
"require: ./components/**/*.js"
|
||||
"require: ./components/app-foo",
|
||||
"require: ./components/app-bar",
|
||||
"require: ./components/app-baz"
|
||||
]
|
||||
}
|
||||
@ -1,5 +1,7 @@
|
||||
{
|
||||
"dependencies": [
|
||||
"require: ./components/**/*.js"
|
||||
"require: ./components/app-foo",
|
||||
"require: ./components/app-bar",
|
||||
"require: ./components/app-baz"
|
||||
]
|
||||
}
|
||||
@ -1,5 +1,7 @@
|
||||
{
|
||||
"dependencies": [
|
||||
"require: ./components/**/*.js"
|
||||
"require: ./components/app-foo",
|
||||
"require: ./components/app-bar",
|
||||
"require: ./components/app-baz"
|
||||
]
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"dependencies": [
|
||||
"require: ./components/**/*.js"
|
||||
"require: ./components/app-foo"
|
||||
]
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"dependencies": [
|
||||
"require: ./components/**/widget.js"
|
||||
"require: ./components/app-button-split/widget"
|
||||
]
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"dependencies": [
|
||||
"require: ./components/**/*.js"
|
||||
"require: ./components/app-foo"
|
||||
]
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
{
|
||||
"dependencies": [
|
||||
"require: ./components/**/*.js"
|
||||
"require: ./components/app-fixed-id",
|
||||
"require: ./components/app-hello/widget"
|
||||
]
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"dependencies": [
|
||||
"require: ./components/**/*.js"
|
||||
"require: ./components/app-foo"
|
||||
]
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"dependencies": [
|
||||
"require: ./components/**/*.js"
|
||||
"require: ./components/app-foo"
|
||||
]
|
||||
}
|
||||
@ -1,7 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
var escapeXml = require('../../runtime/html/escapeXml');
|
||||
var escapeXmlAttr = escapeXml.attr;
|
||||
var runtimeHtmlHelpers = require('../../runtime/html/helpers');
|
||||
var escapeXml = runtimeHtmlHelpers.x;
|
||||
var escapeXmlAttr = runtimeHtmlHelpers.xa;
|
||||
|
||||
var openTagOnly = {};
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ const jsdom = require("jsdom").jsdom;
|
||||
const expect = require('chai').expect;
|
||||
|
||||
const defaultDocument = jsdom('<html><body></body></html>');
|
||||
require('../../runtime/vdom').setDocument(defaultDocument); // We need this to parse HTML fragments on the server
|
||||
require('../../').setDocument(defaultDocument); // We need this to parse HTML fragments on the server
|
||||
|
||||
|
||||
function createAsyncVerifier(main, helpers, out) {
|
||||
@ -179,10 +179,11 @@ module.exports = function runRenderTest(dir, helpers, done, options) {
|
||||
getExpectedHtml(function(err, expectedHtml) {
|
||||
fs.writeFileSync(path.join(dir, 'vdom-expected.generated.html'), expectedHtml, { encoding: 'utf8' });
|
||||
|
||||
let actualizedDom = vdomTree.actualize(defaultDocument);
|
||||
|
||||
// NOTE: We serialie the virtual DOM tree into an HTML string and reparse so that we can
|
||||
// normalize the text
|
||||
let vdomHtml = domToHTML(vdomTree);
|
||||
let vdomHtml = domToHTML(actualizedDom);
|
||||
let vdomRealDocument = jsdom('<html><body>' + vdomHtml + '</body></html>');
|
||||
let vdomString = domToString(vdomRealDocument.body, { childrenOnly: true });
|
||||
helpers.compare(vdomString, 'vdom-', '.generated.html');
|
||||
|
||||
@ -1,5 +1,19 @@
|
||||
var _addEventListener = require('./addEventListener');
|
||||
var updateManager = require('./update-manager');
|
||||
var warp10Parse = require('warp10/parse');
|
||||
|
||||
function getEventAttribute(el, attrName) {
|
||||
var virtualAttrs = el._vattrs;
|
||||
|
||||
if (virtualAttrs) {
|
||||
return el._vattrs[attrName];
|
||||
} else {
|
||||
var attrValue = el.getAttribute(attrName);
|
||||
if (attrValue) {
|
||||
return warp10Parse(attrValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var attachBubbleEventListeners = function() {
|
||||
var body = document.body;
|
||||
@ -30,17 +44,22 @@ var attachBubbleEventListeners = function() {
|
||||
|
||||
// Search up the tree looking DOM events mapped to target
|
||||
// widget methods
|
||||
var attrName = 'data-w-on' + eventType;
|
||||
var targetMethod;
|
||||
var targetWidget;
|
||||
var attrName = 'data-_on' + eventType;
|
||||
var target;
|
||||
|
||||
// Attributes will have the following form:
|
||||
// w-on<event_type>="<target_method>|<widget_id>"
|
||||
|
||||
do {
|
||||
if ((targetMethod = curNode.getAttribute(attrName))) {
|
||||
var separator = targetMethod.lastIndexOf('|');
|
||||
var targetWidgetId = targetMethod.substring(separator+1);
|
||||
if ((target = getEventAttribute(curNode, attrName))) {
|
||||
var targetMethod = target[0];
|
||||
var targetWidgetId = target[1];
|
||||
var targetArgs;
|
||||
|
||||
if (target.length > 2) {
|
||||
targetArgs = target.slice(2);
|
||||
}
|
||||
|
||||
var targetWidgetEl = document.getElementById(targetWidgetId);
|
||||
if (!targetWidgetEl) {
|
||||
// The target widget is not in the DOM anymore
|
||||
@ -50,12 +69,11 @@ var attachBubbleEventListeners = function() {
|
||||
continue;
|
||||
}
|
||||
|
||||
targetWidget = targetWidgetEl.__widget;
|
||||
var targetWidget = targetWidgetEl.__widget;
|
||||
|
||||
if (!targetWidget) {
|
||||
throw new Error('Widget not found: ' + targetWidgetId);
|
||||
}
|
||||
targetMethod = targetMethod.substring(0, separator);
|
||||
|
||||
var targetFunc = targetWidget[targetMethod];
|
||||
if (!targetFunc) {
|
||||
|
||||
@ -42,14 +42,6 @@ function addBubblingEventListener(transformHelper, eventType, targetMethod) {
|
||||
builder.identifier('widget'),
|
||||
builder.identifier('id'));
|
||||
|
||||
if (targetMethod.type === 'Literal') {
|
||||
// We know the event handler is method is no conditional so we set the attribute correctly at compile time
|
||||
attrValue = builder.concat(
|
||||
targetMethod,
|
||||
builder.literal('|'),
|
||||
widgetIdExpression);
|
||||
} else {
|
||||
|
||||
// The event handler method is conditional and it may resolve to a null method name. Therefore,
|
||||
// we need to use a runtime helper to set the value correctly.
|
||||
var markoWidgetsEventFuncId = transformHelper.context.importModule('markoWidgets_event',
|
||||
@ -59,9 +51,8 @@ function addBubblingEventListener(transformHelper, eventType, targetMethod) {
|
||||
targetMethod,
|
||||
widgetIdExpression
|
||||
]);
|
||||
}
|
||||
|
||||
el.setAttributeValue('data-w-on' + eventType.value, attrValue);
|
||||
el.setAttributeValue('data-_on' + eventType.value, attrValue);
|
||||
}
|
||||
|
||||
function addDirectEventListener(transformHelper, eventType, targetMethod) {
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
module.exports = function(handlerMethodName, widgetId) {
|
||||
return handlerMethodName && (handlerMethodName + '|' + widgetId);
|
||||
return handlerMethodName && [handlerMethodName, widgetId];
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user