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';
|
'use strict';
|
||||||
|
|
||||||
var attr = require('../../../../runtime/html/attr');
|
var runtimeHtmlHelpers = require('../../../../runtime/html/helpers');
|
||||||
var escapeXmlAttr = require('../../../../runtime/html/escapeXml').attr;
|
var attr = runtimeHtmlHelpers.a;
|
||||||
|
var escapeXmlAttr = runtimeHtmlHelpers.xa;
|
||||||
|
|
||||||
function isStringLiteral(node) {
|
function isStringLiteral(node) {
|
||||||
return node.type === 'Literal' && typeof node.value === 'string';
|
return node.type === 'Literal' && typeof node.value === 'string';
|
||||||
@ -76,12 +77,11 @@ function generateCodeForExpressionAttr(name, value, escape, codegen) {
|
|||||||
if (isStringLiteral(part)) {
|
if (isStringLiteral(part)) {
|
||||||
part.value = escapeXmlAttr(part.value);
|
part.value = escapeXmlAttr(part.value);
|
||||||
} else if (part.type === 'Literal') {
|
} else if (part.type === 'Literal') {
|
||||||
|
|
||||||
} else if (isNoEscapeXml(part)) {
|
} else if (isNoEscapeXml(part)) {
|
||||||
part = codegen.builder.functionCall(context.helper('str'), [part]);
|
part = codegen.builder.functionCall(context.helper('str'), [part]);
|
||||||
} else {
|
} else {
|
||||||
if (escape !== false) {
|
if (escape !== false) {
|
||||||
part = codegen.builder.functionCall(context.helper('escapeXmlAttr'), [part]);
|
part = builder.functionCall(context.helper('escapeXmlAttr'), [part]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addHtml(part);
|
addHtml(part);
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var escapeXml = require('../../../../runtime/html/escapeXml');
|
var escapeXml = require('../../../../runtime/html/helpers').x;
|
||||||
var Literal = require('../..//Literal');
|
var Literal = require('../..//Literal');
|
||||||
|
|
||||||
module.exports = function(node, codegen) {
|
module.exports = function(node, codegen) {
|
||||||
|
|||||||
@ -21,16 +21,6 @@ class TextVDOM extends Node {
|
|||||||
|
|
||||||
vdomUtil.registerOptimizer(context);
|
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;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +60,6 @@ class TextVDOM extends Node {
|
|||||||
let escape = this.escape;
|
let escape = this.escape;
|
||||||
|
|
||||||
var funcName = escape ? 't' : 'h';
|
var funcName = escape ? 't' : 'h';
|
||||||
var strFuncId = this.strFuncId;
|
|
||||||
|
|
||||||
function writeTextArgs() {
|
function writeTextArgs() {
|
||||||
writer.write('(');
|
writer.write('(');
|
||||||
@ -84,15 +73,7 @@ class TextVDOM extends Node {
|
|||||||
writer.writeIndent();
|
writer.writeIndent();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arg.type === 'Literal') {
|
writer.write(arg);
|
||||||
writer.write(arg);
|
|
||||||
} else {
|
|
||||||
writer.write(strFuncId);
|
|
||||||
writer.write('(');
|
|
||||||
writer.write(arg);
|
|
||||||
writer.write(')');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.write(')');
|
writer.write(')');
|
||||||
|
|||||||
@ -57,7 +57,6 @@ function generateNodesForArray(nodes, context, options) {
|
|||||||
let nextNodeId = 0;
|
let nextNodeId = 0;
|
||||||
let nextAttrsId = 0;
|
let nextAttrsId = 0;
|
||||||
|
|
||||||
var optimizeTextNodes = options.optimizeTextNodes !== false;
|
|
||||||
var optimizeStaticNodes = options.optimizeStaticNodes !== false;
|
var optimizeStaticNodes = options.optimizeStaticNodes !== false;
|
||||||
|
|
||||||
function generateStaticNode(node) {
|
function generateStaticNode(node) {
|
||||||
@ -112,31 +111,6 @@ function generateNodesForArray(nodes, context, options) {
|
|||||||
finalNodes.push(node);
|
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 {
|
} else {
|
||||||
finalNodes.push(node);
|
finalNodes.push(node);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -91,7 +91,7 @@
|
|||||||
"jsdom": "^9.6.0",
|
"jsdom": "^9.6.0",
|
||||||
"jshint": "^2.5.0",
|
"jshint": "^2.5.0",
|
||||||
"lasso": "^2.4.1",
|
"lasso": "^2.4.1",
|
||||||
"lasso-marko": "^2.0.4",
|
"lasso-marko": "^2.1.0",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"mocha": "^2.3.3",
|
"mocha": "^2.3.3",
|
||||||
"mocha-phantomjs": "^4.1.0",
|
"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';
|
'use strict';
|
||||||
var isArray = Array.isArray;
|
var isArray = Array.isArray;
|
||||||
var load = require('./loader');
|
|
||||||
|
|
||||||
function classListHelper(arg, classNames) {
|
function classListHelper(arg, classNames) {
|
||||||
var len;
|
var len;
|
||||||
@ -93,141 +92,138 @@ LoopStatus.prototype = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
/**
|
||||||
/**
|
* Internal helper method to prevent null/undefined from being written out
|
||||||
* Internal helper method to prevent null/undefined from being written out
|
* when writing text that resolves to null/undefined
|
||||||
* when writing text that resolves to null/undefined
|
* @private
|
||||||
* @private
|
*/
|
||||||
*/
|
exports.s = function strHelper(str) {
|
||||||
s: function(str) {
|
return (str == null) ? '' : str.toString();
|
||||||
return (str == null) ? '' : str.toString();
|
};
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal helper method to handle loops with a status variable
|
* Internal helper method to handle loops with a status variable
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
fv: function (array, callback) {
|
exports.fv = function forEachStatusVariableHelper(array, callback) {
|
||||||
if (!array) {
|
if (!array) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!array.forEach) {
|
if (!array.forEach) {
|
||||||
array = [array];
|
array = [array];
|
||||||
}
|
}
|
||||||
|
|
||||||
var len = array.length;
|
var len = array.length;
|
||||||
var loopStatus = new LoopStatus(len);
|
var loopStatus = new LoopStatus(len);
|
||||||
|
|
||||||
for (; loopStatus.i < len; loopStatus.i++) {
|
for (; loopStatus.i < len; loopStatus.i++) {
|
||||||
var o = array[loopStatus.i];
|
var o = array[loopStatus.i];
|
||||||
callback(o, loopStatus);
|
callback(o, loopStatus);
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal helper method to handle loops without a status variable
|
* Internal helper method to handle loops without a status variable
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
f: function forEach(array, callback) {
|
exports.f = function forEachHelper(array, callback) {
|
||||||
if (isArray(array)) {
|
if (isArray(array)) {
|
||||||
for (var i=0; i<array.length; i++) {
|
for (var i=0; i<array.length; i++) {
|
||||||
callback(array[i]);
|
callback(array[i]);
|
||||||
}
|
|
||||||
} else if (typeof array === 'function') {
|
|
||||||
// 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) {
|
|
||||||
if (!o) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
} else if (typeof array === 'function') {
|
||||||
|
// 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
|
||||||
|
*/
|
||||||
|
exports.fp = function forEachPropertyHelper(o, func) {
|
||||||
|
if (!o) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (Array.isArray(o)) {
|
if (Array.isArray(o)) {
|
||||||
for (var i=0; i<o.length; i++) {
|
for (var i=0; i<o.length; i++) {
|
||||||
func(i, o[i]);
|
func(i, o[i]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (var k in o) {
|
for (var k in o) {
|
||||||
if (o.hasOwnProperty(k)) {
|
if (o.hasOwnProperty(k)) {
|
||||||
func(k, o[k]);
|
func(k, o[k]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to load a custom tag
|
* Helper to load a custom tag
|
||||||
*/
|
*/
|
||||||
t: function (renderer, targetProperty, isRepeated, hasNestedTags) {
|
exports.t = function loadTagHelper(renderer, targetProperty, isRepeated, hasNestedTags) {
|
||||||
if (renderer) {
|
if (renderer) {
|
||||||
renderer = resolveRenderer(renderer);
|
renderer = resolveRenderer(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetProperty || hasNestedTags) {
|
if (targetProperty || hasNestedTags) {
|
||||||
return function(input, out, parent, renderBody) {
|
return function(input, out, parent, renderBody) {
|
||||||
// Handle nested tags
|
// Handle nested tags
|
||||||
if (renderBody) {
|
if (renderBody) {
|
||||||
renderBody(out, input);
|
renderBody(out, input);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetProperty) {
|
if (targetProperty) {
|
||||||
// If we are nested tag then we do not have a renderer
|
// If we are nested tag then we do not have a renderer
|
||||||
if (isRepeated) {
|
if (isRepeated) {
|
||||||
var existingArray = parent[targetProperty];
|
var existingArray = parent[targetProperty];
|
||||||
if (existingArray) {
|
if (existingArray) {
|
||||||
existingArray.push(input);
|
existingArray.push(input);
|
||||||
} else {
|
|
||||||
parent[targetProperty] = [input];
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
parent[targetProperty] = input;
|
parent[targetProperty] = [input];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// We are a tag with nested tags, but we have already found
|
parent[targetProperty] = input;
|
||||||
// our nested tags by rendering the body
|
|
||||||
renderer(input, out);
|
|
||||||
}
|
}
|
||||||
};
|
} else {
|
||||||
} else {
|
// We are a tag with nested tags, but we have already found
|
||||||
return renderer;
|
// our nested tags by rendering the body
|
||||||
}
|
renderer(input, out);
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Merges object properties
|
|
||||||
* @param {[type]} object [description]
|
|
||||||
* @param {[type]} source [description]
|
|
||||||
* @return {[type]} [description]
|
|
||||||
*/
|
|
||||||
m: function(into, source) {
|
|
||||||
for (var k in source) {
|
|
||||||
if (source.hasOwnProperty(k) && !into.hasOwnProperty(k)) {
|
|
||||||
into[k] = source[k];
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
return into;
|
} else {
|
||||||
},
|
return renderer;
|
||||||
|
}
|
||||||
/**
|
|
||||||
* classList(a, b, c, ...)
|
|
||||||
* Joines a list of class names with spaces. Empty class names are omitted.
|
|
||||||
*
|
|
||||||
* classList('a', undefined, 'b') --> 'a b'
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
cl: function() {
|
|
||||||
return classList(arguments);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads a template (__helpers.l --> marko_loadTemplate(path))
|
|
||||||
*/
|
|
||||||
l: load,
|
|
||||||
|
|
||||||
i: require('./include')
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges object properties
|
||||||
|
* @param {[type]} object [description]
|
||||||
|
* @param {[type]} source [description]
|
||||||
|
* @return {[type]} [description]
|
||||||
|
*/
|
||||||
|
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, ...)
|
||||||
|
* Joines a list of class names with spaces. Empty class names are omitted.
|
||||||
|
*
|
||||||
|
* classList('a', undefined, 'b') --> 'a b'
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
exports.cl = function classListHelper() {
|
||||||
|
return classList(arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a template (__helpers.l --> marko_loadTemplate(path))
|
||||||
|
*/
|
||||||
|
exports.l = require('./loader');
|
||||||
|
exports.i = require('./include');
|
||||||
@ -2,11 +2,9 @@
|
|||||||
var EventEmitter = require('events').EventEmitter;
|
var EventEmitter = require('events').EventEmitter;
|
||||||
var StringWriter = require('./StringWriter');
|
var StringWriter = require('./StringWriter');
|
||||||
var BufferedWriter = require('./BufferedWriter');
|
var BufferedWriter = require('./BufferedWriter');
|
||||||
var attr = require('./attr');
|
|
||||||
var escapeXml = require('./escapeXml');
|
|
||||||
var extend = require('raptor-util/extend');
|
var extend = require('raptor-util/extend');
|
||||||
|
var documentProvider = require('../document-provider');
|
||||||
var defaultDocument = typeof document != 'undefined' && document;
|
var helpers;
|
||||||
|
|
||||||
var voidWriter = { write:function(){} };
|
var voidWriter = { write:function(){} };
|
||||||
|
|
||||||
@ -412,12 +410,10 @@ var proto = AsyncStream.prototype = {
|
|||||||
return new AsyncStream(this.global);
|
return new AsyncStream(this.global);
|
||||||
},
|
},
|
||||||
|
|
||||||
beginElement: function(name, attrs) {
|
beginElement: function(name, elementAttrs) {
|
||||||
|
|
||||||
var str = '<' + name;
|
var str = '<' + name;
|
||||||
for (var attrName in attrs) {
|
helpers.as(elementAttrs);
|
||||||
str += attr(attrName, attrs[attrName]);
|
|
||||||
}
|
|
||||||
|
|
||||||
str += '>';
|
str += '>';
|
||||||
|
|
||||||
@ -436,7 +432,7 @@ var proto = AsyncStream.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
text: function(str) {
|
text: function(str) {
|
||||||
this.write(escapeXml(str));
|
this.write(helpers.x(str));
|
||||||
},
|
},
|
||||||
|
|
||||||
getNode: function(doc) {
|
getNode: function(doc) {
|
||||||
@ -446,7 +442,7 @@ var proto = AsyncStream.prototype = {
|
|||||||
var html = this.getOutput();
|
var html = this.getOutput();
|
||||||
|
|
||||||
if (!doc) {
|
if (!doc) {
|
||||||
doc = this.document || defaultDocument;
|
doc = documentProvider.document;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!node) {
|
if (!node) {
|
||||||
@ -504,4 +500,6 @@ proto.w = proto.write;
|
|||||||
|
|
||||||
extend(proto, require('../OutMixins'));
|
extend(proto, require('../OutMixins'));
|
||||||
|
|
||||||
module.exports = AsyncStream;
|
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,120 +1,193 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
var escapeXml = require('./escapeXml');
|
require('raptor-polyfill/string/startsWith');
|
||||||
var escapeXmlAttr = escapeXml.attr;
|
|
||||||
var attr = require('./attr');
|
var warp10 = require('warp10');
|
||||||
var extend = require('raptor-util/extend');
|
var extend = require('raptor-util/extend');
|
||||||
|
|
||||||
var STYLE_ATTR = 'style';
|
var STYLE_ATTR = 'style';
|
||||||
var CLASS_ATTR = 'class';
|
var CLASS_ATTR = 'class';
|
||||||
var escapeEndingScriptTagRegExp = /<\//g;
|
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 = commonHelpers.cl;
|
var classList;
|
||||||
|
|
||||||
module.exports = extend({
|
var replacements = {
|
||||||
/**
|
'<': '<',
|
||||||
* Internal method to escape special XML characters
|
'&': '&',
|
||||||
* @private
|
'"': '"',
|
||||||
*/
|
'\'': ''',
|
||||||
x: escapeXml,
|
'\n': ' ' //Preserve new lines so that they don't get normalized as space
|
||||||
/**
|
};
|
||||||
* Internal method to escape special XML characters within an attribute
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
xa: escapeXmlAttr,
|
|
||||||
|
|
||||||
/**
|
function replaceChar(match) {
|
||||||
* Escapes the '</' sequence in the body of a <script> body to avoid the `<script>` being
|
return replacements[match];
|
||||||
* ended prematurely.
|
}
|
||||||
*
|
|
||||||
* For example:
|
|
||||||
* var evil = {
|
|
||||||
* name: '</script><script>alert(1)</script>'
|
|
||||||
* };
|
|
||||||
*
|
|
||||||
* <script>var foo = ${JSON.stringify(evil)}</script>
|
|
||||||
*
|
|
||||||
* Without escaping the ending '</script>' sequence the opening <script> tag would be
|
|
||||||
* prematurely ended and a new script tag could then be started that could then execute
|
|
||||||
* arbitrary code.
|
|
||||||
*/
|
|
||||||
xs: function(val) {
|
|
||||||
return (typeof val === 'string') ? val.replace(escapeEndingScriptTagRegExp, '\\u003C/') : val;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
function escapeStr(str, regexpTest, regexpReplace) {
|
||||||
* Internal method to render a single HTML attribute
|
return regexpTest.test(str) ? str.replace(regexpReplace, replaceChar) : str;
|
||||||
* @private
|
}
|
||||||
*/
|
|
||||||
a: attr,
|
|
||||||
|
|
||||||
/**
|
function escapeXmlHelper(value, regexpTest, regexpReplace) {
|
||||||
* Internal method to render multiple HTML attributes based on the properties of an object
|
// check for most common case first
|
||||||
* @private
|
if (typeof value === 'string') {
|
||||||
*/
|
return escapeStr(value, regexpTest, regexpReplace);
|
||||||
as: function(arg) {
|
} else if (value == null) {
|
||||||
if (typeof arg === 'object') {
|
|
||||||
var out = '';
|
|
||||||
for (var attrName in arg) {
|
|
||||||
out += attr(attrName, arg[attrName]);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
} else if (typeof arg === 'string') {
|
|
||||||
return arg;
|
|
||||||
}
|
|
||||||
return '';
|
return '';
|
||||||
},
|
} else if (typeof value === 'object') {
|
||||||
|
var safeHTML = value.safeHTML;
|
||||||
/**
|
if (safeHTML != null) {
|
||||||
* Internal helper method to handle the "style" attribute. The value can either
|
return value.safeHTML;
|
||||||
* be a string or an object with style propertes. For example:
|
} else {
|
||||||
*
|
|
||||||
* 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) {
|
|
||||||
if (!style) {
|
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
} else if (value === true || value === false || typeof value === 'number') {
|
||||||
|
return value.toString();
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof style === 'string') {
|
return escapeStr(value.toString(), regexpTest, regexpReplace);
|
||||||
return attr(STYLE_ATTR, style, false);
|
}
|
||||||
} else if (typeof style === 'object') {
|
|
||||||
var parts = [];
|
function escapeXml(value) {
|
||||||
for (var name in style) {
|
return escapeXmlHelper(value, elTest, elTestReplace);
|
||||||
if (style.hasOwnProperty(name)) {
|
}
|
||||||
var value = style[name];
|
|
||||||
if (value) {
|
function escapeXmlAttr(value) {
|
||||||
parts.push(name + ':' + 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal method to escape special XML characters
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
exports.x = escapeXml;
|
||||||
|
/**
|
||||||
|
* Internal method to escape special XML characters within an attribute
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
exports.xa = escapeXmlAttr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escapes the '</' sequence in the body of a <script> body to avoid the `<script>` being
|
||||||
|
* ended prematurely.
|
||||||
|
*
|
||||||
|
* For example:
|
||||||
|
* var evil = {
|
||||||
|
* name: '</script><script>alert(1)</script>'
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* <script>var foo = ${JSON.stringify(evil)}</script>
|
||||||
|
*
|
||||||
|
* Without escaping the ending '</script>' sequence the opening <script> tag would be
|
||||||
|
* prematurely ended and a new script tag could then be started that could then execute
|
||||||
|
* arbitrary code.
|
||||||
|
*/
|
||||||
|
exports.xs = function(val) {
|
||||||
|
return (typeof val === 'string') ? val.replace(escapeEndingScriptTagRegExp, '\\u003C/') : val;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal method to render a single HTML attribute
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
exports.a = attr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal method to render multiple HTML attributes based on the properties of an object
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
exports.as = function(arg) {
|
||||||
|
if (typeof arg === 'object') {
|
||||||
|
var out = '';
|
||||||
|
for (var attrName in arg) {
|
||||||
|
out += attr(attrName, arg[attrName]);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
} else if (typeof arg === 'string') {
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal helper method to handle the "style" attribute. The value can either
|
||||||
|
* be a string or an object with style propertes. For example:
|
||||||
|
*
|
||||||
|
* sa('color: red; font-weight: bold') ==> ' style="color: red; font-weight: bold"'
|
||||||
|
* sa({color: 'red', 'font-weight': 'bold'}) ==> ' style="color: red; font-weight: bold"'
|
||||||
|
*/
|
||||||
|
exports.sa = function(style) {
|
||||||
|
if (!style) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof style === 'string') {
|
||||||
|
return attr(STYLE_ATTR, style, false);
|
||||||
|
} else if (typeof style === 'object') {
|
||||||
|
var parts = [];
|
||||||
|
for (var name in style) {
|
||||||
|
if (style.hasOwnProperty(name)) {
|
||||||
|
var value = style[name];
|
||||||
|
if (value) {
|
||||||
|
parts.push(name + ':' + value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return parts ? attr(STYLE_ATTR, parts.join(';'), false) : '';
|
|
||||||
} else {
|
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
},
|
return parts ? attr(STYLE_ATTR, parts.join(';'), false) : '';
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal helper method to handle the "class" attribute. The value can either
|
* Internal helper method to handle the "class" attribute. The value can either
|
||||||
* be a string, an array or an object. For example:
|
* be a string, an array or an object. For example:
|
||||||
*
|
*
|
||||||
* ca('foo bar') ==> ' class="foo bar"'
|
* ca('foo bar') ==> ' class="foo bar"'
|
||||||
* ca({foo: true, bar: false, baz: true}) ==> ' class="foo baz"'
|
* ca({foo: true, bar: false, baz: true}) ==> ' class="foo baz"'
|
||||||
* ca(['foo', 'bar']) ==> ' class="foo bar"'
|
* ca(['foo', 'bar']) ==> ' class="foo bar"'
|
||||||
*/
|
*/
|
||||||
ca: function(classNames) {
|
exports.ca = function(classNames) {
|
||||||
if (!classNames) {
|
if (!classNames) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof classNames === 'string') {
|
if (typeof classNames === 'string') {
|
||||||
return attr(CLASS_ATTR, classNames, false);
|
return attr(CLASS_ATTR, classNames, false);
|
||||||
} else {
|
} else {
|
||||||
return attr(CLASS_ATTR, classList(classNames), false);
|
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);
|
return new Template(path);
|
||||||
};
|
};
|
||||||
|
|
||||||
var AsyncStream = require('./AsyncStream');
|
var AsyncStream;
|
||||||
|
|
||||||
function createOut(globalData) {
|
function createOut(globalData) {
|
||||||
return new AsyncStream(globalData);
|
return new AsyncStream(globalData);
|
||||||
@ -161,6 +161,10 @@ exports.Template = Template;
|
|||||||
helpers = require('./helpers');
|
helpers = require('./helpers');
|
||||||
exports.helpers = helpers;
|
exports.helpers = helpers;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AsyncStream = require('./AsyncStream');
|
||||||
|
|
||||||
exports.enableAsyncStackTrace = AsyncStream.enableAsyncStackTrace;
|
exports.enableAsyncStackTrace = AsyncStream.enableAsyncStackTrace;
|
||||||
|
|
||||||
require('../')._setRuntime(exports);
|
require('../')._setRuntime(exports);
|
||||||
@ -1,4 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
var documentProvider = require('./document-provider');
|
||||||
|
|
||||||
var runtime;
|
var runtime;
|
||||||
|
|
||||||
function setRuntime(_runtime) {
|
function setRuntime(_runtime) {
|
||||||
@ -6,13 +8,18 @@ function setRuntime(_runtime) {
|
|||||||
}
|
}
|
||||||
exports._setRuntime = setRuntime;
|
exports._setRuntime = setRuntime;
|
||||||
|
|
||||||
var load = require('./loader');
|
|
||||||
|
|
||||||
|
|
||||||
function createOut(globalData) {
|
function createOut(globalData) {
|
||||||
return runtime.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.createOut = createOut;
|
||||||
exports.load = load;
|
exports.load = require('./loader');
|
||||||
exports.events = require('./events');
|
exports.events = require('./events');
|
||||||
@ -4,11 +4,8 @@ var DocumentFragment = require('./DocumentFragment');
|
|||||||
var Comment = require('./Comment');
|
var Comment = require('./Comment');
|
||||||
var Text = require('./Text');
|
var Text = require('./Text');
|
||||||
var extend = require('raptor-util/extend');
|
var extend = require('raptor-util/extend');
|
||||||
|
var virtualizeHTML = require('./virtualizeHTML');
|
||||||
var virtualize = require('./virtualize');
|
var documentProvider = require('../document-provider');
|
||||||
var specialHtmlRegexp = /[&<]/;
|
|
||||||
var defaultDocument = typeof document != 'undefined' && document;
|
|
||||||
|
|
||||||
|
|
||||||
function State(tree) {
|
function State(tree) {
|
||||||
this.remaining = 1;
|
this.remaining = 1;
|
||||||
@ -39,8 +36,6 @@ function AsyncVDOMBuilder(globalData, parentNode, state) {
|
|||||||
this._sync = false;
|
this._sync = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var range;
|
|
||||||
|
|
||||||
var proto = AsyncVDOMBuilder.prototype = {
|
var proto = AsyncVDOMBuilder.prototype = {
|
||||||
isAsyncVDOMBuilder: true,
|
isAsyncVDOMBuilder: true,
|
||||||
|
|
||||||
@ -71,6 +66,22 @@ var proto = AsyncVDOMBuilder.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
text: function(text) {
|
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;
|
var parent = this._parent;
|
||||||
if (parent) {
|
if (parent) {
|
||||||
var lastChild = parent.lastChild;
|
var lastChild = parent.lastChild;
|
||||||
@ -88,39 +99,9 @@ var proto = AsyncVDOMBuilder.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
html: function(html) {
|
html: function(html) {
|
||||||
if (!specialHtmlRegexp.test(html)) {
|
if (html != null) {
|
||||||
return this.text(html);
|
var vdomNode = virtualizeHTML(html, documentProvider.document);
|
||||||
}
|
this.node(vdomNode);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@ -291,7 +272,7 @@ var proto = AsyncVDOMBuilder.prototype = {
|
|||||||
var vdomTree = this.getOutput();
|
var vdomTree = this.getOutput();
|
||||||
|
|
||||||
if (!doc) {
|
if (!doc) {
|
||||||
doc = this.document || defaultDocument;
|
doc = documentProvider.document;
|
||||||
}
|
}
|
||||||
|
|
||||||
node = vdomTree.actualize(doc);
|
node = vdomTree.actualize(doc);
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
|
require('raptor-polyfill/string/startsWith');
|
||||||
var inherit = require('raptor-util/inherit');
|
var inherit = require('raptor-util/inherit');
|
||||||
var extend = require('raptor-util/extend');
|
var extend = require('raptor-util/extend');
|
||||||
var Text = require('./Text');
|
var Text = require('./Text');
|
||||||
var Comment = require('./Comment');
|
var Comment = require('./Comment');
|
||||||
var Node = require('./Node');
|
var Node = require('./Node');
|
||||||
|
var documentProvider = require('../document-provider');
|
||||||
|
var virtualizeHTML;
|
||||||
|
|
||||||
var NS_XLINK = 'http://www.w3.org/1999/xlink';
|
var NS_XLINK = 'http://www.w3.org/1999/xlink';
|
||||||
var ATTR_HREF = 'href';
|
var ATTR_HREF = 'href';
|
||||||
@ -20,6 +23,16 @@ function removePreservedAttributes(attrs) {
|
|||||||
return 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) {
|
function HTMLElementClone(other) {
|
||||||
extend(this, other);
|
extend(this, other);
|
||||||
this.parentNode = undefined;
|
this.parentNode = undefined;
|
||||||
@ -136,6 +149,19 @@ HTMLElement.prototype = {
|
|||||||
if (attrValue == null || attrValue === false) {
|
if (attrValue == null || attrValue === false) {
|
||||||
targetNode.removeAttribute(attrName);
|
targetNode.removeAttribute(attrName);
|
||||||
} else if (oldAttrs[attrName] !== attrValue) {
|
} 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);
|
targetNode.setAttribute(attrName, attrValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,6 +208,20 @@ HTMLElement.prototype = {
|
|||||||
* @param {String} value The text value for the new Text node
|
* @param {String} value The text value for the new Text node
|
||||||
*/
|
*/
|
||||||
t: function(value) {
|
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));
|
this.appendChild(new Text(value));
|
||||||
return this._finishChild();
|
return this._finishChild();
|
||||||
},
|
},
|
||||||
@ -221,9 +261,17 @@ HTMLElement.prototype = {
|
|||||||
for (var attrName in attributes) {
|
for (var attrName in attributes) {
|
||||||
var attrValue = attributes[attrName];
|
var attrValue = attributes[attrName];
|
||||||
|
|
||||||
|
if (attrName.startsWith('data-_')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (attrValue !== false && attrValue != null) {
|
if (attrValue !== false && attrValue != null) {
|
||||||
if (attrValue === true) {
|
var type = typeof attrValue;
|
||||||
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') {
|
if (attrName === 'xlink:href') {
|
||||||
@ -313,4 +361,6 @@ Object.defineProperty(proto, 'disabled', {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = HTMLElement;
|
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';
|
'use strict';
|
||||||
|
|
||||||
var HTMLElement = require('./HTMLElement');
|
var HTMLElement = require('./HTMLElement');
|
||||||
@ -23,67 +7,69 @@ var extend = require('raptor-util/extend');
|
|||||||
|
|
||||||
var classList = commonHelpers.cl;
|
var classList = commonHelpers.cl;
|
||||||
|
|
||||||
module.exports = extend({
|
exports.e = function(tagName, attrs, childCount, constId) {
|
||||||
e: function(tagName, attrs, childCount, constId) {
|
return new HTMLElement(tagName, attrs, childCount, constId);
|
||||||
return new HTMLElement(tagName, attrs, childCount, constId);
|
};
|
||||||
},
|
|
||||||
t: function(value) {
|
|
||||||
return new Text(value);
|
|
||||||
},
|
|
||||||
const: function(id) {
|
|
||||||
var i=0;
|
|
||||||
return function() {
|
|
||||||
return id + (i++);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
exports.t = function(value) {
|
||||||
* Helper for generating the string for a style attribute
|
return new Text(value);
|
||||||
* @param {[type]} style [description]
|
};
|
||||||
* @return {[type]} [description]
|
|
||||||
*/
|
|
||||||
sa: function(style) {
|
|
||||||
if (!style) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof style === 'string') {
|
exports.const = function(id) {
|
||||||
return style;
|
var i=0;
|
||||||
} else if (typeof style === 'object') {
|
return function() {
|
||||||
var parts = [];
|
return id + (i++);
|
||||||
for (var name in style) {
|
};
|
||||||
if (style.hasOwnProperty(name)) {
|
};
|
||||||
var value = style[name];
|
|
||||||
if (value) {
|
/**
|
||||||
parts.push(name + ':' + value);
|
* Helper for generating the string for a style attribute
|
||||||
}
|
* @param {[type]} style [description]
|
||||||
|
* @return {[type]} [description]
|
||||||
|
*/
|
||||||
|
exports.sa = function(style) {
|
||||||
|
if (!style) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof style === 'string') {
|
||||||
|
return style;
|
||||||
|
} else if (typeof style === 'object') {
|
||||||
|
var parts = [];
|
||||||
|
for (var name in style) {
|
||||||
|
if (style.hasOwnProperty(name)) {
|
||||||
|
var value = style[name];
|
||||||
|
if (value) {
|
||||||
|
parts.push(name + ':' + value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return parts ? parts.join(';') : null;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
},
|
return parts ? parts.join(';') : null;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal helper method to handle the "class" attribute. The value can either
|
* Internal helper method to handle the "class" attribute. The value can either
|
||||||
* be a string, an array or an object. For example:
|
* be a string, an array or an object. For example:
|
||||||
*
|
*
|
||||||
* ca('foo bar') ==> ' class="foo bar"'
|
* ca('foo bar') ==> ' class="foo bar"'
|
||||||
* ca({foo: true, bar: false, baz: true}) ==> ' class="foo baz"'
|
* ca({foo: true, bar: false, baz: true}) ==> ' class="foo baz"'
|
||||||
* ca(['foo', 'bar']) ==> ' class="foo bar"'
|
* ca(['foo', 'bar']) ==> ' class="foo bar"'
|
||||||
*/
|
*/
|
||||||
ca: function(classNames) {
|
exports.ca = function(classNames) {
|
||||||
if (!classNames) {
|
if (!classNames) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof classNames === 'string') {
|
if (typeof classNames === 'string') {
|
||||||
return classNames;
|
return classNames;
|
||||||
} else {
|
} else {
|
||||||
return classList(classNames);
|
return classList(classNames);
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
|
|
||||||
inline: require('./')._inline
|
exports.inline = require('./')._inline;
|
||||||
}, commonHelpers);
|
|
||||||
|
extend(exports, commonHelpers);
|
||||||
@ -136,14 +136,6 @@ exports.Template = Template;
|
|||||||
|
|
||||||
exports._inline = createInlineMarkoTemplate;
|
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');
|
helpers = require('./helpers');
|
||||||
exports.helpers = 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"),
|
var marko_helpers = require("marko/runtime/vdom/helpers"),
|
||||||
marko_classList = marko_helpers.cl,
|
marko_classList = marko_helpers.cl,
|
||||||
marko_str = marko_helpers.s,
|
|
||||||
marko_classAttr = marko_helpers.ca;
|
marko_classAttr = marko_helpers.ca;
|
||||||
|
|
||||||
function render(data, out) {
|
function render(data, out) {
|
||||||
@ -13,10 +12,10 @@ function render(data, out) {
|
|||||||
bar: true,
|
bar: true,
|
||||||
baz: false
|
baz: false
|
||||||
}))
|
}))
|
||||||
}, 1)
|
}, 3)
|
||||||
.t("Hello " +
|
.t("Hello ")
|
||||||
marko_str(name) +
|
.t(name)
|
||||||
"!");
|
.t("!");
|
||||||
}
|
}
|
||||||
|
|
||||||
template._ = render;
|
template._ = render;
|
||||||
|
|||||||
@ -2,17 +2,14 @@ var template = require("marko/vdom").c(__filename);
|
|||||||
|
|
||||||
module.exports = template;
|
module.exports = template;
|
||||||
|
|
||||||
var marko_helpers = require("marko/runtime/vdom/helpers"),
|
|
||||||
marko_str = marko_helpers.s;
|
|
||||||
|
|
||||||
function render(data, out) {
|
function render(data, out) {
|
||||||
out.e("div", {
|
out.e("div", {
|
||||||
foo: "bar",
|
foo: "bar",
|
||||||
hello: "world"
|
hello: "world"
|
||||||
}, 1)
|
}, 3)
|
||||||
.t("Hello " +
|
.t("Hello ")
|
||||||
marko_str(name) +
|
.t(name)
|
||||||
"!");
|
.t("!");
|
||||||
}
|
}
|
||||||
|
|
||||||
template._ = render;
|
template._ = render;
|
||||||
|
|||||||
@ -2,19 +2,16 @@ var template = require("marko/vdom").c(__filename);
|
|||||||
|
|
||||||
module.exports = template;
|
module.exports = template;
|
||||||
|
|
||||||
var marko_helpers = require("marko/runtime/vdom/helpers"),
|
|
||||||
marko_str = marko_helpers.s;
|
|
||||||
|
|
||||||
function render(data, out) {
|
function render(data, out) {
|
||||||
var attrs = {
|
var attrs = {
|
||||||
foo: "bar",
|
foo: "bar",
|
||||||
hello: "world"
|
hello: "world"
|
||||||
};
|
};
|
||||||
|
|
||||||
out.e("div", attrs, 1)
|
out.e("div", attrs, 3)
|
||||||
.t("Hello " +
|
.t("Hello ")
|
||||||
marko_str(name) +
|
.t(name)
|
||||||
"!");
|
.t("!");
|
||||||
}
|
}
|
||||||
|
|
||||||
template._ = render;
|
template._ = render;
|
||||||
|
|||||||
@ -2,17 +2,15 @@ var template = require("marko/vdom").c(__filename);
|
|||||||
|
|
||||||
module.exports = template;
|
module.exports = template;
|
||||||
|
|
||||||
var marko_helpers = require("marko/runtime/vdom/helpers"),
|
var marko_attrs0 = {
|
||||||
marko_str = marko_helpers.s,
|
|
||||||
marko_attrs0 = {
|
|
||||||
"class": "foo"
|
"class": "foo"
|
||||||
};
|
};
|
||||||
|
|
||||||
function render(data, out) {
|
function render(data, out) {
|
||||||
out.e("div", marko_attrs0, 1)
|
out.e("div", marko_attrs0, 3)
|
||||||
.t("Hello " +
|
.t("Hello ")
|
||||||
marko_str(name) +
|
.t(name)
|
||||||
"!");
|
.t("!");
|
||||||
}
|
}
|
||||||
|
|
||||||
template._ = render;
|
template._ = render;
|
||||||
|
|||||||
@ -2,15 +2,14 @@ var template = require("marko/vdom").c(__filename);
|
|||||||
|
|
||||||
module.exports = template;
|
module.exports = template;
|
||||||
|
|
||||||
var marko_helpers = require("marko/runtime/vdom/helpers"),
|
|
||||||
marko_str = marko_helpers.s;
|
|
||||||
|
|
||||||
function render(data, out) {
|
function render(data, out) {
|
||||||
out.t("Hello " +
|
out.t("Hello ");
|
||||||
marko_str(name) +
|
|
||||||
"! ");
|
|
||||||
|
|
||||||
out.h(marko_str(message));
|
out.t(name);
|
||||||
|
|
||||||
|
out.t("! ");
|
||||||
|
|
||||||
|
out.h(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
template._ = render;
|
template._ = render;
|
||||||
|
|||||||
@ -3,7 +3,6 @@ var template = require("marko/vdom").c(__filename);
|
|||||||
module.exports = template;
|
module.exports = template;
|
||||||
|
|
||||||
var marko_helpers = require("marko/runtime/vdom/helpers"),
|
var marko_helpers = require("marko/runtime/vdom/helpers"),
|
||||||
marko_str = marko_helpers.s,
|
|
||||||
marko_forEach = marko_helpers.f,
|
marko_forEach = marko_helpers.f,
|
||||||
marko_createElement = marko_helpers.e,
|
marko_createElement = marko_helpers.e,
|
||||||
marko_const = marko_helpers.const,
|
marko_const = marko_helpers.const,
|
||||||
@ -12,17 +11,17 @@ var marko_helpers = require("marko/runtime/vdom/helpers"),
|
|||||||
.t("No colors!");
|
.t("No colors!");
|
||||||
|
|
||||||
function render(data, out) {
|
function render(data, out) {
|
||||||
out.e("h1", null, 1)
|
out.e("h1", null, 3)
|
||||||
.t("Hello " +
|
.t("Hello ")
|
||||||
marko_str(data.name) +
|
.t(data.name)
|
||||||
"!");
|
.t("!");
|
||||||
|
|
||||||
if (data.colors.length) {
|
if (data.colors.length) {
|
||||||
out.be("ul");
|
out.be("ul");
|
||||||
|
|
||||||
marko_forEach(data.colors, function(color) {
|
marko_forEach(data.colors, function(color) {
|
||||||
out.e("li", null, 1)
|
out.e("li", null, 1)
|
||||||
.t(marko_str(color));
|
.t(color);
|
||||||
});
|
});
|
||||||
|
|
||||||
out.ee();
|
out.ee();
|
||||||
|
|||||||
@ -3,7 +3,6 @@ var template = require("marko/vdom").c(__filename);
|
|||||||
module.exports = template;
|
module.exports = template;
|
||||||
|
|
||||||
var marko_helpers = require("marko/runtime/vdom/helpers"),
|
var marko_helpers = require("marko/runtime/vdom/helpers"),
|
||||||
marko_str = marko_helpers.s,
|
|
||||||
marko_createElement = marko_helpers.e,
|
marko_createElement = marko_helpers.e,
|
||||||
marko_const = marko_helpers.const,
|
marko_const = marko_helpers.const,
|
||||||
marko_const_nextId = marko_const("69a896"),
|
marko_const_nextId = marko_const("69a896"),
|
||||||
@ -15,10 +14,10 @@ var marko_helpers = require("marko/runtime/vdom/helpers"),
|
|||||||
|
|
||||||
function render(data, out) {
|
function render(data, out) {
|
||||||
out.e("span", null, 2)
|
out.e("span", null, 2)
|
||||||
.e("h1", null, 1)
|
.e("h1", null, 3)
|
||||||
.t("Hello " +
|
.t("Hello ")
|
||||||
marko_str(data.name) +
|
.t(data.name)
|
||||||
"!")
|
.t("!")
|
||||||
.n(marko_node0);
|
.n(marko_node0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
module.exports = require('marko/widgets').defineComponent({
|
module.exports = require('marko/widgets').defineComponent({
|
||||||
createOut: require('marko/html').createOut,
|
|
||||||
|
|
||||||
renderer: function(input, out) {
|
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 forElId = label.getAttribute('for');
|
||||||
var inputEl = document.getElementById(forElId);
|
var inputEl = document.getElementById(forElId);
|
||||||
|
|
||||||
expect(forElId).to.exist;
|
expect(!!forElId).to.equal(true);
|
||||||
expect(inputEl.value).to.equal('test');
|
expect(inputEl.value).to.equal('test');
|
||||||
expect(label.getAttribute('for-ref')).to.equal(null);
|
expect(label.getAttribute('for-ref')).to.equal(null);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,7 +3,7 @@ var expect = require('chai').expect;
|
|||||||
module.exports = function(helpers) {
|
module.exports = function(helpers) {
|
||||||
var widget = helpers.mount(require('./index'), {});
|
var widget = helpers.mount(require('./index'), {});
|
||||||
|
|
||||||
expect(widget.__document).to.exist;
|
expect(widget.__document != null).to.equal(true);
|
||||||
expect(widget.__document).to.equal(document);
|
expect(widget.__document).to.equal(document);
|
||||||
|
|
||||||
var contentWidget = widget.renderIntoIframe();
|
var contentWidget = widget.renderIntoIframe();
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
module.exports = require('marko/widgets').defineComponent({
|
module.exports = require('marko/widgets').defineComponent({
|
||||||
createOut: require('marko/html').createOut,
|
|
||||||
|
|
||||||
renderer: function(input, out) {
|
renderer: function(input, out) {
|
||||||
out.write('Hello ' + input.name + '!');
|
out.text('Hello ' + input.name + '!');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -10,5 +10,5 @@ module.exports = function(helpers) {
|
|||||||
|
|
||||||
widget.destroy();
|
widget.destroy();
|
||||||
|
|
||||||
expect(widget.update()).to.be.undefined;
|
expect(widget.update() === undefined).to.equal(true);
|
||||||
};
|
};
|
||||||
@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
"dependencies": [
|
"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) {
|
module.exports = function(input, out) {
|
||||||
var asyncOut = out.beginAsync();
|
var asyncOut = out.beginAsync();
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"require: ./components/**/*.js"
|
"require: ./components/app-foo"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"require: ./components/**/*.js"
|
"require: ./components/app-simple"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"require: ./components/**/*.js"
|
"require: ./components/app-foo",
|
||||||
|
"require: ./components/app-bar"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"require: ./components/**/*.js"
|
"require: ./components/app-foo",
|
||||||
|
"require: ./components/app-bar",
|
||||||
|
"require: ./components/app-baz"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"require: ./components/**/*.js"
|
"require: ./components/app-foo",
|
||||||
|
"require: ./components/app-bar",
|
||||||
|
"require: ./components/app-baz"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"require: ./components/**/*.js"
|
"require: ./components/app-foo",
|
||||||
|
"require: ./components/app-bar",
|
||||||
|
"require: ./components/app-baz"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"require: ./components/**/*.js"
|
"require: ./components/app-foo"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"require: ./components/**/widget.js"
|
"require: ./components/app-button-split/widget"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"require: ./components/**/*.js"
|
"require: ./components/app-foo"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"require: ./components/**/*.js"
|
"require: ./components/app-fixed-id",
|
||||||
|
"require: ./components/app-hello/widget"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"require: ./components/**/*.js"
|
"require: ./components/app-foo"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"require: ./components/**/*.js"
|
"require: ./components/app-foo"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -1,7 +1,8 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var escapeXml = require('../../runtime/html/escapeXml');
|
var runtimeHtmlHelpers = require('../../runtime/html/helpers');
|
||||||
var escapeXmlAttr = escapeXml.attr;
|
var escapeXml = runtimeHtmlHelpers.x;
|
||||||
|
var escapeXmlAttr = runtimeHtmlHelpers.xa;
|
||||||
|
|
||||||
var openTagOnly = {};
|
var openTagOnly = {};
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@ const jsdom = require("jsdom").jsdom;
|
|||||||
const expect = require('chai').expect;
|
const expect = require('chai').expect;
|
||||||
|
|
||||||
const defaultDocument = jsdom('<html><body></body></html>');
|
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) {
|
function createAsyncVerifier(main, helpers, out) {
|
||||||
@ -179,10 +179,11 @@ module.exports = function runRenderTest(dir, helpers, done, options) {
|
|||||||
getExpectedHtml(function(err, expectedHtml) {
|
getExpectedHtml(function(err, expectedHtml) {
|
||||||
fs.writeFileSync(path.join(dir, 'vdom-expected.generated.html'), expectedHtml, { encoding: 'utf8' });
|
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
|
// NOTE: We serialie the virtual DOM tree into an HTML string and reparse so that we can
|
||||||
// normalize the text
|
// normalize the text
|
||||||
let vdomHtml = domToHTML(vdomTree);
|
let vdomHtml = domToHTML(actualizedDom);
|
||||||
let vdomRealDocument = jsdom('<html><body>' + vdomHtml + '</body></html>');
|
let vdomRealDocument = jsdom('<html><body>' + vdomHtml + '</body></html>');
|
||||||
let vdomString = domToString(vdomRealDocument.body, { childrenOnly: true });
|
let vdomString = domToString(vdomRealDocument.body, { childrenOnly: true });
|
||||||
helpers.compare(vdomString, 'vdom-', '.generated.html');
|
helpers.compare(vdomString, 'vdom-', '.generated.html');
|
||||||
|
|||||||
@ -1,5 +1,19 @@
|
|||||||
var _addEventListener = require('./addEventListener');
|
var _addEventListener = require('./addEventListener');
|
||||||
var updateManager = require('./update-manager');
|
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 attachBubbleEventListeners = function() {
|
||||||
var body = document.body;
|
var body = document.body;
|
||||||
@ -30,17 +44,22 @@ var attachBubbleEventListeners = function() {
|
|||||||
|
|
||||||
// Search up the tree looking DOM events mapped to target
|
// Search up the tree looking DOM events mapped to target
|
||||||
// widget methods
|
// widget methods
|
||||||
var attrName = 'data-w-on' + eventType;
|
var attrName = 'data-_on' + eventType;
|
||||||
var targetMethod;
|
var target;
|
||||||
var targetWidget;
|
|
||||||
|
|
||||||
// Attributes will have the following form:
|
// Attributes will have the following form:
|
||||||
// w-on<event_type>="<target_method>|<widget_id>"
|
// w-on<event_type>="<target_method>|<widget_id>"
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if ((targetMethod = curNode.getAttribute(attrName))) {
|
if ((target = getEventAttribute(curNode, attrName))) {
|
||||||
var separator = targetMethod.lastIndexOf('|');
|
var targetMethod = target[0];
|
||||||
var targetWidgetId = targetMethod.substring(separator+1);
|
var targetWidgetId = target[1];
|
||||||
|
var targetArgs;
|
||||||
|
|
||||||
|
if (target.length > 2) {
|
||||||
|
targetArgs = target.slice(2);
|
||||||
|
}
|
||||||
|
|
||||||
var targetWidgetEl = document.getElementById(targetWidgetId);
|
var targetWidgetEl = document.getElementById(targetWidgetId);
|
||||||
if (!targetWidgetEl) {
|
if (!targetWidgetEl) {
|
||||||
// The target widget is not in the DOM anymore
|
// The target widget is not in the DOM anymore
|
||||||
@ -50,12 +69,11 @@ var attachBubbleEventListeners = function() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
targetWidget = targetWidgetEl.__widget;
|
var targetWidget = targetWidgetEl.__widget;
|
||||||
|
|
||||||
if (!targetWidget) {
|
if (!targetWidget) {
|
||||||
throw new Error('Widget not found: ' + targetWidgetId);
|
throw new Error('Widget not found: ' + targetWidgetId);
|
||||||
}
|
}
|
||||||
targetMethod = targetMethod.substring(0, separator);
|
|
||||||
|
|
||||||
var targetFunc = targetWidget[targetMethod];
|
var targetFunc = targetWidget[targetMethod];
|
||||||
if (!targetFunc) {
|
if (!targetFunc) {
|
||||||
|
|||||||
@ -42,26 +42,17 @@ function addBubblingEventListener(transformHelper, eventType, targetMethod) {
|
|||||||
builder.identifier('widget'),
|
builder.identifier('widget'),
|
||||||
builder.identifier('id'));
|
builder.identifier('id'));
|
||||||
|
|
||||||
if (targetMethod.type === 'Literal') {
|
// The event handler method is conditional and it may resolve to a null method name. Therefore,
|
||||||
// We know the event handler is method is no conditional so we set the attribute correctly at compile time
|
// we need to use a runtime helper to set the value correctly.
|
||||||
attrValue = builder.concat(
|
var markoWidgetsEventFuncId = transformHelper.context.importModule('markoWidgets_event',
|
||||||
targetMethod,
|
transformHelper.getMarkoWidgetsRequirePath('marko/widgets/taglib/helpers/event'));
|
||||||
builder.literal('|'),
|
|
||||||
widgetIdExpression);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// The event handler method is conditional and it may resolve to a null method name. Therefore,
|
attrValue = builder.functionCall(markoWidgetsEventFuncId, [
|
||||||
// we need to use a runtime helper to set the value correctly.
|
targetMethod,
|
||||||
var markoWidgetsEventFuncId = transformHelper.context.importModule('markoWidgets_event',
|
widgetIdExpression
|
||||||
transformHelper.getMarkoWidgetsRequirePath('marko/widgets/taglib/helpers/event'));
|
]);
|
||||||
|
|
||||||
attrValue = builder.functionCall(markoWidgetsEventFuncId, [
|
el.setAttributeValue('data-_on' + eventType.value, attrValue);
|
||||||
targetMethod,
|
|
||||||
widgetIdExpression
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
el.setAttributeValue('data-w-on' + eventType.value, attrValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function addDirectEventListener(transformHelper, eventType, targetMethod) {
|
function addDirectEventListener(transformHelper, eventType, targetMethod) {
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
module.exports = function(handlerMethodName, widgetId) {
|
module.exports = function(handlerMethodName, widgetId) {
|
||||||
return handlerMethodName && (handlerMethodName + '|' + widgetId);
|
return handlerMethodName && [handlerMethodName, widgetId];
|
||||||
};
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user