mirror of
https://github.com/marko-js/marko.git
synced 2025-12-08 19:26:05 +00:00
More code size reductions
This commit is contained in:
parent
74d802b074
commit
20cf6d364e
35
benchmark/size/marko/rollup.config.js
Normal file
35
benchmark/size/marko/rollup.config.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import commonjsPlugin from 'rollup-plugin-commonjs';
|
||||||
|
import browserifyPlugin from 'rollup-plugin-browserify-transform';
|
||||||
|
import nodeResolvePlugin from 'rollup-plugin-node-resolve';
|
||||||
|
import markoify from 'markoify';
|
||||||
|
import envify from 'envify';
|
||||||
|
import minpropsify from 'minprops/browserify';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
process.env.NODE_ENV = 'production';
|
||||||
|
|
||||||
|
// NODE_ENV=production browserify -t envify -t markoify --extension='.marko' --global-transform minprops/browserify -o build/bundles/marko.js marko/client.js
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
entry: path.join(__dirname, 'client.js'),
|
||||||
|
format: 'iife',
|
||||||
|
moduleName: 'app',
|
||||||
|
plugins: [
|
||||||
|
browserifyPlugin(markoify),
|
||||||
|
browserifyPlugin(envify),
|
||||||
|
browserifyPlugin(minpropsify),
|
||||||
|
nodeResolvePlugin({
|
||||||
|
jsnext: true, // Default: false
|
||||||
|
main: true, // Default: true
|
||||||
|
browser: true, // Default: false
|
||||||
|
preferBuiltins: false,
|
||||||
|
extensions: [ '.js', '.marko' ]
|
||||||
|
}),
|
||||||
|
commonjsPlugin({
|
||||||
|
include: [ 'node_modules/**', '**/*.marko', '**/*.js'],
|
||||||
|
extensions: [ '.js', '.marko' ]
|
||||||
|
})
|
||||||
|
],
|
||||||
|
dest: path.join(__dirname, '../build/bundles/marko.js')
|
||||||
|
};
|
||||||
@ -37,6 +37,11 @@ var minifiers = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const out = gcc.compile(options);
|
const out = gcc.compile(options);
|
||||||
|
|
||||||
|
// if (out.errors && out.errors.length) {
|
||||||
|
// console.error(out.errors);
|
||||||
|
// throw new Error(`Minification failed for ${file}`);
|
||||||
|
// }
|
||||||
return out.compiledCode;
|
return out.compiledCode;
|
||||||
},
|
},
|
||||||
uglify: function minifyUglifyJS(src, file) {
|
uglify: function minifyUglifyJS(src, file) {
|
||||||
|
|||||||
@ -8,9 +8,9 @@
|
|||||||
"build": "npm run bundle --silent && npm run minify --silent",
|
"build": "npm run bundle --silent && npm run minify --silent",
|
||||||
"build-marko": "npm run bundle-marko --silent && node minify.js marko",
|
"build-marko": "npm run bundle-marko --silent && node minify.js marko",
|
||||||
"bundle": "mkdir -p build/bundles && npm run bundle-marko && npm run bundle-react && npm run bundle-vue && npm run bundle-preact",
|
"bundle": "mkdir -p build/bundles && npm run bundle-marko && npm run bundle-react && npm run bundle-vue && npm run bundle-preact",
|
||||||
"bundle-marko": "NODE_ENV=production browserify -t envify -t markoify --extension='.marko' --global-transform minprops/browserify -o build/bundles/marko.js marko/client.js",
|
"bundle-marko": "NODE_ENV=production rollup -c marko/rollup.config.js",
|
||||||
"bundle-react": "NODE_ENV=production browserify -t envify -t babelify --extension='.jsx' --global-transform minprops/browserify -o build/bundles/react.js react/client.jsx",
|
"bundle-react": "NODE_ENV=production rollup -c react/rollup.config.js",
|
||||||
"bundle-preact": "NODE_ENV=production browserify -t envify -t babelify --extension='.jsx' --global-transform minprops/browserify -o build/bundles/preact.js preact/client.jsx",
|
"bundle-preact": "NODE_ENV=production rollup -c preact/rollup.config.js",
|
||||||
"bundle-vue": "NODE_ENV=production browserify -t envify -t vueify --extension='.vue' --global-transform minprops/browserify -o build/bundles/vue.js vue/client.js",
|
"bundle-vue": "NODE_ENV=production browserify -t envify -t vueify --extension='.vue' --global-transform minprops/browserify -o build/bundles/vue.js vue/client.js",
|
||||||
"minify": "node minify.js",
|
"minify": "node minify.js",
|
||||||
"http-server": "http-server"
|
"http-server": "http-server"
|
||||||
@ -18,6 +18,7 @@
|
|||||||
"author": "Patrick Steele-Idem <pnidem@gmail.com>",
|
"author": "Patrick Steele-Idem <pnidem@gmail.com>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"babel-plugin-transform-es2015-block-scoping": "^6.21.0",
|
||||||
"babel-plugin-transform-react-constant-elements": "^6.9.1",
|
"babel-plugin-transform-react-constant-elements": "^6.9.1",
|
||||||
"babel-plugin-transform-react-jsx": "^6.8.0",
|
"babel-plugin-transform-react-jsx": "^6.8.0",
|
||||||
"babel-preset-es2015": "^6.18.0",
|
"babel-preset-es2015": "^6.18.0",
|
||||||
@ -35,6 +36,12 @@
|
|||||||
"preact": "^7.1.0",
|
"preact": "^7.1.0",
|
||||||
"react": "^15.4.1",
|
"react": "^15.4.1",
|
||||||
"react-dom": "^15.4.1",
|
"react-dom": "^15.4.1",
|
||||||
|
"rollup": "^0.39.2",
|
||||||
|
"rollup-plugin-babel": "^2.7.1",
|
||||||
|
"rollup-plugin-browserify-transform": "^0.1.0",
|
||||||
|
"rollup-plugin-commonjs": "^7.0.0",
|
||||||
|
"rollup-plugin-marko": "0.0.2",
|
||||||
|
"rollup-plugin-node-resolve": "^2.0.0",
|
||||||
"uglify-js": "^2.7.5",
|
"uglify-js": "^2.7.5",
|
||||||
"vue": "^2.1.6",
|
"vue": "^2.1.6",
|
||||||
"vueify": "^9.4.0"
|
"vueify": "^9.4.0"
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"presets": [
|
"presets": [
|
||||||
"es2015-loose",
|
["es2015", { "loose": true, "modules": false }],
|
||||||
"stage-0"
|
"stage-0"
|
||||||
],
|
],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
[ "transform-react-jsx", { "pragma": "h" } ]
|
[ "transform-react-jsx", { "pragma": "h" } ],
|
||||||
|
["transform-es2015-block-scoping"]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
import { h, render } from 'preact';
|
var preact = require('preact');
|
||||||
|
var h = preact.h;
|
||||||
|
var render = preact.render;
|
||||||
var App = require('./components/App');
|
var App = require('./components/App');
|
||||||
|
|
||||||
render(
|
render(
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { h, Component } from 'preact';
|
var preact = require('preact');
|
||||||
|
var h = preact.h;
|
||||||
|
var Component = preact.Component;
|
||||||
|
|
||||||
function renderColor(color) {
|
function renderColor(color) {
|
||||||
var style = {
|
var style = {
|
||||||
|
|||||||
35
benchmark/size/preact/rollup.config.js
Normal file
35
benchmark/size/preact/rollup.config.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import commonjsPlugin from 'rollup-plugin-commonjs';
|
||||||
|
import browserifyPlugin from 'rollup-plugin-browserify-transform';
|
||||||
|
import nodeResolvePlugin from 'rollup-plugin-node-resolve';
|
||||||
|
import babelPlugin from 'rollup-plugin-babel';
|
||||||
|
import envify from 'envify';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
process.env.NODE_ENV = 'production';
|
||||||
|
|
||||||
|
// NODE_ENV=production browserify -t envify -t markoify --extension='.marko' --global-transform minprops/browserify -o build/bundles/marko.js marko/client.js
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
entry: path.join(__dirname, 'client.jsx'),
|
||||||
|
format: 'iife',
|
||||||
|
moduleName: 'app',
|
||||||
|
plugins: [
|
||||||
|
babelPlugin({
|
||||||
|
// include: ['node_modules/**', '**/*.js', '**/*.jsx']
|
||||||
|
}),
|
||||||
|
browserifyPlugin(envify),
|
||||||
|
nodeResolvePlugin({
|
||||||
|
jsnext: false, // Default: false
|
||||||
|
main: true, // Default: true
|
||||||
|
browser: true, // Default: false
|
||||||
|
preferBuiltins: false,
|
||||||
|
extensions: [ '.js', '.jsx' ]
|
||||||
|
}),
|
||||||
|
commonjsPlugin({
|
||||||
|
include: [ 'node_modules/**', '**/*.js', '**/*.jsx'],
|
||||||
|
extensions: [ '.js', '.jsx' ]
|
||||||
|
})
|
||||||
|
],
|
||||||
|
dest: path.join(__dirname, '../build/bundles/preact.js')
|
||||||
|
};
|
||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"presets": [
|
"presets": [
|
||||||
"es2015-loose",
|
["es2015", { "loose": true, "modules": false }],
|
||||||
"stage-0",
|
"stage-0",
|
||||||
"react"
|
"react"
|
||||||
],
|
],
|
||||||
|
|||||||
35
benchmark/size/react/rollup.config.js
Normal file
35
benchmark/size/react/rollup.config.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import commonjsPlugin from 'rollup-plugin-commonjs';
|
||||||
|
import browserifyPlugin from 'rollup-plugin-browserify-transform';
|
||||||
|
import nodeResolvePlugin from 'rollup-plugin-node-resolve';
|
||||||
|
import babelPlugin from 'rollup-plugin-babel';
|
||||||
|
import envify from 'envify';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
process.env.NODE_ENV = 'production';
|
||||||
|
|
||||||
|
// NODE_ENV=production browserify -t envify -t markoify --extension='.marko' --global-transform minprops/browserify -o build/bundles/marko.js marko/client.js
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
entry: path.join(__dirname, 'client.jsx'),
|
||||||
|
format: 'iife',
|
||||||
|
moduleName: 'app',
|
||||||
|
plugins: [
|
||||||
|
babelPlugin({
|
||||||
|
exclude: 'node_modules/**'
|
||||||
|
}),
|
||||||
|
browserifyPlugin(envify),
|
||||||
|
nodeResolvePlugin({
|
||||||
|
jsnext: true, // Default: false
|
||||||
|
main: true, // Default: true
|
||||||
|
browser: true, // Default: false
|
||||||
|
preferBuiltins: false,
|
||||||
|
extensions: [ '.js', '.jsx' ]
|
||||||
|
}),
|
||||||
|
commonjsPlugin({
|
||||||
|
include: [ 'node_modules/**', '**/*.js', '**/*.jsx'],
|
||||||
|
extensions: [ '.js', '.jsx' ]
|
||||||
|
})
|
||||||
|
],
|
||||||
|
dest: path.join(__dirname, '../build/bundles/react.js')
|
||||||
|
};
|
||||||
33
benchmark/size/vue/rollup.config.js
Normal file
33
benchmark/size/vue/rollup.config.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import commonjsPlugin from 'rollup-plugin-commonjs';
|
||||||
|
import browserifyPlugin from 'rollup-plugin-browserify-transform';
|
||||||
|
import nodeResolvePlugin from 'rollup-plugin-node-resolve';
|
||||||
|
import vueify from 'vueify';
|
||||||
|
import envify from 'envify';
|
||||||
|
import minpropsify from 'minprops/browserify';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
process.env.NODE_ENV = 'production';
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
entry: path.join(__dirname, 'client.js'),
|
||||||
|
format: 'iife',
|
||||||
|
moduleName: 'app',
|
||||||
|
plugins: [
|
||||||
|
browserifyPlugin(vueify),
|
||||||
|
browserifyPlugin(envify),
|
||||||
|
browserifyPlugin(minpropsify),
|
||||||
|
nodeResolvePlugin({
|
||||||
|
jsnext: true, // Default: false
|
||||||
|
main: true, // Default: true
|
||||||
|
browser: true, // Default: false
|
||||||
|
preferBuiltins: false,
|
||||||
|
extensions: [ '.js', '.vue' ]
|
||||||
|
}),
|
||||||
|
commonjsPlugin({
|
||||||
|
include: [ 'node_modules/**', '**/*.vue', '**/*.js'],
|
||||||
|
extensions: [ '.js', '.vue' ]
|
||||||
|
})
|
||||||
|
],
|
||||||
|
dest: path.join(__dirname, '../build/bundles/vue.js')
|
||||||
|
};
|
||||||
@ -58,22 +58,29 @@ const helpers = {
|
|||||||
'classList': 'cl',
|
'classList': 'cl',
|
||||||
'const': 'const',
|
'const': 'const',
|
||||||
'createElement': 'e',
|
'createElement': 'e',
|
||||||
'createInlineTemplate': 'inline',
|
'createInlineTemplate': {
|
||||||
|
vdom: { module: 'marko/runtime/vdom/helper-createInlineTemplate'},
|
||||||
|
html: { module: 'marko/runtime/html/helper-createInlineTemplate'}
|
||||||
|
},
|
||||||
'escapeXml': 'x',
|
'escapeXml': 'x',
|
||||||
'escapeXmlAttr': 'xa',
|
'escapeXmlAttr': 'xa',
|
||||||
'escapeScript': 'xs',
|
'escapeScript': 'xs',
|
||||||
'forEach': 'f',
|
'forEach': 'f',
|
||||||
'forEachProp': 'fp',
|
'forEachProp': { module: 'marko/runtime/helper-forEachProperty' },
|
||||||
'forEachWithStatusVar': 'fv',
|
'forEachPropStatusVar': { module: 'marko/runtime/helper-forEachPropStatusVar' },
|
||||||
'forRange': 'fr',
|
'forEachWithStatusVar': { module: 'marko/runtime/helper-forEachWithStatusVar' },
|
||||||
|
'forRange': { module: 'marko/runtime/helper-forRange' },
|
||||||
'include': 'i',
|
'include': 'i',
|
||||||
'loadNestedTag': 'n',
|
'loadNestedTag': { module: 'marko/runtime/helper-loadNestedTag' },
|
||||||
'loadTag': 't',
|
'loadTag': 't',
|
||||||
'loadTemplate': 'l',
|
'loadTemplate': { module: 'marko/runtime/helper-loadTemplate' },
|
||||||
'mergeNestedTagsHelper': 'mn',
|
'mergeNestedTagsHelper': { module: 'marko/runtime/helper-mergeNestedTags' },
|
||||||
'merge': 'm',
|
'merge': { module: 'marko/runtime/helper-merge' },
|
||||||
'str': 's',
|
'str': 's',
|
||||||
'styleAttr': 'sa',
|
'styleAttr': {
|
||||||
|
vdom: { module: 'marko/runtime/vdom/helper-styleAttr'},
|
||||||
|
html: 'sa'
|
||||||
|
},
|
||||||
'createText': 't'
|
'createText': 't'
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -672,15 +679,32 @@ class CompileContext extends EventEmitter {
|
|||||||
helper(name) {
|
helper(name) {
|
||||||
var helperIdentifier = this._helpers[name];
|
var helperIdentifier = this._helpers[name];
|
||||||
if (!helperIdentifier) {
|
if (!helperIdentifier) {
|
||||||
var methodName = helpers[name];
|
var helperInfo = helpers[name];
|
||||||
if (!methodName) {
|
|
||||||
|
if (helperInfo && typeof helperInfo === 'object') {
|
||||||
|
if (!helperInfo.module) {
|
||||||
|
helperInfo = helperInfo[this.outputType];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!helperInfo) {
|
||||||
throw new Error('Invalid helper: ' + name);
|
throw new Error('Invalid helper: ' + name);
|
||||||
}
|
}
|
||||||
var methodIdentifier = this.builder.identifier(methodName);
|
|
||||||
|
|
||||||
helperIdentifier = this.addStaticVar(
|
if (typeof helperInfo === 'string') {
|
||||||
'marko_' + name,
|
let methodName = helperInfo;
|
||||||
this.builder.memberExpression(this.helpersIdentifier, methodIdentifier));
|
var methodIdentifier = this.builder.identifier(methodName);
|
||||||
|
|
||||||
|
helperIdentifier = this.addStaticVar(
|
||||||
|
'marko_' + name,
|
||||||
|
this.builder.memberExpression(this.helpersIdentifier, methodIdentifier));
|
||||||
|
} else if (helperInfo && helperInfo.module) {
|
||||||
|
helperIdentifier = this.addStaticVar(
|
||||||
|
'marko_' + name,
|
||||||
|
this.builder.require(this.builder.literal(helperInfo.module)));
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid helper: ' + name);
|
||||||
|
}
|
||||||
|
|
||||||
this._helpers[name] = helperIdentifier;
|
this._helpers[name] = helperIdentifier;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,7 +33,7 @@ class ForEachProp extends Node {
|
|||||||
var builder = codegen.builder;
|
var builder = codegen.builder;
|
||||||
|
|
||||||
if (statusVarName) {
|
if (statusVarName) {
|
||||||
let helperVar = builder.require(builder.literal('marko/runtime/forEachPropStatusVar'));
|
let helperVar = context.helper('forEachPropStatusVar');
|
||||||
let forEachVarName = codegen.addStaticVar('forEacPropStatusVar', helperVar);
|
let forEachVarName = codegen.addStaticVar('forEacPropStatusVar', helperVar);
|
||||||
let body = this.body;
|
let body = this.body;
|
||||||
|
|
||||||
|
|||||||
@ -62,6 +62,11 @@ class TemplateRoot extends Node {
|
|||||||
renderStatements)
|
renderStatements)
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
|
var isBrowser = context.options.browser;
|
||||||
|
var createArgs = isBrowser ?
|
||||||
|
[] :
|
||||||
|
[ builder.identifier('__filename') ];
|
||||||
|
|
||||||
let templateDeclaration = builder.variableDeclarator('marko_template',
|
let templateDeclaration = builder.variableDeclarator('marko_template',
|
||||||
builder.assignment(
|
builder.assignment(
|
||||||
builder.moduleExports(),
|
builder.moduleExports(),
|
||||||
@ -72,9 +77,7 @@ class TemplateRoot extends Node {
|
|||||||
),
|
),
|
||||||
builder.identifier('t')
|
builder.identifier('t')
|
||||||
),
|
),
|
||||||
[
|
createArgs
|
||||||
builder.identifier('__filename')
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|||||||
@ -64,7 +64,7 @@
|
|||||||
"lasso-package-root": "^1.0.0",
|
"lasso-package-root": "^1.0.0",
|
||||||
"listener-tracker": "^2.0.0",
|
"listener-tracker": "^2.0.0",
|
||||||
"minimatch": "^3.0.2",
|
"minimatch": "^3.0.2",
|
||||||
"morphdom": "^2.2.0",
|
"morphdom": "^2.3.0",
|
||||||
"object-assign": "^4.1.0",
|
"object-assign": "^4.1.0",
|
||||||
"property-handlers": "^1.0.0",
|
"property-handlers": "^1.0.0",
|
||||||
"raptor-async": "^1.1.2",
|
"raptor-async": "^1.1.2",
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
var events = require('./events');
|
|
||||||
var domInsert = require('./dom-insert');
|
var domInsert = require('./dom-insert');
|
||||||
var EMPTY_ARRAY = [];
|
|
||||||
|
|
||||||
function checkAddedToDOM(result, method) {
|
function checkAddedToDOM(result, method) {
|
||||||
if (!result.$__widgets) {
|
if (!result.$__widgets) {
|
||||||
@ -57,27 +55,24 @@ var proto = RenderResult.prototype = {
|
|||||||
afterInsert: function(doc) {
|
afterInsert: function(doc) {
|
||||||
var out = this.$__out;
|
var out = this.$__out;
|
||||||
var widgetsContext = out.global.widgets;
|
var widgetsContext = out.global.widgets;
|
||||||
this.$__widgets = (widgetsContext && widgetsContext.$__widgets) || EMPTY_ARRAY;
|
if (widgetsContext) {
|
||||||
|
this.$__widgets = widgetsContext.$__widgets;
|
||||||
events.emit('mountNode', {
|
widgetsContext.$__initWidgets(doc);
|
||||||
result: this,
|
}
|
||||||
out: this.$__out,
|
|
||||||
document: doc
|
|
||||||
}); // NOTE: This will trigger widgets to be initialized if there were any
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
getNode: function(doc) {
|
getNode: function(doc) {
|
||||||
return this.$__out.getNode(doc);
|
return this.$__out.$__getNode(doc);
|
||||||
},
|
},
|
||||||
getOutput: function() {
|
getOutput: function() {
|
||||||
return this.$__out.getOutput();
|
return this.$__out.$__getOutput();
|
||||||
},
|
},
|
||||||
toString: function() {
|
toString: function() {
|
||||||
return this.$__out.toString();
|
return this.$__out.toString();
|
||||||
},
|
},
|
||||||
toJSON: function() {
|
toJSON: function() {
|
||||||
return this.getOutput();
|
return this.$__out.$__getOutput();
|
||||||
},
|
},
|
||||||
document: typeof document !== 'undefined' && document
|
document: typeof document !== 'undefined' && document
|
||||||
};
|
};
|
||||||
|
|||||||
13
runtime/createOut.js
Normal file
13
runtime/createOut.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
var actualCreateOut;
|
||||||
|
|
||||||
|
function setCreateOut(createOutFunc) {
|
||||||
|
actualCreateOut = createOutFunc;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createOut(globalData) {
|
||||||
|
return actualCreateOut(globalData);
|
||||||
|
}
|
||||||
|
|
||||||
|
createOut.$__setCreateOut = setCreateOut;
|
||||||
|
|
||||||
|
module.exports = createOut;
|
||||||
@ -1,70 +1,77 @@
|
|||||||
var path = require('path');
|
var path = require('path');
|
||||||
var resolveFrom = require('resolve-from');
|
var resolveFrom = require('resolve-from');
|
||||||
var Template = require('./html').Template;
|
var Template = require('./html/Template');
|
||||||
|
|
||||||
function getDeps(template) {
|
function getDeps(template) {
|
||||||
if(!template.meta && template.template) {
|
if (!template.meta && template.template) {
|
||||||
template = template.template;
|
template = template.template;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!(template instanceof Template)) {
|
if (!(template instanceof Template)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if(false && template.deps) {
|
if (false && template.deps) {
|
||||||
return template.deps;
|
return template.deps;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!template.meta) {
|
if (!template.meta) {
|
||||||
console.error('Metadata not set for template at ', template.path);
|
console.error('Metadata not set for template at ', template.path);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
var meta = template.meta;
|
var meta = template.meta;
|
||||||
var root = path.dirname(template.path);
|
var root = path.dirname(template.path);
|
||||||
var deps = [];
|
var deps = [];
|
||||||
|
|
||||||
if(meta.tags) {
|
if (meta.tags) {
|
||||||
meta.tags.forEach(tagPath => {
|
meta.tags.forEach(tagPath => {
|
||||||
var tag = resolveFrom(root, tagPath);
|
var tag = resolveFrom(root, tagPath);
|
||||||
var tagDeps = getDeps(require(tag));
|
var tagDeps = getDeps(require(tag));
|
||||||
deps.push.apply(deps, tagDeps);
|
deps.push.apply(deps, tagDeps);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(meta.deps) {
|
if (meta.deps) {
|
||||||
deps.push.apply(deps, meta.deps.map(d => resolveDep(d, root)));
|
deps.push.apply(deps, meta.deps.map(d => resolveDep(d, root)));
|
||||||
}
|
}
|
||||||
|
|
||||||
deps = dedupeDeps(deps);
|
deps = dedupeDeps(deps);
|
||||||
|
|
||||||
template.deps = deps;
|
template.deps = deps;
|
||||||
|
|
||||||
return deps;
|
return deps;
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveDep(dep, root) {
|
function resolveDep(dep, root) {
|
||||||
if(typeof dep === 'string') {
|
if (typeof dep === 'string') {
|
||||||
dep = parseDependencyString(dep);
|
dep = parseDependencyString(dep);
|
||||||
}
|
}
|
||||||
if(dep.path) {
|
if (dep.path) {
|
||||||
return Object.assign({}, dep, { path:resolveFrom(root, dep.path) });
|
return Object.assign({}, dep, {
|
||||||
} else if(dep.virtualPath) {
|
path: resolveFrom(root, dep.path)
|
||||||
return Object.assign({}, dep, { virtualPath:path.resolve(root, dep.virtualPath) });
|
});
|
||||||
} else {
|
} else if (dep.virtualPath) {
|
||||||
return dep;
|
return Object.assign({}, dep, {
|
||||||
}
|
virtualPath: path.resolve(root, dep.virtualPath)
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return dep;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDependencyString(string) {
|
function parseDependencyString(string) {
|
||||||
var match = /^(?:([\w-]+)(?:\:\s*|\s+))?(.*?(?:\.(\w+))?)$/.exec(string);
|
var match = /^(?:([\w-]+)(?:\:\s*|\s+))?(.*?(?:\.(\w+))?)$/.exec(string);
|
||||||
return { type:match[1]||match[3], path:match[2] };
|
return {
|
||||||
|
type: match[1] || match[3],
|
||||||
|
path: match[2]
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function dedupeDeps(deps) {
|
function dedupeDeps(deps) {
|
||||||
return deps;
|
return deps;
|
||||||
}
|
}
|
||||||
|
|
||||||
require('./html').Template.prototype.getDependencies = function() {
|
Template.prototype.getDependencies = function() {
|
||||||
return getDeps(this);
|
return getDeps(this);
|
||||||
};
|
};
|
||||||
@ -1 +0,0 @@
|
|||||||
exports.$__document = typeof document != 'undefined' && document;
|
|
||||||
@ -1,5 +1,7 @@
|
|||||||
var events = require('./events');
|
|
||||||
var extend = require('raptor-util/extend');
|
var extend = require('raptor-util/extend');
|
||||||
|
var widgetsUtil = require('../widgets/util');
|
||||||
|
var destroyWidgetForEl = widgetsUtil.$__destroyWidgetForEl;
|
||||||
|
var destroyElRecursive = widgetsUtil.$__destroyElRecursive;
|
||||||
|
|
||||||
function resolveEl(el) {
|
function resolveEl(el) {
|
||||||
if (typeof el === 'string') {
|
if (typeof el === 'string') {
|
||||||
@ -13,33 +15,34 @@ function resolveEl(el) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function beforeRemove(referenceEl) {
|
function beforeRemove(referenceEl) {
|
||||||
events.emit('dom/beforeRemove', {
|
destroyElRecursive(referenceEl);
|
||||||
el: referenceEl
|
destroyWidgetForEl(referenceEl);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = function(target, getEl, afterInsert) {
|
module.exports = function(target, getEl, afterInsert) {
|
||||||
extend(target, {
|
extend(target, {
|
||||||
appendTo: function(referenceEl) {
|
appendTo: function(referenceEl) {
|
||||||
|
referenceEl = resolveEl(referenceEl);
|
||||||
var el = getEl(this, referenceEl);
|
var el = getEl(this, referenceEl);
|
||||||
resolveEl(referenceEl).appendChild(el);
|
referenceEl.appendChild(el);
|
||||||
return afterInsert(this, referenceEl);
|
return afterInsert(this, referenceEl);
|
||||||
},
|
},
|
||||||
prependTo: function(referenceEl) {
|
prependTo: function(referenceEl) {
|
||||||
|
referenceEl = resolveEl(referenceEl);
|
||||||
var el = getEl(this, referenceEl);
|
var el = getEl(this, referenceEl);
|
||||||
referenceEl.insertBefore(el, referenceEl.firstChild || null);
|
referenceEl.insertBefore(el, referenceEl.firstChild || null);
|
||||||
return afterInsert(this, referenceEl);
|
return afterInsert(this, referenceEl);
|
||||||
},
|
},
|
||||||
replace: function(referenceEl) {
|
replace: function(referenceEl) {
|
||||||
var el = getEl(this, referenceEl);
|
|
||||||
referenceEl = resolveEl(referenceEl);
|
referenceEl = resolveEl(referenceEl);
|
||||||
|
var el = getEl(this, referenceEl);
|
||||||
beforeRemove(referenceEl);
|
beforeRemove(referenceEl);
|
||||||
referenceEl.parentNode.replaceChild(el, referenceEl);
|
referenceEl.parentNode.replaceChild(el, referenceEl);
|
||||||
return afterInsert(this, referenceEl);
|
return afterInsert(this, referenceEl);
|
||||||
},
|
},
|
||||||
replaceChildrenOf: function(referenceEl) {
|
replaceChildrenOf: function(referenceEl) {
|
||||||
var el = getEl(this, referenceEl);
|
|
||||||
referenceEl = resolveEl(referenceEl);
|
referenceEl = resolveEl(referenceEl);
|
||||||
|
var el = getEl(this, referenceEl);
|
||||||
|
|
||||||
var curChild = referenceEl.firstChild;
|
var curChild = referenceEl.firstChild;
|
||||||
while(curChild) {
|
while(curChild) {
|
||||||
@ -53,14 +56,14 @@ module.exports = function(target, getEl, afterInsert) {
|
|||||||
return afterInsert(this, referenceEl);
|
return afterInsert(this, referenceEl);
|
||||||
},
|
},
|
||||||
insertBefore: function(referenceEl) {
|
insertBefore: function(referenceEl) {
|
||||||
var el = getEl(this, referenceEl);
|
|
||||||
referenceEl = resolveEl(referenceEl);
|
referenceEl = resolveEl(referenceEl);
|
||||||
|
var el = getEl(this, referenceEl);
|
||||||
referenceEl.parentNode.insertBefore(el, referenceEl);
|
referenceEl.parentNode.insertBefore(el, referenceEl);
|
||||||
return afterInsert(this, referenceEl);
|
return afterInsert(this, referenceEl);
|
||||||
},
|
},
|
||||||
insertAfter: function(referenceEl) {
|
insertAfter: function(referenceEl) {
|
||||||
var el = getEl(this, referenceEl);
|
|
||||||
referenceEl = resolveEl(referenceEl);
|
referenceEl = resolveEl(referenceEl);
|
||||||
|
var el = getEl(this, referenceEl);
|
||||||
el = el;
|
el = el;
|
||||||
var nextSibling = referenceEl.nextSibling;
|
var nextSibling = referenceEl.nextSibling;
|
||||||
var parentNode = referenceEl.parentNode;
|
var parentNode = referenceEl.parentNode;
|
||||||
|
|||||||
30
runtime/env-init.js
Normal file
30
runtime/env-init.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
require('./stream');
|
||||||
|
require('./dependencies');
|
||||||
|
|
||||||
|
if (process.env.hasOwnProperty('MARKO_HOT_RELOAD')) {
|
||||||
|
require('../hot-reload').enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If process was launched with browser refresh then automatically
|
||||||
|
// enable browser-refresh
|
||||||
|
require('../browser-refresh').enable();
|
||||||
|
|
||||||
|
function fixFlush() {
|
||||||
|
try {
|
||||||
|
var OutgoingMessage = require('http').OutgoingMessage;
|
||||||
|
if (OutgoingMessage.prototype.flush && OutgoingMessage.prototype.flush.toString().indexOf('deprecated') !== -1) {
|
||||||
|
// Yes, we are monkey-patching http. This method should never have been added and it was introduced on
|
||||||
|
// the iojs fork. It was quickly deprecated and I'm 99% sure no one is actually using it.
|
||||||
|
// See:
|
||||||
|
// - https://github.com/marko-js/async-writer/issues/3
|
||||||
|
// - https://github.com/nodejs/node/issues/2920
|
||||||
|
//
|
||||||
|
// This method causes problems since marko looks for the flush method and calls it found.
|
||||||
|
// The `res.flush()` method is introduced by the [compression](https://www.npmjs.com/package/compression)
|
||||||
|
// middleware, but, otherwise, it should typically not exist.
|
||||||
|
delete require('http').OutgoingMessage.prototype.flush;
|
||||||
|
}
|
||||||
|
} catch(e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fixFlush();
|
||||||
@ -7,7 +7,7 @@ function LoopStatus(getLength, isLast, isFirst, getIndex) {
|
|||||||
this.getIndex = getIndex;
|
this.getIndex = getIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = function forEachPropStatusVar(object, callback) {
|
module.exports = function forEachPropStatusVarHelper(object, callback) {
|
||||||
var keys = Object.keys(object);
|
var keys = Object.keys(object);
|
||||||
|
|
||||||
var i = 0;
|
var i = 0;
|
||||||
27
runtime/helper-forEachProperty.js
Normal file
27
runtime/helper-forEachProperty.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
var isArray = Array.isArray;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal helper method for looping over the properties of any object
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
module.exports = function forEachPropertyHelper(o, func) {
|
||||||
|
if (!o) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isArray(o)) {
|
||||||
|
for (var i=0; i<o.length; i++) {
|
||||||
|
func(i, o[i]);
|
||||||
|
}
|
||||||
|
} else if (typeof Map && o instanceof Map) {
|
||||||
|
o.forEach(function(v, k) {
|
||||||
|
func(k, v);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
for (var k in o) {
|
||||||
|
if (o.hasOwnProperty(k)) {
|
||||||
|
func(k, o[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
40
runtime/helper-forEachWithStatusVar.js
Normal file
40
runtime/helper-forEachWithStatusVar.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
function LoopStatus(len) {
|
||||||
|
this.i = 0;
|
||||||
|
this.len = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
LoopStatus.prototype = {
|
||||||
|
getLength: function() {
|
||||||
|
return this.len;
|
||||||
|
},
|
||||||
|
isLast: function() {
|
||||||
|
return this.i === this.len - 1;
|
||||||
|
},
|
||||||
|
isFirst: function() {
|
||||||
|
return this.i === 0;
|
||||||
|
},
|
||||||
|
getIndex: function() {
|
||||||
|
return this.i;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal helper method to handle loops with a status variable
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
module.exports = function forEachStatusVariableHelper(array, callback) {
|
||||||
|
if (!array) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!array.forEach) {
|
||||||
|
array = [array];
|
||||||
|
}
|
||||||
|
|
||||||
|
var len = array.length;
|
||||||
|
var loopStatus = new LoopStatus(len);
|
||||||
|
|
||||||
|
for (; loopStatus.i < len; loopStatus.i++) {
|
||||||
|
var o = array[loopStatus.i];
|
||||||
|
callback(o, loopStatus);
|
||||||
|
}
|
||||||
|
};
|
||||||
18
runtime/helper-forRange.js
Normal file
18
runtime/helper-forRange.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
module.exports = function forRangeHelper(from, to, step, callback) {
|
||||||
|
if (step == null) {
|
||||||
|
step = from <= to ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var i;
|
||||||
|
|
||||||
|
if (step > 0) {
|
||||||
|
for (i=from; i<=to; i += step) {
|
||||||
|
callback(i);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (i=from; i>=to; i += step) {
|
||||||
|
callback(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
15
runtime/helper-loadNestedTag.js
Normal file
15
runtime/helper-loadNestedTag.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
module.exports = function loadNestedTagHelper(targetProperty, isRepeated) {
|
||||||
|
return function(input, parent) {
|
||||||
|
// If we are nested tag then we do not have a renderer
|
||||||
|
if (isRepeated) {
|
||||||
|
var existingArray = parent[targetProperty];
|
||||||
|
if (existingArray) {
|
||||||
|
existingArray.push(input);
|
||||||
|
} else {
|
||||||
|
parent[targetProperty] = [input];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
parent[targetProperty] = input;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
4
runtime/helper-loadTemplate.js
Normal file
4
runtime/helper-loadTemplate.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/**
|
||||||
|
* Loads a template
|
||||||
|
*/
|
||||||
|
module.exports = require('./loader');
|
||||||
16
runtime/helper-merge.js
Normal file
16
runtime/helper-merge.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* Merges object properties
|
||||||
|
* @param {[type]} object [description]
|
||||||
|
* @param {[type]} source [description]
|
||||||
|
* @return {[type]} [description]
|
||||||
|
*/
|
||||||
|
function merge(into, source) {
|
||||||
|
for (var k in source) {
|
||||||
|
if (source.hasOwnProperty(k) && !into.hasOwnProperty(k)) {
|
||||||
|
into[k] = source[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return into;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = merge;
|
||||||
15
runtime/helper-mergeNestedTags.js
Normal file
15
runtime/helper-mergeNestedTags.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/**
|
||||||
|
* Merges nested tags by rendering the body
|
||||||
|
* @param {[type]} object [description]
|
||||||
|
* @param {[type]} source [description]
|
||||||
|
* @return {[type]} [description]
|
||||||
|
*/
|
||||||
|
function mergeNestedTags(input) {
|
||||||
|
if (input.renderBody) {
|
||||||
|
input.renderBody(null, input);
|
||||||
|
}
|
||||||
|
input.renderBody = null;
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = mergeNestedTags;
|
||||||
@ -1,6 +1,10 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
var isArray = Array.isArray;
|
var isArray = Array.isArray;
|
||||||
|
|
||||||
|
function isFunction(arg) {
|
||||||
|
return typeof arg === 'function';
|
||||||
|
}
|
||||||
|
|
||||||
function classListHelper(arg, classNames) {
|
function classListHelper(arg, classNames) {
|
||||||
var len;
|
var len;
|
||||||
|
|
||||||
@ -40,8 +44,8 @@ function createDeferredRenderer(handler) {
|
|||||||
// This is the initial function that will do the rendering. We replace
|
// This is the initial function that will do the rendering. We replace
|
||||||
// the renderer with the actual renderer func on the first render
|
// the renderer with the actual renderer func on the first render
|
||||||
deferredRenderer.renderer = function(input, out) {
|
deferredRenderer.renderer = function(input, out) {
|
||||||
var rendererFunc = handler.renderer || handler.render;
|
var rendererFunc = handler.renderer || handler._ || handler.render;
|
||||||
if (typeof rendererFunc !== 'function') {
|
if (!isFunction(rendererFunc)) {
|
||||||
throw Error('Invalid renderer');
|
throw Error('Invalid renderer');
|
||||||
}
|
}
|
||||||
// Use the actual renderer from now on
|
// Use the actual renderer from now on
|
||||||
@ -59,14 +63,10 @@ function resolveRenderer(handler) {
|
|||||||
return renderer;
|
return renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof handler === 'function') {
|
if (isFunction(handler)) {
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof (renderer = handler.render) === 'function') {
|
|
||||||
return renderer.bind(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the user code has a circular function then the renderer function
|
// If the user code has a circular function then the renderer function
|
||||||
// may not be available on the module. Since we can't get a reference
|
// may not be available on the module. Since we can't get a reference
|
||||||
// to the actual renderer(input, out) function right now we lazily
|
// to the actual renderer(input, out) function right now we lazily
|
||||||
@ -74,26 +74,6 @@ function resolveRenderer(handler) {
|
|||||||
return createDeferredRenderer(handler);
|
return createDeferredRenderer(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
function LoopStatus(len) {
|
|
||||||
this.i = 0;
|
|
||||||
this.len = len;
|
|
||||||
}
|
|
||||||
|
|
||||||
LoopStatus.prototype = {
|
|
||||||
getLength: function() {
|
|
||||||
return this.len;
|
|
||||||
},
|
|
||||||
isLast: function() {
|
|
||||||
return this.i === this.len - 1;
|
|
||||||
},
|
|
||||||
isFirst: function() {
|
|
||||||
return this.i === 0;
|
|
||||||
},
|
|
||||||
getIndex: function() {
|
|
||||||
return this.i;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
@ -103,27 +83,6 @@ exports.s = function strHelper(str) {
|
|||||||
return (str == null) ? '' : str.toString();
|
return (str == null) ? '' : str.toString();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal helper method to handle loops with a status variable
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
exports.fv = function forEachStatusVariableHelper(array, callback) {
|
|
||||||
if (!array) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!array.forEach) {
|
|
||||||
array = [array];
|
|
||||||
}
|
|
||||||
|
|
||||||
var len = array.length;
|
|
||||||
var loopStatus = new LoopStatus(len);
|
|
||||||
|
|
||||||
for (; loopStatus.i < len; loopStatus.i++) {
|
|
||||||
var o = array[loopStatus.i];
|
|
||||||
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
|
||||||
@ -133,57 +92,12 @@ exports.f = function forEachHelper(array, callback) {
|
|||||||
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') {
|
} else if (isFunction(array)) {
|
||||||
// Also allow the first argument to be a custom iterator function
|
// Also allow the first argument to be a custom iterator function
|
||||||
array(callback);
|
array(callback);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.fr = function forRangeHelper(from, to, step, callback) {
|
|
||||||
if (step == null) {
|
|
||||||
step = from <= to ? 1 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
var i;
|
|
||||||
|
|
||||||
if (step > 0) {
|
|
||||||
for (i=from; i<=to; i += step) {
|
|
||||||
callback(i);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (i=from; i>=to; i += step) {
|
|
||||||
callback(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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)) {
|
|
||||||
for (var i=0; i<o.length; i++) {
|
|
||||||
func(i, o[i]);
|
|
||||||
}
|
|
||||||
} else if (typeof Map && o instanceof Map) {
|
|
||||||
o.forEach(function(v, k) {
|
|
||||||
func(k, v);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
for (var k in o) {
|
|
||||||
if (o.hasOwnProperty(k)) {
|
|
||||||
func(k, o[k]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to load a custom tag
|
* Helper to load a custom tag
|
||||||
*/
|
*/
|
||||||
@ -195,51 +109,6 @@ exports.t = function loadTagHelper(renderer, targetProperty, isRepeated) {
|
|||||||
return renderer;
|
return renderer;
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.n = function loadNestedTagHelper(targetProperty, isRepeated) {
|
|
||||||
return function(input, parent) {
|
|
||||||
// If we are nested tag then we do not have a renderer
|
|
||||||
if (isRepeated) {
|
|
||||||
var existingArray = parent[targetProperty];
|
|
||||||
if (existingArray) {
|
|
||||||
existingArray.push(input);
|
|
||||||
} else {
|
|
||||||
parent[targetProperty] = [input];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
parent[targetProperty] = input;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Merges nested tags by rendering the body
|
|
||||||
* @param {[type]} object [description]
|
|
||||||
* @param {[type]} source [description]
|
|
||||||
* @return {[type]} [description]
|
|
||||||
*/
|
|
||||||
exports.mn = function mergeNestedTagsHelper(input) {
|
|
||||||
if (input.renderBody) {
|
|
||||||
input.renderBody(null, input);
|
|
||||||
}
|
|
||||||
input.renderBody = null;
|
|
||||||
return input;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* classList(a, b, c, ...)
|
* classList(a, b, c, ...)
|
||||||
* Joines a list of class names with spaces. Empty class names are omitted.
|
* Joines a list of class names with spaces. Empty class names are omitted.
|
||||||
@ -249,9 +118,4 @@ exports.mn = function mergeNestedTagsHelper(input) {
|
|||||||
*/
|
*/
|
||||||
exports.cl = function classListHelper() {
|
exports.cl = function classListHelper() {
|
||||||
return classList(arguments);
|
return classList(arguments);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads a template (__helpers.l --> marko_loadTemplate(path))
|
|
||||||
*/
|
|
||||||
exports.l = require('./loader');
|
|
||||||
@ -2,9 +2,10 @@
|
|||||||
var EventEmitter = require('events-light');
|
var EventEmitter = require('events-light');
|
||||||
var StringWriter = require('./StringWriter');
|
var StringWriter = require('./StringWriter');
|
||||||
var BufferedWriter = require('./BufferedWriter');
|
var BufferedWriter = require('./BufferedWriter');
|
||||||
var documentProvider = require('../document-provider');
|
var defaultDocument = typeof document != 'undefined' && document;
|
||||||
var RenderResult = require('../RenderResult');
|
var RenderResult = require('../RenderResult');
|
||||||
var helpers;
|
var attrsHelper = require('./helper-attrs');
|
||||||
|
var escapeXml = require('./escape').escapeXml;
|
||||||
|
|
||||||
var voidWriter = { write:function(){} };
|
var voidWriter = { write:function(){} };
|
||||||
|
|
||||||
@ -37,7 +38,7 @@ function AsyncStream(global, writer, state, shouldBuffer) {
|
|||||||
writer = new BufferedWriter(writer);
|
writer = new BufferedWriter(writer);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
writer = originalStream = new StringWriter(events);
|
writer = originalStream = new StringWriter();
|
||||||
}
|
}
|
||||||
|
|
||||||
state = new State(this, originalStream, writer, events);
|
state = new State(this, originalStream, writer, events);
|
||||||
@ -69,7 +70,8 @@ AsyncStream.enableAsyncStackTrace = function() {
|
|||||||
|
|
||||||
var proto = AsyncStream.prototype = {
|
var proto = AsyncStream.prototype = {
|
||||||
constructor: AsyncStream,
|
constructor: AsyncStream,
|
||||||
isOut: true,
|
$__document: defaultDocument,
|
||||||
|
$__isOut: true,
|
||||||
|
|
||||||
sync: function() {
|
sync: function() {
|
||||||
this._sync = true;
|
this._sync = true;
|
||||||
@ -86,15 +88,22 @@ var proto = AsyncStream.prototype = {
|
|||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
getOutput: function() {
|
$__getOutput: function() {
|
||||||
return this._state.writer.toString();
|
return this._state.writer.toString();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Legacy...
|
||||||
|
*/
|
||||||
|
getOutput: function() {
|
||||||
|
return this.$__getOutput();
|
||||||
|
},
|
||||||
|
|
||||||
toString: function() {
|
toString: function() {
|
||||||
return this._state.writer.toString();
|
return this._state.writer.toString();
|
||||||
},
|
},
|
||||||
|
|
||||||
getResult: function() {
|
$__getResult: function() {
|
||||||
this._result = this._result || new RenderResult(this);
|
this._result = this._result || new RenderResult(this);
|
||||||
return this._result;
|
return this._result;
|
||||||
},
|
},
|
||||||
@ -228,10 +237,11 @@ var proto = AsyncStream.prototype = {
|
|||||||
|
|
||||||
if (remaining === 0) {
|
if (remaining === 0) {
|
||||||
state.finished = true;
|
state.finished = true;
|
||||||
|
|
||||||
if (state.writer.end) {
|
if (state.writer.end) {
|
||||||
state.writer.end();
|
state.writer.end();
|
||||||
} else {
|
} else {
|
||||||
state.events.emit('finish', this);
|
state.events.emit('finish', this.$__getResult());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -300,7 +310,7 @@ var proto = AsyncStream.prototype = {
|
|||||||
var state = this._state;
|
var state = this._state;
|
||||||
|
|
||||||
if (event === 'finish' && state.finished) {
|
if (event === 'finish' && state.finished) {
|
||||||
callback(this);
|
callback(this.$__getResult());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,7 +322,7 @@ var proto = AsyncStream.prototype = {
|
|||||||
var state = this._state;
|
var state = this._state;
|
||||||
|
|
||||||
if (event === 'finish' && state.finished) {
|
if (event === 'finish' && state.finished) {
|
||||||
callback(this);
|
callback(this.$__getResult());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -420,7 +430,7 @@ var proto = AsyncStream.prototype = {
|
|||||||
|
|
||||||
element: function(tagName, elementAttrs, openTagOnly) {
|
element: function(tagName, elementAttrs, openTagOnly) {
|
||||||
var str = '<' + tagName +
|
var str = '<' + tagName +
|
||||||
helpers.as(elementAttrs) +
|
attrsHelper(elementAttrs) +
|
||||||
'>';
|
'>';
|
||||||
|
|
||||||
if (openTagOnly !== true) {
|
if (openTagOnly !== true) {
|
||||||
@ -433,7 +443,7 @@ var proto = AsyncStream.prototype = {
|
|||||||
beginElement: function(name, elementAttrs) {
|
beginElement: function(name, elementAttrs) {
|
||||||
|
|
||||||
var str = '<' + name +
|
var str = '<' + name +
|
||||||
helpers.as(elementAttrs) +
|
attrsHelper(elementAttrs) +
|
||||||
'>';
|
'>';
|
||||||
|
|
||||||
this.write(str);
|
this.write(str);
|
||||||
@ -451,17 +461,17 @@ var proto = AsyncStream.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
text: function(str) {
|
text: function(str) {
|
||||||
this.write(helpers.x(str));
|
this.write(escapeXml(str));
|
||||||
},
|
},
|
||||||
|
|
||||||
getNode: function(doc) {
|
$__getNode: function(doc) {
|
||||||
var node = this._node;
|
var node = this._node;
|
||||||
var curEl;
|
var curEl;
|
||||||
var newBodyEl;
|
var newBodyEl;
|
||||||
var html = this.getOutput();
|
var html = this.$__getOutput();
|
||||||
|
|
||||||
if (!doc) {
|
if (!doc) {
|
||||||
doc = documentProvider.$__document;
|
doc = this.$__document;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!node) {
|
if (!node) {
|
||||||
@ -491,8 +501,8 @@ var proto = AsyncStream.prototype = {
|
|||||||
var out = this;
|
var out = this;
|
||||||
var promise = new Promise(function(resolve, reject) {
|
var promise = new Promise(function(resolve, reject) {
|
||||||
out.on('error', reject);
|
out.on('error', reject);
|
||||||
out.on('finish', function() {
|
out.on('finish', function(result) {
|
||||||
resolve(out.getResult());
|
resolve(result);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -507,6 +517,4 @@ var proto = AsyncStream.prototype = {
|
|||||||
// alias:
|
// alias:
|
||||||
proto.w = proto.write;
|
proto.w = proto.write;
|
||||||
|
|
||||||
module.exports = AsyncStream;
|
module.exports = AsyncStream;
|
||||||
|
|
||||||
helpers = require('./helpers');
|
|
||||||
@ -1,19 +1,10 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
function StringWriter(events) {
|
function StringWriter() {
|
||||||
this.str = '';
|
this.str = '';
|
||||||
this.events = events;
|
|
||||||
this.finished = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StringWriter.prototype = {
|
StringWriter.prototype = {
|
||||||
end: function() {
|
|
||||||
this.finished = true;
|
|
||||||
if (this.events) {
|
|
||||||
this.events.emit('finish');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
write: function(str) {
|
write: function(str) {
|
||||||
this.str += str;
|
this.str += str;
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
25
runtime/html/Template.js
Normal file
25
runtime/html/Template.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
'use strict';
|
||||||
|
var AsyncStream = require('./AsyncStream');
|
||||||
|
var makeRenderable = require('../renderable');
|
||||||
|
|
||||||
|
function Template(path, renderFunc, options) {
|
||||||
|
this.path = path;
|
||||||
|
this._ = renderFunc;
|
||||||
|
this.$__shouldBuffer = !options || options.shouldBuffer !== false;
|
||||||
|
this.meta = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createOut(globalData, parent, state, buffer) {
|
||||||
|
return new AsyncStream(globalData, parent, state, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
Template.prototype = {
|
||||||
|
createOut: createOut,
|
||||||
|
stream: function() {
|
||||||
|
throw new Error('You must require("marko/stream")');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
makeRenderable(Template.prototype);
|
||||||
|
|
||||||
|
module.exports = Template;
|
||||||
52
runtime/html/escape.js
Normal file
52
runtime/html/escape.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
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 escapeString(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 escapeString(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 escapeString(value.toString(), regexpTest, regexpReplace);
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeXml(value) {
|
||||||
|
return escapeXmlHelper(value, elTest, elTestReplace);
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeXmlAttr(value) {
|
||||||
|
return escapeXmlHelper(value, attrTest, attrReplace);
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.escapeString = escapeString;
|
||||||
|
exports.escapeXml = escapeXml;
|
||||||
|
exports.escapeXmlAttr = escapeXmlAttr;
|
||||||
29
runtime/html/helper-attr.js
Normal file
29
runtime/html/helper-attr.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
var warp10 = require('warp10');
|
||||||
|
|
||||||
|
var escape = require('./escape');
|
||||||
|
var escapeString = escape.escapeString;
|
||||||
|
var escapeXmlAttr = escape.escapeXmlAttr;
|
||||||
|
|
||||||
|
var stringifiedAttrTest = /[&\'\n]/;
|
||||||
|
var stringifiedAttrReplace = /[&\'\n]/g;
|
||||||
|
|
||||||
|
function attr(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 if (typeof value === 'object') {
|
||||||
|
if (name.substring(0, 6) === 'data-_') {
|
||||||
|
value = warp10.stringify(value);
|
||||||
|
} else {
|
||||||
|
value = JSON.stringify(value);
|
||||||
|
}
|
||||||
|
return ' ' + name + "='" + escapeString(value, stringifiedAttrTest, stringifiedAttrReplace) + "'";
|
||||||
|
} else {
|
||||||
|
return ' ' + name + '=' + value; // number (doesn't need quotes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = attr;
|
||||||
16
runtime/html/helper-attrs.js
Normal file
16
runtime/html/helper-attrs.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
var attrHelper = require('./helper-attr');
|
||||||
|
|
||||||
|
function attrs(arg) {
|
||||||
|
if (typeof arg === 'object') {
|
||||||
|
var out = '';
|
||||||
|
for (var attrName in arg) {
|
||||||
|
out += attrHelper(attrName, arg[attrName]);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
} else if (typeof arg === 'string') {
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = attrs;
|
||||||
5
runtime/html/helper-createInlineTemplate.js
Normal file
5
runtime/html/helper-createInlineTemplate.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
var Template = require('./Template');
|
||||||
|
|
||||||
|
module.exports = function(path, renderFunc) {
|
||||||
|
return new Template(path, renderFunc);
|
||||||
|
};
|
||||||
@ -1,82 +1,22 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
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 elTest = /[&<]/;
|
var escape = require('./escape');
|
||||||
var elTestReplace = /[&<]/g;
|
var escapeXml = escape.escapeXml;
|
||||||
var attrTest = /[&<\"\n]/;
|
var escapeXmlAttr = escape.escapeXmlAttr;
|
||||||
var attrReplace = /[&<\"\n]/g;
|
var attrHelper = require('./helper-attr');
|
||||||
var stringifiedAttrTest = /[&\'\n]/;
|
var attrsHelper = require('./helper-attrs');
|
||||||
var stringifiedAttrReplace = /[&\'\n]/g;
|
|
||||||
|
|
||||||
var classList;
|
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.substring(0, 6) === '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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -113,24 +53,13 @@ exports.xs = function escapeScriptHelper(val) {
|
|||||||
* Internal method to render a single HTML attribute
|
* Internal method to render a single HTML attribute
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
exports.a = attr;
|
exports.a = attrHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal method to render multiple HTML attributes based on the properties of an object
|
* Internal method to render multiple HTML attributes based on the properties of an object
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
exports.as = function(arg) {
|
exports.as = attrsHelper;
|
||||||
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
|
* Internal helper method to handle the "style" attribute. The value can either
|
||||||
@ -145,7 +74,7 @@ exports.sa = function(style) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof style === 'string') {
|
if (typeof style === 'string') {
|
||||||
return attr(STYLE_ATTR, style, false);
|
return attrHelper(STYLE_ATTR, style, false);
|
||||||
} else if (typeof style === 'object') {
|
} else if (typeof style === 'object') {
|
||||||
var parts = [];
|
var parts = [];
|
||||||
for (var name in style) {
|
for (var name in style) {
|
||||||
@ -156,7 +85,7 @@ exports.sa = function(style) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return parts ? attr(STYLE_ATTR, parts.join(';'), false) : '';
|
return parts ? attrHelper(STYLE_ATTR, parts.join(';'), false) : '';
|
||||||
} else {
|
} else {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
@ -176,9 +105,9 @@ exports.ca = function(classNames) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof classNames === 'string') {
|
if (typeof classNames === 'string') {
|
||||||
return attr(CLASS_ATTR, classNames, false);
|
return attrHelper(CLASS_ATTR, classNames, false);
|
||||||
} else {
|
} else {
|
||||||
return attr(CLASS_ATTR, classList(classNames), false);
|
return attrHelper(CLASS_ATTR, classList(classNames), false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -186,6 +115,4 @@ exports.ca = function(classNames) {
|
|||||||
|
|
||||||
var commonHelpers = require('../helpers');
|
var commonHelpers = require('../helpers');
|
||||||
classList = commonHelpers.cl;
|
classList = commonHelpers.cl;
|
||||||
extend(exports, commonHelpers);
|
extend(exports, commonHelpers);
|
||||||
|
|
||||||
exports.inline = require('./')._inline;
|
|
||||||
@ -1,6 +1,8 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
require('../env-init');
|
||||||
|
|
||||||
var AsyncStream = require('./AsyncStream');
|
var AsyncStream = require('./AsyncStream');
|
||||||
var makeRenderable = require('../renderable');
|
var Template = require('./Template');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method is for internal usage only. This method
|
* Method is for internal usage only. This method
|
||||||
@ -12,38 +14,17 @@ exports.t = function createTemplate(path) {
|
|||||||
return new Template(path);
|
return new Template(path);
|
||||||
};
|
};
|
||||||
|
|
||||||
function Template(path, func, options) {
|
|
||||||
this.path = path;
|
|
||||||
this._ = func;
|
|
||||||
this._shouldBuffer = !options || options.shouldBuffer !== false;
|
|
||||||
this.meta = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createOut(globalData, parent, state, buffer) {
|
function createOut(globalData, parent, state, buffer) {
|
||||||
return new AsyncStream(globalData, parent, state, buffer);
|
return new AsyncStream(globalData, parent, state, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
Template.prototype = {
|
|
||||||
createOut: createOut,
|
|
||||||
stream: function() {
|
|
||||||
throw new Error('You must require("marko/stream")');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
makeRenderable(Template.prototype);
|
|
||||||
|
|
||||||
exports.createWriter = function(writer) {
|
exports.createWriter = function(writer) {
|
||||||
return new AsyncStream(null, writer);
|
return new AsyncStream(null, writer);
|
||||||
};
|
};
|
||||||
|
|
||||||
exports._inline = function(filename, renderFunc) {
|
|
||||||
return new Template(filename, renderFunc);
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.Template = Template;
|
exports.Template = Template;
|
||||||
exports.createOut = createOut;
|
exports.$__createOut = createOut;
|
||||||
exports.AsyncStream = AsyncStream;
|
exports.AsyncStream = AsyncStream;
|
||||||
exports.enableAsyncStackTrace = AsyncStream.enableAsyncStackTrace;
|
exports.enableAsyncStackTrace = AsyncStream.enableAsyncStackTrace;
|
||||||
exports.helpers = require('./helpers');
|
|
||||||
|
|
||||||
require('../').$__setRuntime(exports);
|
require('../createOut').$__setCreateOut(createOut);
|
||||||
@ -1,25 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
var documentProvider = require('./document-provider');
|
require('./env-init'); // no-op in the browser, but enables extra features on the server
|
||||||
|
|
||||||
var runtime;
|
exports.createOut = require('./createOut');
|
||||||
|
|
||||||
function setRuntime(_runtime) {
|
|
||||||
runtime = _runtime;
|
|
||||||
}
|
|
||||||
exports.$__setRuntime = setRuntime;
|
|
||||||
|
|
||||||
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 = require('./loader');
|
exports.load = require('./loader');
|
||||||
exports.events = require('./events');
|
exports.events = require('./events');
|
||||||
@ -1,4 +1,4 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
module.exports = function load(templatePath) {
|
module.exports = function load(templatePath) {
|
||||||
throw Error('Template not found: ' + templatePath);
|
throw Error('Not found: ' + templatePath);
|
||||||
};
|
};
|
||||||
@ -27,34 +27,6 @@ var markoCompiler = require('../../compiler');
|
|||||||
var cwd = process.cwd();
|
var cwd = process.cwd();
|
||||||
var fsOptions = {encoding: 'utf8'};
|
var fsOptions = {encoding: 'utf8'};
|
||||||
|
|
||||||
if (process.env.hasOwnProperty('MARKO_HOT_RELOAD')) {
|
|
||||||
require('../../hot-reload').enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If process was launched with browser refresh then automatically
|
|
||||||
// enable browser-refresh
|
|
||||||
require('../../browser-refresh').enable();
|
|
||||||
|
|
||||||
function fixFlush() {
|
|
||||||
try {
|
|
||||||
var OutgoingMessage = require('http').OutgoingMessage;
|
|
||||||
if (OutgoingMessage.prototype.flush && OutgoingMessage.prototype.flush.toString().indexOf('deprecated') !== -1) {
|
|
||||||
// Yes, we are monkey-patching http. This method should never have been added and it was introduced on
|
|
||||||
// the iojs fork. It was quickly deprecated and I'm 99% sure no one is actually using it.
|
|
||||||
// See:
|
|
||||||
// - https://github.com/marko-js/async-writer/issues/3
|
|
||||||
// - https://github.com/nodejs/node/issues/2920
|
|
||||||
//
|
|
||||||
// This method causes problems since marko looks for the flush method and calls it found.
|
|
||||||
// The `res.flush()` method is introduced by the [compression](https://www.npmjs.com/package/compression)
|
|
||||||
// middleware, but, otherwise, it should typically not exist.
|
|
||||||
delete require('http').OutgoingMessage.prototype.flush;
|
|
||||||
}
|
|
||||||
} catch(e) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fixFlush();
|
|
||||||
|
|
||||||
function loadSource(templatePath, compiledSrc) {
|
function loadSource(templatePath, compiledSrc) {
|
||||||
var templateModulePath = templatePath + '.js';
|
var templateModulePath = templatePath + '.js';
|
||||||
|
|
||||||
@ -183,7 +155,4 @@ function doLoad(templatePath, templateSrc, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return template;
|
return template;
|
||||||
}
|
}
|
||||||
|
|
||||||
require('../stream');
|
|
||||||
require('../dependencies');
|
|
||||||
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"browser": {
|
"browser": {
|
||||||
"./loader/index.js": "./loader/index-browser.js"
|
"./loader/index.js": "./loader/index-browser.js",
|
||||||
|
"./env-init.js": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,9 +1,9 @@
|
|||||||
var marko = require('./index');
|
var defaultCreateOut = require('./createOut');
|
||||||
var extend = require('raptor-util/extend');
|
var extend = require('raptor-util/extend');
|
||||||
|
|
||||||
module.exports = function(target, renderer) {
|
module.exports = function(target, renderer) {
|
||||||
var renderFunc = renderer && (renderer.renderer || renderer.render || renderer);
|
var renderFunc = renderer && (renderer.renderer || renderer.render || renderer);
|
||||||
var createOut = target.createOut || renderer.createOut || marko.createOut;
|
var createOut = target.createOut || renderer.createOut || defaultCreateOut;
|
||||||
|
|
||||||
return extend(target, {
|
return extend(target, {
|
||||||
createOut: createOut,
|
createOut: createOut,
|
||||||
@ -35,7 +35,7 @@ module.exports = function(target, renderer) {
|
|||||||
out.sync();
|
out.sync();
|
||||||
|
|
||||||
render(localData, out);
|
render(localData, out);
|
||||||
return out.getResult();
|
return out.$__getResult();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -61,7 +61,7 @@ module.exports = function(target, renderer) {
|
|||||||
var finalData;
|
var finalData;
|
||||||
var globalData;
|
var globalData;
|
||||||
var render = renderFunc || this._;
|
var render = renderFunc || this._;
|
||||||
var shouldBuffer = this._shouldBuffer;
|
var shouldBuffer = this.$__shouldBuffer;
|
||||||
var shouldEnd = true;
|
var shouldEnd = true;
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
@ -73,7 +73,7 @@ module.exports = function(target, renderer) {
|
|||||||
finalData = {};
|
finalData = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (out && out.isOut){
|
if (out && out.$__isOut) {
|
||||||
finalOut = out;
|
finalOut = out;
|
||||||
shouldEnd = false;
|
shouldEnd = false;
|
||||||
extend(out.global, globalData);
|
extend(out.global, globalData);
|
||||||
@ -92,12 +92,14 @@ module.exports = function(target, renderer) {
|
|||||||
if (callback) {
|
if (callback) {
|
||||||
finalOut
|
finalOut
|
||||||
.on('finish', function() {
|
.on('finish', function() {
|
||||||
callback(null, finalOut.getResult());
|
callback(null, finalOut.$__getResult());
|
||||||
})
|
})
|
||||||
.once('error', callback);
|
.once('error', callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
finalOut.global.template = finalOut.global.template || this;
|
globalData = finalOut.global;
|
||||||
|
|
||||||
|
globalData.template = globalData.template || this;
|
||||||
|
|
||||||
render(finalData, finalOut);
|
render(finalData, finalOut);
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@ line to your app:
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
var stream = require('stream');
|
var stream = require('stream');
|
||||||
|
var Template = require('./html/Template');
|
||||||
var AsyncStream = require('./html/AsyncStream');
|
var AsyncStream = require('./html/AsyncStream');
|
||||||
|
|
||||||
function Readable(template, data, options) {
|
function Readable(template, data, options) {
|
||||||
@ -47,6 +48,6 @@ Readable.prototype = {
|
|||||||
|
|
||||||
require('raptor-util/inherit')(Readable, stream.Readable);
|
require('raptor-util/inherit')(Readable, stream.Readable);
|
||||||
|
|
||||||
require('./html').Template.prototype.stream = function(data) {
|
Template.prototype.stream = function(data) {
|
||||||
return new Readable(this, data, this._options);
|
return new Readable(this, data, this._options);
|
||||||
};
|
};
|
||||||
@ -1,15 +1,19 @@
|
|||||||
var EventEmitter = require('events-light');
|
var EventEmitter = require('events-light');
|
||||||
var HTMLElement = require('./HTMLElement');
|
var vdom = require('./vdom');
|
||||||
var DocumentFragment = require('./DocumentFragment');
|
var HTMLElement = vdom.$__HTMLElement;
|
||||||
var Comment = require('./Comment');
|
var DocumentFragment = vdom.$__DocumentFragment;
|
||||||
var Text = require('./Text');
|
var Comment = vdom.$__Comment;
|
||||||
var virtualizeHTML = require('./virtualizeHTML');
|
var Text = vdom.$__Text;
|
||||||
var documentProvider = require('../document-provider');
|
var virtualizeHTML = vdom.$__virtualizeHTML;
|
||||||
var RenderResult = require('../RenderResult');
|
var RenderResult = require('../RenderResult');
|
||||||
|
var defaultDocument = vdom.$__defaultDocument;
|
||||||
|
|
||||||
var FLAG_FINISHED = 1;
|
var FLAG_FINISHED = 1;
|
||||||
var FLAG_LAST_FIRED = 2;
|
var FLAG_LAST_FIRED = 2;
|
||||||
|
|
||||||
|
var EVENT_UPDATE = 'update';
|
||||||
|
var EVENT_FINISH = 'finish';
|
||||||
|
|
||||||
function State(tree) {
|
function State(tree) {
|
||||||
this.$__remaining = 1;
|
this.$__remaining = 1;
|
||||||
this.$__events = new EventEmitter();
|
this.$__events = new EventEmitter();
|
||||||
@ -39,7 +43,8 @@ function AsyncVDOMBuilder(globalData, parentNode, state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var proto = AsyncVDOMBuilder.prototype = {
|
var proto = AsyncVDOMBuilder.prototype = {
|
||||||
isOut: true,
|
$__isOut: true,
|
||||||
|
$__document: defaultDocument,
|
||||||
|
|
||||||
element: function(name, attrs, childCount) {
|
element: function(name, attrs, childCount) {
|
||||||
var element = new HTMLElement(name, attrs, childCount);
|
var element = new HTMLElement(name, attrs, childCount);
|
||||||
@ -87,7 +92,7 @@ var proto = AsyncVDOMBuilder.prototype = {
|
|||||||
var parent = this.$__parent;
|
var parent = this.$__parent;
|
||||||
if (parent) {
|
if (parent) {
|
||||||
var lastChild = parent.lastChild;
|
var lastChild = parent.lastChild;
|
||||||
if (lastChild && lastChild.nodeType === 3) {
|
if (lastChild && lastChild.$__Text) {
|
||||||
lastChild.nodeValue += text;
|
lastChild.nodeValue += text;
|
||||||
} else {
|
} else {
|
||||||
parent.$__appendChild(new Text(text));
|
parent.$__appendChild(new Text(text));
|
||||||
@ -102,7 +107,7 @@ var proto = AsyncVDOMBuilder.prototype = {
|
|||||||
|
|
||||||
html: function(html) {
|
html: function(html) {
|
||||||
if (html != null) {
|
if (html != null) {
|
||||||
var vdomNode = virtualizeHTML(html, documentProvider.$__document);
|
var vdomNode = virtualizeHTML(html, this.$__document);
|
||||||
this.node(vdomNode);
|
this.node(vdomNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +146,7 @@ var proto = AsyncVDOMBuilder.prototype = {
|
|||||||
|
|
||||||
if (!remaining) {
|
if (!remaining) {
|
||||||
state.$__flags |= FLAG_FINISHED;
|
state.$__flags |= FLAG_FINISHED;
|
||||||
state.$__events.emit('finish', this);
|
state.$__events.emit(EVENT_FINISH, this.$__getResult());
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@ -176,23 +181,26 @@ var proto = AsyncVDOMBuilder.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
flush: function() {
|
flush: function() {
|
||||||
var state = this.$__state;
|
var events = this.$__state.$__events;
|
||||||
state.$__events.emit('update', this);
|
|
||||||
|
if (events.listenerCount(EVENT_UPDATE)) {
|
||||||
|
events.emit(EVENT_UPDATE, new RenderResult(this));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getOutput: function() {
|
$__getOutput: function() {
|
||||||
return this.$__state.$__tree;
|
return this.$__state.$__tree;
|
||||||
},
|
},
|
||||||
|
|
||||||
getResult: function() {
|
$__getResult: function() {
|
||||||
return this.$__result || (this.$__result = new RenderResult(this));
|
return this.$__result || (this.$__result = new RenderResult(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
on: function(event, callback) {
|
on: function(event, callback) {
|
||||||
var state = this.$__state;
|
var state = this.$__state;
|
||||||
|
|
||||||
if (event === 'finish' && (state.$__flags & FLAG_FINISHED)) {
|
if (event === EVENT_FINISH && (state.$__flags & FLAG_FINISHED)) {
|
||||||
callback(this);
|
callback(this.$__getResult());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,8 +211,8 @@ var proto = AsyncVDOMBuilder.prototype = {
|
|||||||
once: function(event, callback) {
|
once: function(event, callback) {
|
||||||
var state = this.$__state;
|
var state = this.$__state;
|
||||||
|
|
||||||
if (event === 'finish' && (state.$__flags & FLAG_FINISHED)) {
|
if (event === EVENT_FINISH && (state.$__flags & FLAG_FINISHED)) {
|
||||||
callback(this);
|
callback(this.$__getResult());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,45 +275,31 @@ var proto = AsyncVDOMBuilder.prototype = {
|
|||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
getNode: function(doc) {
|
$__getNode: function(doc) {
|
||||||
var node = this.$__node;
|
var node = this.$__node;
|
||||||
if (!node) {
|
if (!node) {
|
||||||
var vdomTree = this.getOutput();
|
var vdomTree = this.$__getOutput();
|
||||||
|
|
||||||
if (!doc) {
|
if (!doc) {
|
||||||
doc = documentProvider.$__document;
|
doc = this.$__document;
|
||||||
}
|
}
|
||||||
|
|
||||||
node = vdomTree.actualize(doc);
|
node = this.$__node = vdomTree.actualize(doc);
|
||||||
|
|
||||||
if (node.nodeType === 11 /* DocumentFragment */) {
|
|
||||||
var firstChild = node.firstChild;
|
|
||||||
if (firstChild) {
|
|
||||||
var nextSibling = firstChild.nextSibling;
|
|
||||||
if (!nextSibling) {
|
|
||||||
// If the DocumentFragment only has one child
|
|
||||||
// then just return that first child as the node
|
|
||||||
node = firstChild;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$__node = node;
|
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
},
|
},
|
||||||
|
|
||||||
toString: function() {
|
toString: function() {
|
||||||
return this.getNode().outerHTML;
|
return this.$__getNode().outerHTML;
|
||||||
},
|
},
|
||||||
|
|
||||||
then: function(fn, fnErr) {
|
then: function(fn, fnErr) {
|
||||||
var out = this;
|
var out = this;
|
||||||
var promise = new Promise(function(resolve, reject) {
|
var promise = new Promise(function(resolve, reject) {
|
||||||
out.on('error', reject);
|
out.on('error', reject)
|
||||||
out.on('finish', function() {
|
.on(EVENT_FINISH, function(result) {
|
||||||
resolve(out.getResult());
|
resolve(result);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.resolve(promise).then(fn, fnErr);
|
return Promise.resolve(promise).then(fn, fnErr);
|
||||||
|
|||||||
@ -2,15 +2,15 @@ var Node = require('./Node');
|
|||||||
var inherit = require('raptor-util/inherit');
|
var inherit = require('raptor-util/inherit');
|
||||||
|
|
||||||
function Comment(value) {
|
function Comment(value) {
|
||||||
Node.call(this, -1 /* no children */);
|
this.$__Node(-1 /* no children */);
|
||||||
this.nodeValue = value;
|
this.nodeValue = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Comment.prototype = {
|
Comment.prototype = {
|
||||||
nodeType: 8,
|
nodeType: 8,
|
||||||
|
|
||||||
actualize: function(document) {
|
actualize: function(doc) {
|
||||||
return document.createComment(this.nodeValue);
|
return doc.createComment(this.nodeValue);
|
||||||
},
|
},
|
||||||
|
|
||||||
$__cloneNode: function() {
|
$__cloneNode: function() {
|
||||||
|
|||||||
@ -9,26 +9,28 @@ function DocumentFragmentClone(other) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function DocumentFragment(documentFragment) {
|
function DocumentFragment(documentFragment) {
|
||||||
Node.call(this, null /* childCount */);
|
this.$__Node(null /* childCount */);
|
||||||
this.namespaceURI = undefined;
|
this.namespaceURI = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
DocumentFragment.prototype = {
|
DocumentFragment.prototype = {
|
||||||
nodeType: 11,
|
nodeType: 11,
|
||||||
|
|
||||||
|
$__DocumentFragment: true,
|
||||||
|
|
||||||
$__nsAware: true,
|
$__nsAware: true,
|
||||||
|
|
||||||
$__cloneNode: function() {
|
$__cloneNode: function() {
|
||||||
return new DocumentFragmentClone(this);
|
return new DocumentFragmentClone(this);
|
||||||
},
|
},
|
||||||
|
|
||||||
actualize: function(document) {
|
actualize: function(doc) {
|
||||||
var docFragment = document.createDocumentFragment();
|
var docFragment = doc.createDocumentFragment();
|
||||||
|
|
||||||
var curChild = this.firstChild;
|
var curChild = this.firstChild;
|
||||||
|
|
||||||
while(curChild) {
|
while(curChild) {
|
||||||
docFragment.appendChild(curChild.actualize(document));
|
docFragment.appendChild(curChild.actualize(doc));
|
||||||
curChild = curChild.nextSibling;
|
curChild = curChild.nextSibling;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,10 @@
|
|||||||
|
var Node = require('./Node');
|
||||||
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 defineProperty = Object.defineProperty;
|
||||||
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 NS_XLINK = 'http://www.w3.org/1999/xlink';
|
||||||
|
var ATTR_XLINK_HREF = 'xlink:href';
|
||||||
var ATTR_HREF = 'href';
|
var ATTR_HREF = 'href';
|
||||||
var EMPTY_OBJECT = Object.freeze({});
|
var EMPTY_OBJECT = Object.freeze({});
|
||||||
var ATTR_MARKO_CONST = 'data-marko-const';
|
var ATTR_MARKO_CONST = 'data-marko-const';
|
||||||
@ -59,7 +57,7 @@ function HTMLElement(tagName, attrs, childCount, constId) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node.call(this, childCount);
|
this.$__Node(childCount);
|
||||||
|
|
||||||
if (constId) {
|
if (constId) {
|
||||||
if (!attrs) {
|
if (!attrs) {
|
||||||
@ -68,7 +66,7 @@ function HTMLElement(tagName, attrs, childCount, constId) {
|
|||||||
attrs[ATTR_MARKO_CONST] = constId;
|
attrs[ATTR_MARKO_CONST] = constId;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.attributes = attrs || EMPTY_OBJECT;
|
this.$__attributes = attrs || EMPTY_OBJECT;
|
||||||
this.$__isTextArea = isTextArea;
|
this.$__isTextArea = isTextArea;
|
||||||
this.namespaceURI = namespaceURI;
|
this.namespaceURI = namespaceURI;
|
||||||
this.nodeName = tagName;
|
this.nodeName = tagName;
|
||||||
@ -77,116 +75,12 @@ function HTMLElement(tagName, attrs, childCount, constId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HTMLElement.prototype = {
|
HTMLElement.prototype = {
|
||||||
|
$__HTMLElement: true,
|
||||||
|
|
||||||
nodeType: 1,
|
nodeType: 1,
|
||||||
|
|
||||||
$__nsAware: true,
|
$__nsAware: true,
|
||||||
|
|
||||||
assignAttributes: function(targetNode) {
|
|
||||||
var attrs = this.attributes;
|
|
||||||
var attrName;
|
|
||||||
var i;
|
|
||||||
|
|
||||||
// We use expando properties to associate the previous HTML
|
|
||||||
// attributes provided as part of the VDOM node with the
|
|
||||||
// real HTMLElement DOM node. When diffing attributes,
|
|
||||||
// we only use our internal representation of the attributes.
|
|
||||||
// When diffing for the first time it's possible that the
|
|
||||||
// real HTMLElement node will not have the expando property
|
|
||||||
// so we build the attribute map from the expando property
|
|
||||||
|
|
||||||
var oldAttrs = targetNode._vattrs;
|
|
||||||
if (oldAttrs) {
|
|
||||||
if (oldAttrs === attrs) {
|
|
||||||
// For constant attributes the same object will be provided
|
|
||||||
// every render and we can use that to our advantage to
|
|
||||||
// not waste time diffing a constant, immutable attribute
|
|
||||||
// map.
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
oldAttrs = removePreservedAttributes(extend({}, oldAttrs));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// We need to build the attribute map from the real attributes
|
|
||||||
oldAttrs = {};
|
|
||||||
|
|
||||||
var oldAttributesList = targetNode.attributes;
|
|
||||||
for (i = oldAttributesList.length - 1; i >= 0; --i) {
|
|
||||||
var attr = oldAttributesList[i];
|
|
||||||
|
|
||||||
if (attr.specified !== false) {
|
|
||||||
attrName = attr.name;
|
|
||||||
var attrNamespaceURI = attr.namespaceURI;
|
|
||||||
if (attrNamespaceURI === NS_XLINK) {
|
|
||||||
oldAttrs['xlink:href'] = attr.value;
|
|
||||||
} else {
|
|
||||||
oldAttrs[attrName] = attr.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We don't want preserved attributes to show up in either the old
|
|
||||||
// or new attribute map.
|
|
||||||
removePreservedAttributes(oldAttrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
// In some cases we only want to set an attribute value for the first
|
|
||||||
// render or we don't want certain attributes to be touched. To support
|
|
||||||
// that use case we delete out all of the preserved attributes
|
|
||||||
// so it's as if they never existed.
|
|
||||||
var preservedAttrs = attrs['data-preserve-attrs'];
|
|
||||||
if (preservedAttrs) {
|
|
||||||
attrs = removePreservedAttributes(extend({}, attrs));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loop over all of the attributes in the attribute map and compare
|
|
||||||
// them to the value in the old map. However, if the value is
|
|
||||||
// null/undefined/false then we want to remove the attribute
|
|
||||||
for (attrName in attrs) {
|
|
||||||
var attrValue = attrs[attrName];
|
|
||||||
|
|
||||||
if (attrName === 'xlink:href') {
|
|
||||||
if (attrValue == null || attrValue === false) {
|
|
||||||
targetNode.removeAttributeNS(NS_XLINK, ATTR_HREF);
|
|
||||||
} else if (oldAttrs[attrName] !== attrValue) {
|
|
||||||
targetNode.setAttributeNS(NS_XLINK, ATTR_HREF, attrValue);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (attrValue == null || attrValue === false) {
|
|
||||||
targetNode.removeAttribute(attrName);
|
|
||||||
} else if (oldAttrs[attrName] !== attrValue) {
|
|
||||||
|
|
||||||
if (specialAttrRegexp.test(attrName)) {
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there are any old attributes that are not in the new set of attributes
|
|
||||||
// then we need to remove those attributes from the target node
|
|
||||||
for (attrName in oldAttrs) {
|
|
||||||
if (attrs.hasOwnProperty(attrName) === false) {
|
|
||||||
if (attrName === 'xlink:href') {
|
|
||||||
targetNode.removeAttributeNS(NS_XLINK, ATTR_HREF);
|
|
||||||
} else {
|
|
||||||
targetNode.removeAttribute(attrName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
targetNode._vattrs = attrs;
|
|
||||||
},
|
|
||||||
|
|
||||||
$__cloneNode: function() {
|
$__cloneNode: function() {
|
||||||
return new HTMLElementClone(this);
|
return new HTMLElementClone(this);
|
||||||
},
|
},
|
||||||
@ -208,37 +102,7 @@ HTMLElement.prototype = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Shorthand method for creating and appending a Text node with a given value
|
|
||||||
* @param {String} value The text value for the new Text node
|
|
||||||
*/
|
|
||||||
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();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shorthand method for creating and appending a Comment node with a given value
|
|
||||||
* @param {String} value The value for the new Comment node
|
|
||||||
*/
|
|
||||||
c: function(value) {
|
|
||||||
this.$__appendChild(new Comment(value));
|
|
||||||
return this.$__finishChild();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shorthand method for creating and appending a static node. The provided node is automatically cloned
|
* Shorthand method for creating and appending a static node. The provided node is automatically cloned
|
||||||
@ -251,18 +115,18 @@ HTMLElement.prototype = {
|
|||||||
return this.$__finishChild();
|
return this.$__finishChild();
|
||||||
},
|
},
|
||||||
|
|
||||||
actualize: function(document) {
|
actualize: function(doc) {
|
||||||
var el;
|
var el;
|
||||||
var namespaceURI = this.namespaceURI;
|
var namespaceURI = this.namespaceURI;
|
||||||
var tagName = this.nodeName;
|
var tagName = this.nodeName;
|
||||||
|
|
||||||
if (namespaceURI) {
|
if (namespaceURI) {
|
||||||
el = document.createElementNS(namespaceURI, tagName);
|
el = doc.createElementNS(namespaceURI, tagName);
|
||||||
} else {
|
} else {
|
||||||
el = document.createElement(tagName);
|
el = doc.createElement(tagName);
|
||||||
}
|
}
|
||||||
|
|
||||||
var attributes = this.attributes;
|
var attributes = this.$__attributes;
|
||||||
for (var attrName in attributes) {
|
for (var attrName in attributes) {
|
||||||
var attrValue = attributes[attrName];
|
var attrValue = attributes[attrName];
|
||||||
|
|
||||||
@ -279,7 +143,7 @@ HTMLElement.prototype = {
|
|||||||
attrValue = convertAttrValue(type, attrValue);
|
attrValue = convertAttrValue(type, attrValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attrName === 'xlink:href') {
|
if (attrName === ATTR_XLINK_HREF) {
|
||||||
el.setAttributeNS(NS_XLINK, ATTR_HREF, attrValue);
|
el.setAttributeNS(NS_XLINK, ATTR_HREF, attrValue);
|
||||||
} else {
|
} else {
|
||||||
el.setAttribute(attrName, attrValue);
|
el.setAttribute(attrName, attrValue);
|
||||||
@ -288,12 +152,12 @@ HTMLElement.prototype = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.$__isTextArea) {
|
if (this.$__isTextArea) {
|
||||||
el.value = this.value;
|
el.value = this.$__value;
|
||||||
} else {
|
} else {
|
||||||
var curChild = this.firstChild;
|
var curChild = this.firstChild;
|
||||||
|
|
||||||
while(curChild) {
|
while(curChild) {
|
||||||
el.appendChild(curChild.actualize(document));
|
el.appendChild(curChild.actualize(doc));
|
||||||
curChild = curChild.nextSibling;
|
curChild = curChild.nextSibling;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -307,25 +171,23 @@ HTMLElement.prototype = {
|
|||||||
// We don't care about the namespaces since the there
|
// We don't care about the namespaces since the there
|
||||||
// is no chance that attributes with the same name will have
|
// is no chance that attributes with the same name will have
|
||||||
// different namespaces
|
// different namespaces
|
||||||
return this.attributes[name] !== undefined;
|
return this.$__attributes[name] !== undefined;
|
||||||
},
|
},
|
||||||
|
|
||||||
getAttribute: function(name) {
|
getAttribute: function(name) {
|
||||||
return this.attributes[name];
|
return this.$__attributes[name];
|
||||||
},
|
},
|
||||||
|
|
||||||
isSameNode: function(otherNode) {
|
isSameNode: function(otherNode) {
|
||||||
if (otherNode.nodeType !== 1) {
|
if (otherNode.nodeType == 1) {
|
||||||
return false;
|
var constId = this.$__constId;
|
||||||
|
if (constId) {
|
||||||
|
var otherSameId = otherNode.$__Node ? otherNode.$__constId : otherNode.getAttribute(ATTR_MARKO_CONST);
|
||||||
|
return constId === otherSameId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var constId = this.$__constId;
|
return false;
|
||||||
if (constId) {
|
|
||||||
var otherSameId = otherNode.actualize ? otherNode.$__constId : otherNode.getAttribute(ATTR_MARKO_CONST);
|
|
||||||
return constId === otherSameId;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -333,39 +195,130 @@ inherit(HTMLElement, Node);
|
|||||||
|
|
||||||
var proto = HTMLElementClone.prototype = HTMLElement.prototype;
|
var proto = HTMLElementClone.prototype = HTMLElement.prototype;
|
||||||
|
|
||||||
Object.defineProperty(proto, 'checked', {
|
['checked', 'selected', 'disabled'].forEach(function(name) {
|
||||||
|
defineProperty(proto, name, {
|
||||||
|
get: function () {
|
||||||
|
return this.$__attributes[name] !== undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
defineProperty(proto, 'id', {
|
||||||
get: function () {
|
get: function () {
|
||||||
return this.attributes.checked !== undefined;
|
return this.$__attributes.id;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.defineProperty(proto, 'selected', {
|
defineProperty(proto, 'value', {
|
||||||
get: function () {
|
get: function () {
|
||||||
return this.attributes.selected !== undefined;
|
return this.$__value || this.$__attributes.value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.defineProperty(proto, 'id', {
|
HTMLElement.$__morphAttrs = function(fromEl, toEl) {
|
||||||
get: function () {
|
var attrs = toEl.$__attributes;
|
||||||
return this.attributes.id;
|
var attrName;
|
||||||
|
var i;
|
||||||
|
|
||||||
|
// We use expando properties to associate the previous HTML
|
||||||
|
// attributes provided as part of the VDOM node with the
|
||||||
|
// real HTMLElement DOM node. When diffing attributes,
|
||||||
|
// we only use our internal representation of the attributes.
|
||||||
|
// When diffing for the first time it's possible that the
|
||||||
|
// real HTMLElement node will not have the expando property
|
||||||
|
// so we build the attribute map from the expando property
|
||||||
|
|
||||||
|
var oldAttrs = fromEl._vattrs;
|
||||||
|
if (oldAttrs) {
|
||||||
|
if (oldAttrs === attrs) {
|
||||||
|
// For constant attributes the same object will be provided
|
||||||
|
// every render and we can use that to our advantage to
|
||||||
|
// not waste time diffing a constant, immutable attribute
|
||||||
|
// map.
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
oldAttrs = removePreservedAttributes(extend({}, oldAttrs));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// We need to build the attribute map from the real attributes
|
||||||
|
oldAttrs = {};
|
||||||
|
|
||||||
|
var oldAttributesList = fromEl.attributes;
|
||||||
|
for (i = oldAttributesList.length - 1; i >= 0; --i) {
|
||||||
|
var attr = oldAttributesList[i];
|
||||||
|
|
||||||
|
if (attr.specified !== false) {
|
||||||
|
attrName = attr.name;
|
||||||
|
var attrNamespaceURI = attr.namespaceURI;
|
||||||
|
if (attrNamespaceURI === NS_XLINK) {
|
||||||
|
oldAttrs[ATTR_XLINK_HREF] = attr.value;
|
||||||
|
} else {
|
||||||
|
oldAttrs[attrName] = attr.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't want preserved attributes to show up in either the old
|
||||||
|
// or new attribute map.
|
||||||
|
removePreservedAttributes(oldAttrs);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
Object.defineProperty(proto, 'value', {
|
// In some cases we only want to set an attribute value for the first
|
||||||
get: function () {
|
// render or we don't want certain attributes to be touched. To support
|
||||||
return this.$__value || this.attributes.value;
|
// that use case we delete out all of the preserved attributes
|
||||||
},
|
// so it's as if they never existed.
|
||||||
set: function (value) {
|
var preservedAttrs = attrs['data-preserve-attrs'];
|
||||||
this.$__value = value;
|
if (preservedAttrs) {
|
||||||
|
attrs = removePreservedAttributes(extend({}, attrs));
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
Object.defineProperty(proto, 'disabled', {
|
// Loop over all of the attributes in the attribute map and compare
|
||||||
get: function () {
|
// them to the value in the old map. However, if the value is
|
||||||
return this.attributes.disabled !== undefined;
|
// null/undefined/false then we want to remove the attribute
|
||||||
|
for (attrName in attrs) {
|
||||||
|
var attrValue = attrs[attrName];
|
||||||
|
|
||||||
|
if (attrName === ATTR_XLINK_HREF) {
|
||||||
|
if (attrValue == null || attrValue === false) {
|
||||||
|
fromEl.removeAttributeNS(NS_XLINK, ATTR_HREF);
|
||||||
|
} else if (oldAttrs[attrName] !== attrValue) {
|
||||||
|
fromEl.setAttributeNS(NS_XLINK, ATTR_HREF, attrValue);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (attrValue == null || attrValue === false) {
|
||||||
|
fromEl.removeAttribute(attrName);
|
||||||
|
} else if (oldAttrs[attrName] !== attrValue) {
|
||||||
|
|
||||||
|
if (specialAttrRegexp.test(attrName)) {
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
fromEl.setAttribute(attrName, attrValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = HTMLElement;
|
// If there are any old attributes that are not in the new set of attributes
|
||||||
|
// then we need to remove those attributes from the target node
|
||||||
|
for (attrName in oldAttrs) {
|
||||||
|
if (attrs.hasOwnProperty(attrName) === false) {
|
||||||
|
if (attrName === ATTR_XLINK_HREF) {
|
||||||
|
fromEl.removeAttributeNS(NS_XLINK, ATTR_HREF);
|
||||||
|
} else {
|
||||||
|
fromEl.removeAttribute(attrName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virtualizeHTML = require('./virtualizeHTML');
|
fromEl._vattrs = attrs;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = HTMLElement;
|
||||||
@ -1,7 +1,5 @@
|
|||||||
/* jshint newcap:false */
|
/* jshint newcap:false */
|
||||||
|
|
||||||
var DocumentFragment;
|
|
||||||
|
|
||||||
function assignNamespace(node, namespaceURI) {
|
function assignNamespace(node, namespaceURI) {
|
||||||
node.namespaceURI = namespaceURI;
|
node.namespaceURI = namespaceURI;
|
||||||
|
|
||||||
@ -14,26 +12,27 @@ function assignNamespace(node, namespaceURI) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function Node(finalChildCount) {
|
function Node() {}
|
||||||
this.$__finalChildCount = finalChildCount;
|
|
||||||
this.$__childCount = 0;
|
|
||||||
this.$__firstChild = undefined;
|
|
||||||
this.$__lastChild = undefined;
|
|
||||||
this.$__parentNode = undefined;
|
|
||||||
this.$__nextSibling = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
Node.prototype = {
|
Node.prototype = {
|
||||||
removeChildren: function() {
|
$__Node: function(finalChildCount) {
|
||||||
this.$__firstChild = undefined;
|
this.$__finalChildCount = finalChildCount;
|
||||||
this.$__childCount = 0;
|
this.$__childCount = 0;
|
||||||
|
this.$__firstChild = undefined;
|
||||||
this.$__lastChild = undefined;
|
this.$__lastChild = undefined;
|
||||||
|
this.$__parentNode = undefined;
|
||||||
|
this.$__nextSibling = undefined;
|
||||||
},
|
},
|
||||||
|
// removeChildren: function() {
|
||||||
|
// this.$__firstChild = undefined;
|
||||||
|
// this.$__childCount = 0;
|
||||||
|
// this.$__lastChild = undefined;
|
||||||
|
// },
|
||||||
|
|
||||||
get firstChild() {
|
get firstChild() {
|
||||||
var firstChild = this.$__firstChild;
|
var firstChild = this.$__firstChild;
|
||||||
|
|
||||||
if (firstChild && firstChild.nodeType === 11 /* DocumentFragment */) {
|
if (firstChild && firstChild.$__DocumentFragment) {
|
||||||
var nestedFirstChild = firstChild.firstChild;
|
var nestedFirstChild = firstChild.firstChild;
|
||||||
// The first child is a DocumentFragment node.
|
// The first child is a DocumentFragment node.
|
||||||
// If the DocumentFragment node has a first child then we will return that.
|
// If the DocumentFragment node has a first child then we will return that.
|
||||||
@ -45,27 +44,17 @@ Node.prototype = {
|
|||||||
return firstChild;
|
return firstChild;
|
||||||
},
|
},
|
||||||
|
|
||||||
get lastChild() {
|
|
||||||
var lastChild = this.$__lastChild;
|
|
||||||
|
|
||||||
if (lastChild && lastChild.nodeType === 11 /* DocumentFragment */) {
|
|
||||||
return lastChild.lastChild;
|
|
||||||
}
|
|
||||||
|
|
||||||
return lastChild;
|
|
||||||
},
|
|
||||||
|
|
||||||
get nextSibling() {
|
get nextSibling() {
|
||||||
var nextSibling = this.$__nextSibling;
|
var nextSibling = this.$__nextSibling;
|
||||||
|
|
||||||
if (nextSibling) {
|
if (nextSibling) {
|
||||||
if (nextSibling.nodeType === 11 /* DocumentFragment */) {
|
if (nextSibling.$__DocumentFragment) {
|
||||||
var firstChild = nextSibling.firstChild;
|
var firstChild = nextSibling.firstChild;
|
||||||
return firstChild || nextSibling.nextSibling;
|
return firstChild || nextSibling.nextSibling;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var parentNode = this.$__parentNode;
|
var parentNode = this.$__parentNode;
|
||||||
if (parentNode && parentNode.nodeType === 11) {
|
if (parentNode && parentNode.$__DocumentFragment) {
|
||||||
return parentNode.nextSibling;
|
return parentNode.nextSibling;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,15 +62,11 @@ Node.prototype = {
|
|||||||
return nextSibling;
|
return nextSibling;
|
||||||
},
|
},
|
||||||
|
|
||||||
$__appendDocumentFragment: function() {
|
|
||||||
return this.$__appendChild(new DocumentFragment());
|
|
||||||
},
|
|
||||||
|
|
||||||
$__appendChild: function(child) {
|
$__appendChild: function(child) {
|
||||||
if (this.$__isTextArea) {
|
if (this.$__isTextArea) {
|
||||||
if (child.nodeType === 3) {
|
if (child.$__Text) {
|
||||||
var currentValue = this.value;
|
var childValue = child.nodeValue;
|
||||||
this.value = currentValue ? currentValue + child.nodeValue : child.nodeValue;
|
this.$__value = (this.$__value || '') + childValue;
|
||||||
} else {
|
} else {
|
||||||
throw TypeError();
|
throw TypeError();
|
||||||
}
|
}
|
||||||
@ -135,6 +120,4 @@ Node.prototype = {
|
|||||||
// }
|
// }
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = Node;
|
module.exports = Node;
|
||||||
|
|
||||||
DocumentFragment = require('./DocumentFragment');
|
|
||||||
@ -2,15 +2,17 @@ var Node = require('./Node');
|
|||||||
var inherit = require('raptor-util/inherit');
|
var inherit = require('raptor-util/inherit');
|
||||||
|
|
||||||
function Text(value) {
|
function Text(value) {
|
||||||
Node.call(this, -1 /* no children */);
|
this.$__Node(-1 /* no children */);
|
||||||
this.nodeValue = value;
|
this.nodeValue = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Text.prototype = {
|
Text.prototype = {
|
||||||
|
$__Text: true,
|
||||||
|
|
||||||
nodeType: 3,
|
nodeType: 3,
|
||||||
|
|
||||||
actualize: function(document) {
|
actualize: function(doc) {
|
||||||
return document.createTextNode(this.nodeValue);
|
return doc.createTextNode(this.nodeValue);
|
||||||
},
|
},
|
||||||
|
|
||||||
$__cloneNode: function() {
|
$__cloneNode: function() {
|
||||||
|
|||||||
5
runtime/vdom/helper-createInlineTemplate.js
Normal file
5
runtime/vdom/helper-createInlineTemplate.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
var Template = require('./').Template;
|
||||||
|
|
||||||
|
module.exports = function(path, renderFunc) {
|
||||||
|
return new Template(path, renderFunc);
|
||||||
|
};
|
||||||
27
runtime/vdom/helper-styleAttr.js
Normal file
27
runtime/vdom/helper-styleAttr.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* Helper for generating the string for a style attribute
|
||||||
|
* @param {[type]} style [description]
|
||||||
|
* @return {[type]} [description]
|
||||||
|
*/
|
||||||
|
module.exports = 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;
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -1,7 +1,9 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var HTMLElement = require('./HTMLElement');
|
var vdom = require('./vdom');
|
||||||
var Text = require('./Text');
|
var HTMLElement = vdom.$__HTMLElement;
|
||||||
|
var Text = vdom.$__Text;
|
||||||
|
|
||||||
var commonHelpers = require('../helpers');
|
var commonHelpers = require('../helpers');
|
||||||
var extend = require('raptor-util/extend');
|
var extend = require('raptor-util/extend');
|
||||||
|
|
||||||
@ -22,34 +24,6 @@ exports.const = function(id) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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:
|
||||||
@ -70,6 +44,4 @@ exports.ca = function(classNames) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.inline = require('./')._inline;
|
|
||||||
|
|
||||||
extend(exports, commonHelpers);
|
extend(exports, commonHelpers);
|
||||||
@ -24,18 +24,13 @@ function createOut(globalData, parent, state) {
|
|||||||
return new AsyncVDOMBuilder(globalData, parent, state);
|
return new AsyncVDOMBuilder(globalData, parent, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
Template.prototype = {
|
var Template_prototype = Template.prototype = {
|
||||||
createOut: createOut
|
createOut: createOut
|
||||||
};
|
};
|
||||||
|
|
||||||
makeRenderable(Template.prototype);
|
makeRenderable(Template_prototype);
|
||||||
|
|
||||||
exports._inline = function(filename, renderFunc) {
|
|
||||||
return new Template(filename, renderFunc);
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.Template = Template;
|
exports.Template = Template;
|
||||||
exports.createOut = createOut;
|
exports.$__createOut = createOut;
|
||||||
exports.helpers = require('./helpers');
|
|
||||||
|
|
||||||
require('../').$__setRuntime(exports);
|
require('../createOut').$__setCreateOut(createOut);
|
||||||
|
|||||||
139
runtime/vdom/vdom.js
Normal file
139
runtime/vdom/vdom.js
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
var Node = require('./Node');
|
||||||
|
var Comment = require('./Comment');
|
||||||
|
var DocumentFragment = require('./DocumentFragment');
|
||||||
|
var HTMLElement = require('./HTMLElement');
|
||||||
|
var Text = require('./Text');
|
||||||
|
var defaultDocument = typeof document != 'undefined' && document;
|
||||||
|
|
||||||
|
var specialHtmlRegexp = /[&<]/;
|
||||||
|
var range;
|
||||||
|
|
||||||
|
function virtualizeChildNodes(node, vdomParent) {
|
||||||
|
var curChild = node.firstChild;
|
||||||
|
while(curChild) {
|
||||||
|
vdomParent.$__appendChild(virtualize(curChild));
|
||||||
|
curChild = curChild.nextSibling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function virtualize(node) {
|
||||||
|
switch(node.nodeType) {
|
||||||
|
case 1:
|
||||||
|
var attributes = node.attributes;
|
||||||
|
var attrCount = attributes.length;
|
||||||
|
|
||||||
|
var attrs;
|
||||||
|
|
||||||
|
if (attrCount) {
|
||||||
|
attrs = {};
|
||||||
|
|
||||||
|
for (var i=0; i<attrCount; i++) {
|
||||||
|
var attr = attributes[i];
|
||||||
|
var attrName;
|
||||||
|
|
||||||
|
if (attr.namespaceURI === 'http://www.w3.org/1999/xlink' && attr.localName === 'href') {
|
||||||
|
attrName = 'xlink:href';
|
||||||
|
} else {
|
||||||
|
attrName = attr.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
attrs[attrName] = attr.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var vdomEL = new HTMLElement(node.nodeName, attrs);
|
||||||
|
|
||||||
|
if (vdomEL.$__isTextArea) {
|
||||||
|
vdomEL.$__value = node.value;
|
||||||
|
} else {
|
||||||
|
virtualizeChildNodes(node, vdomEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return vdomEL;
|
||||||
|
case 3:
|
||||||
|
return new Text(node.nodeValue);
|
||||||
|
case 8:
|
||||||
|
return new Comment(node.nodeValue);
|
||||||
|
case 11:
|
||||||
|
var vdomDocFragment = new DocumentFragment();
|
||||||
|
virtualizeChildNodes(node, vdomDocFragment);
|
||||||
|
return vdomDocFragment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
var Node_prototype = Node.prototype;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shorthand method for creating and appending a Text node with a given value
|
||||||
|
* @param {String} value The text value for the new Text node
|
||||||
|
*/
|
||||||
|
Node_prototype.t = function(value) {
|
||||||
|
var type = typeof value;
|
||||||
|
|
||||||
|
if (type !== 'string') {
|
||||||
|
if (value == null) {
|
||||||
|
value = '';
|
||||||
|
} else if (type === 'object') {
|
||||||
|
var safeHTML = value.safeHTML;
|
||||||
|
var vdomNode = virtualizeHTML(safeHTML || '', document);
|
||||||
|
this.$__appendChild(vdomNode);
|
||||||
|
return this.$__finishChild();
|
||||||
|
} else {
|
||||||
|
value = value.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.$__appendChild(new Text(value));
|
||||||
|
return this.$__finishChild();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shorthand method for creating and appending a Comment node with a given value
|
||||||
|
* @param {String} value The value for the new Comment node
|
||||||
|
*/
|
||||||
|
Node_prototype.c = function(value) {
|
||||||
|
this.$__appendChild(new Comment(value));
|
||||||
|
return this.$__finishChild();
|
||||||
|
};
|
||||||
|
|
||||||
|
Node_prototype.$__appendDocumentFragment = function() {
|
||||||
|
return this.$__appendChild(new DocumentFragment());
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.$__Comment = Comment;
|
||||||
|
exports.$__DocumentFragment = DocumentFragment;
|
||||||
|
exports.$__HTMLElement = HTMLElement;
|
||||||
|
exports.$__Text = Text;
|
||||||
|
exports.$__virtualize = virtualize;
|
||||||
|
exports.$__virtualizeHTML = virtualizeHTML;
|
||||||
|
exports.$__defaultDocument = defaultDocument;
|
||||||
@ -1,57 +0,0 @@
|
|||||||
var HTMLElement = require('./HTMLElement');
|
|
||||||
var DocumentFragment = require('./DocumentFragment');
|
|
||||||
var Comment = require('./Comment');
|
|
||||||
var Text = require('./Text');
|
|
||||||
|
|
||||||
function virtualizeChildNodes(node, vdomParent) {
|
|
||||||
var curChild = node.firstChild;
|
|
||||||
while(curChild) {
|
|
||||||
vdomParent.$__appendChild(virtualize(curChild));
|
|
||||||
curChild = curChild.nextSibling;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function virtualize(node) {
|
|
||||||
if (node.nodeType === 1) { // HtmlElement node
|
|
||||||
var attributes = node.attributes;
|
|
||||||
var attrCount = attributes.length;
|
|
||||||
|
|
||||||
var attrs;
|
|
||||||
|
|
||||||
if (attrCount) {
|
|
||||||
attrs = {};
|
|
||||||
|
|
||||||
for (var i=0; i<attrCount; i++) {
|
|
||||||
var attr = attributes[i];
|
|
||||||
var attrName;
|
|
||||||
|
|
||||||
if (attr.namespaceURI === 'http://www.w3.org/1999/xlink' && attr.localName === 'href') {
|
|
||||||
attrName = 'xlink:href';
|
|
||||||
} else {
|
|
||||||
attrName = attr.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
attrs[attrName] = attr.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var vdomEL = new HTMLElement(node.nodeName, attrs);
|
|
||||||
|
|
||||||
if (vdomEL.$__isTextArea) {
|
|
||||||
vdomEL.value = node.value;
|
|
||||||
} else {
|
|
||||||
virtualizeChildNodes(node, vdomEL);
|
|
||||||
}
|
|
||||||
|
|
||||||
return vdomEL;
|
|
||||||
} else if (node.nodeType === 3) { // Text node
|
|
||||||
return new Text(node.nodeValue);
|
|
||||||
} else if (node.nodeType === 8) { // Comment node
|
|
||||||
return new Comment(node.nodeValue);
|
|
||||||
} else if (node.nodeType === 11) { // DocumentFragment node
|
|
||||||
var vdomDocFragment = new DocumentFragment();
|
|
||||||
virtualizeChildNodes(node, vdomDocFragment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = virtualize;
|
|
||||||
@ -1,37 +0,0 @@
|
|||||||
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;
|
|
||||||
};
|
|
||||||
@ -212,8 +212,8 @@ module.exports = function awaitTag(input, out) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
asyncOut
|
asyncOut
|
||||||
.on('finish', function() {
|
.on('finish', function(result) {
|
||||||
asyncValue.resolve(asyncOut.getOutput());
|
asyncValue.resolve(result.getOutput());
|
||||||
})
|
})
|
||||||
.on('error', function(err) {
|
.on('error', function(err) {
|
||||||
asyncValue.reject(err);
|
asyncValue.reject(err);
|
||||||
|
|||||||
10
taglibs/cache/cached-fragment-tag.js
vendored
10
taglibs/cache/cached-fragment-tag.js
vendored
@ -19,15 +19,15 @@ module.exports = {
|
|||||||
|
|
||||||
if (input.renderBody) {
|
if (input.renderBody) {
|
||||||
input.renderBody(nestedOut);
|
input.renderBody(nestedOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
nestedOut.end();
|
|
||||||
|
|
||||||
nestedOut
|
nestedOut
|
||||||
.on('error', callback)
|
.on('error', callback)
|
||||||
.on('finish', function() {
|
.on('finish', function(result) {
|
||||||
callback(null, nestedOut.getOutput());
|
callback(null, result.getOutput());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
nestedOut.end();
|
||||||
}
|
}
|
||||||
}, function(err, result) {
|
}, function(err, result) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|||||||
@ -50,8 +50,8 @@ describe('AsyncStream', function() {
|
|||||||
out.write('3');
|
out.write('3');
|
||||||
out.write('4');
|
out.write('4');
|
||||||
out.end();
|
out.end();
|
||||||
out.on('finish', function() {
|
out.on('finish', function(result) {
|
||||||
var output = out.getOutput();
|
var output = result.getOutput();
|
||||||
expect(output).to.equal('1234');
|
expect(output).to.equal('1234');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -64,7 +64,7 @@ describe('AsyncStream', function() {
|
|||||||
out.write('2');
|
out.write('2');
|
||||||
|
|
||||||
return out.end().then((result) => {
|
return out.end().then((result) => {
|
||||||
const output = out.getOutput();
|
const output = result.getOutput();
|
||||||
expect(output).to.equal('12');
|
expect(output).to.equal('12');
|
||||||
expect(result.toString()).to.equal('12');
|
expect(result.toString()).to.equal('12');
|
||||||
});
|
});
|
||||||
@ -89,8 +89,8 @@ describe('AsyncStream', function() {
|
|||||||
}, 10);
|
}, 10);
|
||||||
|
|
||||||
out.end();
|
out.end();
|
||||||
out.on('finish', function() {
|
out.on('finish', function(result) {
|
||||||
var output = out.getOutput();
|
var output = result.getOutput();
|
||||||
expect(output).to.equal('1234');
|
expect(output).to.equal('1234');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -108,8 +108,8 @@ describe('AsyncStream', function() {
|
|||||||
|
|
||||||
out.write('3');
|
out.write('3');
|
||||||
out.end();
|
out.end();
|
||||||
out.on('finish', function() {
|
out.on('finish', function(result) {
|
||||||
var output = out.getOutput();
|
var output = result.getOutput();
|
||||||
expect(output).to.equal('123');
|
expect(output).to.equal('123');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -126,8 +126,8 @@ describe('AsyncStream', function() {
|
|||||||
|
|
||||||
out.write('3');
|
out.write('3');
|
||||||
out.end();
|
out.end();
|
||||||
out.on('finish', function() {
|
out.on('finish', function(result) {
|
||||||
var output = out.getOutput();
|
var output = result.getOutput();
|
||||||
expect(output).to.equal('123');
|
expect(output).to.equal('123');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -151,9 +151,9 @@ describe('AsyncStream', function() {
|
|||||||
out.write('3');
|
out.write('3');
|
||||||
out.end();
|
out.end();
|
||||||
|
|
||||||
out.on('finish', function() {
|
out.on('finish', function(result) {
|
||||||
expect(errors.length).to.equal(1);
|
expect(errors.length).to.equal(1);
|
||||||
expect(out.getOutput()).to.equal('13');
|
expect(result.getOutput()).to.equal('13');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -199,8 +199,8 @@ describe('AsyncStream', function() {
|
|||||||
}, 10);
|
}, 10);
|
||||||
|
|
||||||
out.end();
|
out.end();
|
||||||
out.on('finish', function() {
|
out.on('finish', function(result) {
|
||||||
var output = out.getOutput();
|
var output = result.getOutput();
|
||||||
expect(output).to.equal('12a2b2c34a4b4c');
|
expect(output).to.equal('12a2b2c34a4b4c');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -209,8 +209,8 @@ describe('AsyncStream', function() {
|
|||||||
it('should handle odd execution ordering', function(done) {
|
it('should handle odd execution ordering', function(done) {
|
||||||
var outA = createAsyncStream({ name:'outA' });
|
var outA = createAsyncStream({ name:'outA' });
|
||||||
|
|
||||||
outA.on('finish', function() {
|
outA.on('finish', function(result) {
|
||||||
var output = outA.getOutput();
|
var output = result.getOutput();
|
||||||
expect(output).to.equal('1234567');
|
expect(output).to.equal('1234567');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -255,8 +255,8 @@ describe('AsyncStream', function() {
|
|||||||
}, 10);
|
}, 10);
|
||||||
out.write('3');
|
out.write('3');
|
||||||
out.end();
|
out.end();
|
||||||
out.on('finish', function() {
|
out.on('finish', function(result) {
|
||||||
var output = out.getOutput();
|
var output = result.getOutput();
|
||||||
expect(errors.length).to.equal(1);
|
expect(errors.length).to.equal(1);
|
||||||
expect(output).to.equal('13');
|
expect(output).to.equal('13');
|
||||||
done();
|
done();
|
||||||
@ -292,7 +292,7 @@ describe('AsyncStream', function() {
|
|||||||
|
|
||||||
out.catch((err) => {
|
out.catch((err) => {
|
||||||
expect(err).to.be.an('error');
|
expect(err).to.be.an('error');
|
||||||
expect(out.getOutput()).to.equal('1');
|
expect(out.$__getOutput()).to.equal('1');
|
||||||
done();
|
done();
|
||||||
}).then((data) => {
|
}).then((data) => {
|
||||||
throw new Error('Should not get here!');
|
throw new Error('Should not get here!');
|
||||||
@ -309,8 +309,8 @@ describe('AsyncStream', function() {
|
|||||||
.on('error', function(e) {
|
.on('error', function(e) {
|
||||||
errors.push(e);
|
errors.push(e);
|
||||||
})
|
})
|
||||||
.on('finish', function() {
|
.on('finish', function(result) {
|
||||||
var output = out.getOutput();
|
var output = result.getOutput();
|
||||||
expect(errors.length).to.equal(1);
|
expect(errors.length).to.equal(1);
|
||||||
expect(output).to.equal('13');
|
expect(output).to.equal('13');
|
||||||
done();
|
done();
|
||||||
@ -435,8 +435,8 @@ describe('AsyncStream', function() {
|
|||||||
|
|
||||||
out.write('2');
|
out.write('2');
|
||||||
out.end();
|
out.end();
|
||||||
out.on('finish', function() {
|
out.on('finish', function(result) {
|
||||||
var output = out.getOutput();
|
var output = result.getOutput();
|
||||||
expect(output).to.equal('1Hello World2');
|
expect(output).to.equal('1Hello World2');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -492,8 +492,8 @@ describe('AsyncStream', function() {
|
|||||||
|
|
||||||
out.write('3');
|
out.write('3');
|
||||||
out.end();
|
out.end();
|
||||||
out.on('finish', function() {
|
out.on('finish', function(result) {
|
||||||
var output = out.getOutput();
|
var output = result.getOutput();
|
||||||
expect(output).to.equal('123');
|
expect(output).to.equal('123');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -519,9 +519,9 @@ describe('AsyncStream', function() {
|
|||||||
|
|
||||||
out.write('3');
|
out.write('3');
|
||||||
out.end();
|
out.end();
|
||||||
out.on('finish', function() {
|
out.on('finish', function(result) {
|
||||||
expect(lastFiredCount).to.equal(1);
|
expect(lastFiredCount).to.equal(1);
|
||||||
var output = out.getOutput();
|
var output = result.getOutput();
|
||||||
expect(output).to.equal('123');
|
expect(output).to.equal('123');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -590,8 +590,8 @@ describe('AsyncStream', function() {
|
|||||||
|
|
||||||
out.write('5');
|
out.write('5');
|
||||||
out.end();
|
out.end();
|
||||||
out.on('finish', function() {
|
out.on('finish', function(result) {
|
||||||
var output = out.getOutput();
|
var output = result.getOutput();
|
||||||
expect(output).to.equal('12345');
|
expect(output).to.equal('12345');
|
||||||
expect(onLastCount).to.equal(2);
|
expect(onLastCount).to.equal(2);
|
||||||
expect(lastOutput).to.deep.equal(['a', 'b']);
|
expect(lastOutput).to.deep.equal(['a', 'b']);
|
||||||
@ -795,8 +795,8 @@ describe('AsyncStream', function() {
|
|||||||
var out = new AsyncStream();
|
var out = new AsyncStream();
|
||||||
out.name = 'outer';
|
out.name = 'outer';
|
||||||
|
|
||||||
out.on('finish', function() {
|
out.on('finish', function(result) {
|
||||||
var output = out.getOutput();
|
var output = result.getOutput();
|
||||||
expect(output).to.equal('123');
|
expect(output).to.equal('123');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -820,8 +820,8 @@ describe('AsyncStream', function() {
|
|||||||
var out = createAsyncStream({global: { foo: 'bar' }});
|
var out = createAsyncStream({global: { foo: 'bar' }});
|
||||||
out.name = 'outer';
|
out.name = 'outer';
|
||||||
|
|
||||||
out.on('finish', function() {
|
out.on('finish', function(result) {
|
||||||
var output = out.getOutput();
|
var output = result.getOutput();
|
||||||
expect(output).to.equal('123');
|
expect(output).to.equal('123');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -17,7 +17,7 @@ describe('AsyncVDOMBuilder', function() {
|
|||||||
it('sync', function() {
|
it('sync', function() {
|
||||||
var out = new AsyncVDOMBuilder();
|
var out = new AsyncVDOMBuilder();
|
||||||
out.element('div', {}, 0);
|
out.element('div', {}, 0);
|
||||||
var tree = out.getOutput();
|
var tree = out.$__getOutput();
|
||||||
expect(getChildNodes(tree).length).to.equal(1);
|
expect(getChildNodes(tree).length).to.equal(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,7 @@ var autotest = require('./autotest');
|
|||||||
var marko = require('../');
|
var marko = require('../');
|
||||||
var markoCompiler = require('../compiler');
|
var markoCompiler = require('../compiler');
|
||||||
|
|
||||||
describe('api' , function() {
|
describe('api (compiler)' , function() {
|
||||||
var autoTestDir = nodePath.join(__dirname, 'autotests/api-compiler');
|
var autoTestDir = nodePath.join(__dirname, 'autotests/api-compiler');
|
||||||
|
|
||||||
autotest.scanDir(autoTestDir, function run(dir, helpers, done) {
|
autotest.scanDir(autoTestDir, function run(dir, helpers, done) {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
var marko_template = module.exports = require("marko/vdom").t(__filename);
|
var marko_template = module.exports = require("marko/vdom").t();
|
||||||
|
|
||||||
function render(data, out) {
|
function render(data, out) {
|
||||||
out.t("Hello ");
|
out.t("Hello ");
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
var marko_template = module.exports = require("marko/vdom").t(__filename);
|
var marko_template = module.exports = require("marko/vdom").t();
|
||||||
|
|
||||||
function render(data, out) {
|
function render(data, out) {
|
||||||
out.t("Hello ");
|
out.t("Hello ");
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
var marko_template = module.exports = require("marko/vdom").t(__filename);
|
var marko_template = module.exports = require("marko/vdom").t();
|
||||||
|
|
||||||
function render(data, out) {
|
function render(data, out) {
|
||||||
out.t("Hello ");
|
out.t("Hello ");
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
var marko_template = module.exports = require("marko/vdom").t(__filename);
|
var marko_template = module.exports = require("marko/vdom").t();
|
||||||
|
|
||||||
function render(data, out) {
|
function render(data, out) {
|
||||||
out.t("Hello ");
|
out.t("Hello ");
|
||||||
|
|||||||
@ -5,13 +5,13 @@ exports.check = function(marko, markoCompiler, expect, done) {
|
|||||||
template.renderToString({
|
template.renderToString({
|
||||||
name: 'John'
|
name: 'John'
|
||||||
},
|
},
|
||||||
function(err, result, out) {
|
function(err, html, out) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return done(err);
|
return done(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(result.toString()).to.equal(out.getOutput());
|
expect(html).to.equal(out.getOutput());
|
||||||
expect(result.toString()).to.equal('Hello John!');
|
expect(html).to.equal('Hello John!');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -5,8 +5,8 @@ exports.check = function(marko, markoCompiler, expect, done) {
|
|||||||
|
|
||||||
var out = runtimeHtml.createWriter();
|
var out = runtimeHtml.createWriter();
|
||||||
out
|
out
|
||||||
.on('finish', function() {
|
.on('finish', function(result) {
|
||||||
expect(out.getOutput()).to.equal('Hello John!');
|
expect(result.getOutput()).to.equal('Hello John!');
|
||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
.on('error', function(e) {
|
.on('error', function(e) {
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
var marko_template = module.exports = require("marko/html").t(__filename),
|
var marko_template = module.exports = require("marko/html").t(__filename),
|
||||||
marko_helpers = require("marko/runtime/html/helpers"),
|
marko_forEachProp = require("marko/runtime/helper-forEachProperty");
|
||||||
marko_forEachProp = marko_helpers.fp;
|
|
||||||
|
|
||||||
function render(data, out) {
|
function render(data, out) {
|
||||||
marko_forEachProp(myObject, function(k, v) {
|
marko_forEachProp(myObject, function(k, v) {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
var marko_template = module.exports = require("marko/vdom").t(__filename),
|
var marko_template = module.exports = require("marko/vdom").t(),
|
||||||
include_target_template = require("./include-target.marko"),
|
include_target_template = require("./include-target.marko"),
|
||||||
marko_helpers = require("marko/runtime/vdom/helpers"),
|
marko_helpers = require("marko/runtime/vdom/helpers"),
|
||||||
marko_loadTag = marko_helpers.t,
|
marko_loadTag = marko_helpers.t,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
var marko_template = module.exports = require("marko/vdom").t(__filename),
|
var marko_template = module.exports = require("marko/vdom").t(),
|
||||||
marko_helpers = require("marko/runtime/vdom/helpers"),
|
marko_helpers = require("marko/runtime/vdom/helpers"),
|
||||||
marko_forEach = marko_helpers.f,
|
marko_forEach = marko_helpers.f,
|
||||||
marko_createElement = marko_helpers.e,
|
marko_createElement = marko_helpers.e,
|
||||||
|
|||||||
@ -2,7 +2,7 @@ var marko_template = module.exports = require("marko/html").t(__filename),
|
|||||||
marko_helpers = require("marko/runtime/html/helpers"),
|
marko_helpers = require("marko/runtime/html/helpers"),
|
||||||
marko_loadTag = marko_helpers.t,
|
marko_loadTag = marko_helpers.t,
|
||||||
custom_tag_data_tag = marko_loadTag(require("./custom-tag-data-tag")),
|
custom_tag_data_tag = marko_loadTag(require("./custom-tag-data-tag")),
|
||||||
marko_merge = marko_helpers.m;
|
marko_merge = require("marko/runtime/helper-merge");
|
||||||
|
|
||||||
function render(data, out) {
|
function render(data, out) {
|
||||||
custom_tag_data_tag({
|
custom_tag_data_tag({
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
var marko_template = module.exports = require("marko/html").t(__filename),
|
var marko_template = module.exports = require("marko/html").t(__filename),
|
||||||
marko_helpers = require("marko/runtime/html/helpers"),
|
marko_loadTemplate = require("marko/runtime/helper-loadTemplate"),
|
||||||
marko_loadTemplate = marko_helpers.l,
|
|
||||||
hello_template = marko_loadTemplate(require.resolve("./hello.marko")),
|
hello_template = marko_loadTemplate(require.resolve("./hello.marko")),
|
||||||
|
marko_helpers = require("marko/runtime/html/helpers"),
|
||||||
marko_loadTag = marko_helpers.t,
|
marko_loadTag = marko_helpers.t,
|
||||||
hello_tag = marko_loadTag(hello_template);
|
hello_tag = marko_loadTag(hello_template);
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
var marko_template = module.exports = require("marko/html").t(__filename),
|
var marko_template = module.exports = require("marko/html").t(__filename),
|
||||||
marko_helpers = require("marko/runtime/html/helpers"),
|
marko_loadTemplate = require("marko/runtime/helper-loadTemplate"),
|
||||||
marko_loadTemplate = marko_helpers.l,
|
|
||||||
target_template = marko_loadTemplate(require.resolve("./target.marko")),
|
target_template = marko_loadTemplate(require.resolve("./target.marko")),
|
||||||
|
marko_helpers = require("marko/runtime/html/helpers"),
|
||||||
marko_loadTag = marko_helpers.t,
|
marko_loadTag = marko_helpers.t,
|
||||||
include_tag = marko_loadTag(require("marko/taglibs/core/include-tag"));
|
include_tag = marko_loadTag(require("marko/taglibs/core/include-tag"));
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
var marko_template = module.exports = require("marko/html").t(__filename),
|
var marko_template = module.exports = require("marko/html").t(__filename),
|
||||||
marko_helpers = require("marko/runtime/html/helpers"),
|
marko_loadTemplate = require("marko/runtime/helper-loadTemplate"),
|
||||||
marko_loadTemplate = marko_helpers.l,
|
|
||||||
test_message_template = marko_loadTemplate(require.resolve("./components/test-message/template.marko")),
|
test_message_template = marko_loadTemplate(require.resolve("./components/test-message/template.marko")),
|
||||||
|
marko_helpers = require("marko/runtime/html/helpers"),
|
||||||
marko_loadTag = marko_helpers.t,
|
marko_loadTag = marko_helpers.t,
|
||||||
test_message_tag = marko_loadTag(test_message_template);
|
test_message_tag = marko_loadTag(test_message_template);
|
||||||
|
|
||||||
|
|||||||
1
test/autotests/render/for-tag-status-var/expected.html
Normal file
1
test/autotests/render/for-tag-status-var/expected.html
Normal file
@ -0,0 +1 @@
|
|||||||
|
<div>red - true - false - 0 - 3</div><div>green - false - false - 1 - 3</div><div>blue - false - true - 2 - 3</div>
|
||||||
5
test/autotests/render/for-tag-status-var/template.marko
Normal file
5
test/autotests/render/for-tag-status-var/template.marko
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<for(item in ['red', 'green', 'blue'] | status-var=loop)>
|
||||||
|
<div>
|
||||||
|
${item} - ${loop.isFirst()} - ${loop.isLast()} - ${loop.getIndex()} - ${loop.getLength()}
|
||||||
|
</div>
|
||||||
|
</for>
|
||||||
1
test/autotests/render/for-tag-status-var/test.js
Normal file
1
test/autotests/render/for-tag-status-var/test.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
exports.templateData = {};
|
||||||
@ -1,24 +1 @@
|
|||||||
exports.templateData = {
|
exports.templateData = {};
|
||||||
"accounts": [
|
|
||||||
{
|
|
||||||
"balance": 0,
|
|
||||||
"balanceFormatted": "$0.00",
|
|
||||||
"status": "open"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"balance": 10,
|
|
||||||
"balanceFormatted": "$10.00",
|
|
||||||
"status": "closed"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"balance": -100,
|
|
||||||
"balanceFormatted": "$-100.00",
|
|
||||||
"status": "suspended"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"balance": 999,
|
|
||||||
"balanceFormatted": "$999.00",
|
|
||||||
"status": "open"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
var marko_template = module.exports = require("marko/vdom").t(__filename),
|
var marko_template = module.exports = require("marko/vdom").t(),
|
||||||
marko_helpers = require("marko/runtime/vdom/helpers"),
|
marko_helpers = require("marko/runtime/vdom/helpers"),
|
||||||
marko_classList = marko_helpers.cl,
|
marko_classList = marko_helpers.cl,
|
||||||
marko_classAttr = marko_helpers.ca;
|
marko_classAttr = marko_helpers.ca;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
var marko_template = module.exports = require("marko/vdom").t(__filename);
|
var marko_template = module.exports = require("marko/vdom").t();
|
||||||
|
|
||||||
function render(data, out) {
|
function render(data, out) {
|
||||||
out.e("div", {
|
out.e("div", {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
var marko_template = module.exports = require("marko/vdom").t(__filename);
|
var marko_template = module.exports = require("marko/vdom").t();
|
||||||
|
|
||||||
function render(data, out) {
|
function render(data, out) {
|
||||||
var attrs = {
|
var attrs = {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
var marko_template = module.exports = require("marko/vdom").t(__filename),
|
var marko_template = module.exports = require("marko/vdom").t(),
|
||||||
marko_helpers = require("marko/runtime/vdom/helpers"),
|
marko_helpers = require("marko/runtime/vdom/helpers"),
|
||||||
marko_loadTag = marko_helpers.t,
|
marko_loadTag = marko_helpers.t,
|
||||||
test_hello_tag = marko_loadTag(require("./tags/test-hello/renderer")),
|
test_hello_tag = marko_loadTag(require("./tags/test-hello/renderer")),
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
var marko_template = module.exports = require("marko/vdom").t(__filename),
|
var marko_template = module.exports = require("marko/vdom").t(),
|
||||||
marko_attrs0 = {
|
marko_attrs0 = {
|
||||||
"class": "foo"
|
"class": "foo"
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
var marko_template = module.exports = require("marko/vdom").t(__filename);
|
var marko_template = module.exports = require("marko/vdom").t();
|
||||||
|
|
||||||
function render(data, out) {
|
function render(data, out) {
|
||||||
out.t("Hello ");
|
out.t("Hello ");
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
var marko_template = module.exports = require("marko/vdom").t(__filename),
|
var marko_template = module.exports = require("marko/vdom").t(),
|
||||||
marko_helpers = require("marko/runtime/vdom/helpers"),
|
marko_helpers = require("marko/runtime/vdom/helpers"),
|
||||||
marko_forEach = marko_helpers.f,
|
marko_forEach = marko_helpers.f,
|
||||||
marko_createElement = marko_helpers.e,
|
marko_createElement = marko_helpers.e,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
var marko_template = module.exports = require("marko/vdom").t(__filename),
|
var marko_template = module.exports = require("marko/vdom").t(),
|
||||||
marko_helpers = require("marko/runtime/vdom/helpers"),
|
marko_helpers = require("marko/runtime/vdom/helpers"),
|
||||||
marko_createElement = marko_helpers.e,
|
marko_createElement = marko_helpers.e,
|
||||||
marko_const = marko_helpers.const,
|
marko_const = marko_helpers.const,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
var marko_template = module.exports = require("marko/vdom").t(__filename),
|
var marko_template = module.exports = require("marko/vdom").t(),
|
||||||
marko_helpers = require("marko/runtime/vdom/helpers"),
|
marko_helpers = require("marko/runtime/vdom/helpers"),
|
||||||
marko_createElement = marko_helpers.e,
|
marko_createElement = marko_helpers.e,
|
||||||
marko_const = marko_helpers.const,
|
marko_const = marko_helpers.const,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
var marko_template = module.exports = require("marko/vdom").t(__filename),
|
var marko_template = module.exports = require("marko/vdom").t(),
|
||||||
marko_helpers = require("marko/runtime/vdom/helpers"),
|
marko_helpers = require("marko/runtime/vdom/helpers"),
|
||||||
marko_loadTag = marko_helpers.t,
|
marko_loadTag = marko_helpers.t,
|
||||||
test_hello_tag = marko_loadTag(require("./tags/test-hello/renderer"));
|
test_hello_tag = marko_loadTag(require("./tags/test-hello/renderer"));
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
|
|
||||||
module.exports = function(helpers) {
|
module.exports = function(helpers) {
|
||||||
var targetEl = helpers.document.createElement('div');
|
var morphAttrs = helpers.vdom.HTMLElement.$__morphAttrs;
|
||||||
var virtualEl = helpers.vdom.createElement('div', { class: 'foo', 'xlink:href': 'bar.com' });
|
|
||||||
virtualEl.assignAttributes(targetEl);
|
var fromEl = helpers.document.createElement('div');
|
||||||
return targetEl;
|
var toEl = helpers.vdom.createElement('div', { class: 'foo', 'xlink:href': 'bar.com' });
|
||||||
|
morphAttrs(fromEl, toEl);
|
||||||
|
return fromEl;
|
||||||
};
|
};
|
||||||
@ -1,3 +0,0 @@
|
|||||||
<div>
|
|
||||||
<h1>
|
|
||||||
"New child"
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
var expect = require('chai').expect;
|
|
||||||
module.exports = function(helpers) {
|
|
||||||
var div = helpers.vdom.createElement('div', null, 1 /* childCount */)
|
|
||||||
.e('span', { class: 'bar' }, 0);
|
|
||||||
|
|
||||||
expect(div.firstChild.nodeName).to.equal('span');
|
|
||||||
|
|
||||||
div.removeChildren();
|
|
||||||
expect(div.firstChild).to.equal(undefined);
|
|
||||||
|
|
||||||
var newChild = helpers.vdom.createElement('h1', null, 1)
|
|
||||||
.t('New child');
|
|
||||||
|
|
||||||
div.$__appendChild(newChild);
|
|
||||||
|
|
||||||
expect(div.firstChild).to.equal(newChild);
|
|
||||||
expect(div.firstChild.nextSibling).to.equal(undefined);
|
|
||||||
|
|
||||||
return div;
|
|
||||||
};
|
|
||||||
@ -4,9 +4,9 @@ var marko_template = module.exports = require("marko/html").t(__filename),
|
|||||||
marko_widgetType = marko_registerWidget("/marko-test$1.0.0/autotests/widgets-compilation/ref/index.marko", function() {
|
marko_widgetType = marko_registerWidget("/marko-test$1.0.0/autotests/widgets-compilation/ref/index.marko", function() {
|
||||||
return module.exports;
|
return module.exports;
|
||||||
}),
|
}),
|
||||||
marko_helpers = require("marko/runtime/html/helpers"),
|
marko_loadTemplate = require("marko/runtime/helper-loadTemplate"),
|
||||||
marko_loadTemplate = marko_helpers.l,
|
|
||||||
app_foo_template = marko_loadTemplate(require.resolve("./components/app-foo")),
|
app_foo_template = marko_loadTemplate(require.resolve("./components/app-foo")),
|
||||||
|
marko_helpers = require("marko/runtime/html/helpers"),
|
||||||
marko_loadTag = marko_helpers.t,
|
marko_loadTag = marko_helpers.t,
|
||||||
app_foo_tag = marko_loadTag(app_foo_template),
|
app_foo_tag = marko_loadTag(app_foo_template),
|
||||||
marko_attr = marko_helpers.a;
|
marko_attr = marko_helpers.a;
|
||||||
|
|||||||
@ -1,15 +1,16 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
const jsdom = require("jsdom").jsdom;
|
||||||
|
const defaultDocument = jsdom('<html><body></body></html>');
|
||||||
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const marko = require('marko');
|
const marko = require('marko');
|
||||||
const fsExtra = require('fs-extra');
|
const fsExtra = require('fs-extra');
|
||||||
const domToHTML = require('./domToHTML');
|
const domToHTML = require('./domToHTML');
|
||||||
const domToString = require('./domToString');
|
const domToString = require('./domToString');
|
||||||
const jsdom = require("jsdom").jsdom;
|
|
||||||
const expect = require('chai').expect;
|
const expect = require('chai').expect;
|
||||||
|
|
||||||
const defaultDocument = jsdom('<html><body></body></html>');
|
|
||||||
require('../../').setDocument(defaultDocument); // We need this to parse HTML fragments on the server
|
|
||||||
|
|
||||||
|
|
||||||
function createAsyncVerifier(main, helpers, out) {
|
function createAsyncVerifier(main, helpers, out) {
|
||||||
@ -141,8 +142,8 @@ module.exports = function runRenderTest(dir, helpers, done, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
out.on('error', done);
|
out.on('error', done);
|
||||||
out.on('finish', function() {
|
out.on('finish', function(result) {
|
||||||
var renderOutput = out.getOutput();
|
var renderOutput = result.getOutput();
|
||||||
|
|
||||||
if (isVDOM) {
|
if (isVDOM) {
|
||||||
let vdomTree = renderOutput;
|
let vdomTree = renderOutput;
|
||||||
@ -158,6 +159,9 @@ module.exports = function runRenderTest(dir, helpers, done, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
require('marko/compiler').configure({ output: 'html' });
|
require('marko/compiler').configure({ output: 'html' });
|
||||||
|
require('marko/runtime/vdom/AsyncVDOMBuilder').prototype.$__document = defaultDocument;
|
||||||
|
global.document = defaultDocument;
|
||||||
|
|
||||||
let htmlTemplatePath = path.join(dir, 'template.marko');
|
let htmlTemplatePath = path.join(dir, 'template.marko');
|
||||||
let htmlTemplate = marko.load(htmlTemplatePath);
|
let htmlTemplate = marko.load(htmlTemplatePath);
|
||||||
let htmlMainPath = path.join(dir, 'test.js');
|
let htmlMainPath = path.join(dir, 'test.js');
|
||||||
|
|||||||
@ -28,7 +28,7 @@ function toHTML(node) {
|
|||||||
|
|
||||||
html += indent + '<' + tagName;
|
html += indent + '<' + tagName;
|
||||||
|
|
||||||
var attributes = el.attributes;
|
var attributes = el.attributes || el.$__attributes;
|
||||||
var attributesArray = [];
|
var attributesArray = [];
|
||||||
var attrName;
|
var attrName;
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,8 @@ var vdomHelpers = {
|
|||||||
},
|
},
|
||||||
createDocumentFragment: function() {
|
createDocumentFragment: function() {
|
||||||
return new DocumentFragment();
|
return new DocumentFragment();
|
||||||
}
|
},
|
||||||
|
HTMLElement: HTMLElement
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('marko-vdom', () => {
|
describe('marko-vdom', () => {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
var path = require('path');
|
var path = require('path');
|
||||||
var virtualize = require('../runtime/vdom/virtualize');
|
var virtualize = require('../runtime/vdom/vdom').$__virtualize;
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var toHTML = require('./util/toHTML');
|
var toHTML = require('./util/toHTML');
|
||||||
var jsdom = require("jsdom").jsdom;
|
var jsdom = require("jsdom").jsdom;
|
||||||
|
|||||||
@ -5,6 +5,7 @@ describe('marko-widgets (server)', function() {
|
|||||||
require('./util/autotest').runTests(
|
require('./util/autotest').runTests(
|
||||||
require('./autotests/widgets-server/autotests.tests'),
|
require('./autotests/widgets-server/autotests.tests'),
|
||||||
function run(testFunc, done) {
|
function run(testFunc, done) {
|
||||||
|
require('marko/compiler').configure({ output: 'html' });
|
||||||
var helpers = {};
|
var helpers = {};
|
||||||
|
|
||||||
if (testFunc.length === 1) {
|
if (testFunc.length === 1) {
|
||||||
|
|||||||
@ -62,11 +62,10 @@ State.prototype = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
$__set: function(name, value, shouldEnsure, forceDirty, noQueue) {
|
$__set: function(name, value, shouldEnsure, forceDirty, noQueue) {
|
||||||
var self = this;
|
var rawState = this.$__raw;
|
||||||
var rawState = self.$__raw;
|
|
||||||
|
|
||||||
if (shouldEnsure) {
|
if (shouldEnsure) {
|
||||||
ensure(self, name);
|
ensure(this, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value === null) {
|
if (value === null) {
|
||||||
@ -106,7 +105,7 @@ State.prototype = {
|
|||||||
if (clean && noQueue !== true) {
|
if (clean && noQueue !== true) {
|
||||||
// If we were clean before then we are now dirty so queue
|
// If we were clean before then we are now dirty so queue
|
||||||
// up the widget for update
|
// up the widget for update
|
||||||
updateManager.$__queueWidgetUpdate(self.$__widget);
|
updateManager.$__queueWidgetUpdate(this.$__widget);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
toJSON: function() {
|
toJSON: function() {
|
||||||
|
|||||||
@ -3,15 +3,22 @@
|
|||||||
|
|
||||||
var domInsert = require('../runtime/dom-insert');
|
var domInsert = require('../runtime/dom-insert');
|
||||||
var marko = require('../');
|
var marko = require('../');
|
||||||
var markoWidgets = require('./');
|
var widgetsUtil = require('./util');
|
||||||
var getRootEls = require('./getRootEls');
|
var getWidgetForEl = widgetsUtil.$__getWidgetForEl;
|
||||||
|
var widgetLookup = widgetsUtil.$__widgetLookup;
|
||||||
|
var emitLifecycleEvent = widgetsUtil.$__emitLifecycleEvent;
|
||||||
|
var destroyWidgetForEl = widgetsUtil.$__destroyWidgetForEl;
|
||||||
|
var destroyElRecursive = widgetsUtil.$__destroyElRecursive;
|
||||||
|
var getElementById = widgetsUtil.$__getElementById;
|
||||||
var EventEmitter = require('events-light');
|
var EventEmitter = require('events-light');
|
||||||
var RenderResult = require('../runtime/RenderResult');
|
var RenderResult = require('../runtime/RenderResult');
|
||||||
var SubscriptionTracker = require('listener-tracker');
|
var SubscriptionTracker = require('listener-tracker');
|
||||||
var inherit = require('raptor-util/inherit');
|
var inherit = require('raptor-util/inherit');
|
||||||
var updateManager = require('./update-manager');
|
var updateManager = require('./update-manager');
|
||||||
var morphdom = require('morphdom');
|
var morphAttrs = require('../runtime/vdom/HTMLElement').$__morphAttrs;
|
||||||
var widgetLookup = require('./lookup').$__widgets;
|
var morphdomFactory = require('morphdom/factory');
|
||||||
|
var morphdom = morphdomFactory(morphAttrs);
|
||||||
|
|
||||||
|
|
||||||
var slice = Array.prototype.slice;
|
var slice = Array.prototype.slice;
|
||||||
|
|
||||||
@ -24,115 +31,14 @@ var NON_WIDGET_SUBSCRIBE_TO_OPTIONS = {
|
|||||||
|
|
||||||
var emit = EventEmitter.prototype.emit;
|
var emit = EventEmitter.prototype.emit;
|
||||||
|
|
||||||
var lifecycleEventMethods = {};
|
function removeListener(removeEventListenerHandle) {
|
||||||
|
removeEventListenerHandle();
|
||||||
['beforeDestroy',
|
|
||||||
'destroy',
|
|
||||||
'beforeUpdate',
|
|
||||||
'update',
|
|
||||||
'mount',
|
|
||||||
'render',
|
|
||||||
'beforeInit',
|
|
||||||
'afterInit'].forEach(function(eventName) {
|
|
||||||
lifecycleEventMethods[eventName] = 'on' + eventName.charAt(0).toUpperCase() + eventName.substring(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
function removeListener(eventListenerHandle) {
|
|
||||||
eventListenerHandle();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method handles invoking a widget's event handler method
|
|
||||||
* (if present) while also emitting the event through
|
|
||||||
* the standard EventEmitter.prototype.emit method.
|
|
||||||
*
|
|
||||||
* Special events and their corresponding handler methods
|
|
||||||
* include the following:
|
|
||||||
*
|
|
||||||
* beforeDestroy --> onBeforeDestroy
|
|
||||||
* destroy --> onDestroy
|
|
||||||
* beforeUpdate --> onBeforeUpdate
|
|
||||||
* update --> onUpdate
|
|
||||||
* render --> onRender
|
|
||||||
*/
|
|
||||||
function emitLifecycleEvent(widget, eventType, eventArg) {
|
|
||||||
var listenerMethod = widget[lifecycleEventMethods[eventType]];
|
|
||||||
|
|
||||||
if (listenerMethod) {
|
|
||||||
listenerMethod.call(widget, eventArg);
|
|
||||||
}
|
|
||||||
|
|
||||||
widget.emit(eventType, eventArg);
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeDOMEventListeners(widget) {
|
|
||||||
var eventListenerHandles = widget.$__domEventListenerHandles;
|
|
||||||
if (eventListenerHandles) {
|
|
||||||
eventListenerHandles.forEach(removeListener);
|
|
||||||
widget.$__domEventListenerHandles = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function destroyWidgetForEl(el) {
|
|
||||||
var widgetToDestroy = el._w;
|
|
||||||
if (widgetToDestroy) {
|
|
||||||
destroyWidgetHelper(widgetToDestroy);
|
|
||||||
el._w = null;
|
|
||||||
|
|
||||||
while ((widgetToDestroy = widgetToDestroy.$__rootFor)) {
|
|
||||||
widgetToDestroy.$__rootFor = null;
|
|
||||||
destroyWidgetHelper(widgetToDestroy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function destroyElRecursive(el) {
|
|
||||||
var curChild = el.firstChild;
|
|
||||||
while(curChild) {
|
|
||||||
if (curChild.nodeType === 1) {
|
|
||||||
destroyElRecursive(curChild);
|
|
||||||
destroyWidgetForEl(curChild);
|
|
||||||
}
|
|
||||||
curChild = curChild.nextSibling;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function destroyWidgetHelper(widget) {
|
|
||||||
if (widget.$__destroyed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
emitLifecycleEvent(widget, 'beforeDestroy');
|
|
||||||
widget.$__destroyed = true;
|
|
||||||
|
|
||||||
widget.els = null;
|
|
||||||
widget.el = null;
|
|
||||||
|
|
||||||
// Unsubscribe from all DOM events
|
|
||||||
removeDOMEventListeners(widget);
|
|
||||||
|
|
||||||
if (widget.$__subscriptions) {
|
|
||||||
widget.$__subscriptions.removeAllListeners();
|
|
||||||
widget.$__subscriptions = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete widgetLookup[widget.id];
|
|
||||||
|
|
||||||
emitLifecycleEvent(widget, 'destroy');
|
|
||||||
}
|
|
||||||
|
|
||||||
function resetWidget(widget) {
|
|
||||||
widget.$__newProps = null;
|
|
||||||
widget.$__state.$__reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasCompatibleWidget(widgetsContext, existingWidget) {
|
function hasCompatibleWidget(widgetsContext, existingWidget) {
|
||||||
var id = existingWidget.id;
|
var id = existingWidget.id;
|
||||||
var newWidgetDef = widgetsContext.$__widgetsById[id];
|
var newWidgetDef = widgetsContext.$__widgetsById[id];
|
||||||
if (!newWidgetDef) {
|
return newWidgetDef && existingWidget.$__type == newWidgetDef.$__type;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return existingWidget.$__type === newWidgetDef.$__type;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCustomEventWithMethodListener(widget, targetMethodName, args, extraArgs) {
|
function handleCustomEventWithMethodListener(widget, targetMethodName, args, extraArgs) {
|
||||||
@ -174,8 +80,7 @@ function getElIdHelper(widget, widgetElId, index) {
|
|||||||
*/
|
*/
|
||||||
function processUpdateHandlers(widget, stateChanges, oldState) {
|
function processUpdateHandlers(widget, stateChanges, oldState) {
|
||||||
var handlerMethod;
|
var handlerMethod;
|
||||||
var handlers = [];
|
var handlers;
|
||||||
|
|
||||||
|
|
||||||
for (var propName in stateChanges) {
|
for (var propName in stateChanges) {
|
||||||
if (stateChanges.hasOwnProperty(propName)) {
|
if (stateChanges.hasOwnProperty(propName)) {
|
||||||
@ -183,11 +88,11 @@ function processUpdateHandlers(widget, stateChanges, oldState) {
|
|||||||
|
|
||||||
handlerMethod = widget[handlerMethodName];
|
handlerMethod = widget[handlerMethodName];
|
||||||
if (handlerMethod) {
|
if (handlerMethod) {
|
||||||
handlers.push([propName, handlerMethod]);
|
(handlers || (handlers=[])).push([propName, handlerMethod]);
|
||||||
} else {
|
} else {
|
||||||
// This state change does not have a state handler so return false
|
// This state change does not have a state handler so return false
|
||||||
// to force a rerender
|
// to force a rerender
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -195,30 +100,27 @@ function processUpdateHandlers(widget, stateChanges, oldState) {
|
|||||||
// If we got here then all of the changed state properties have
|
// If we got here then all of the changed state properties have
|
||||||
// an update handler or there are no state properties that actually
|
// an update handler or there are no state properties that actually
|
||||||
// changed.
|
// changed.
|
||||||
|
if (handlers) {
|
||||||
|
// Otherwise, there are handlers for all of the changed properties
|
||||||
|
// so apply the updates using those handlers
|
||||||
|
|
||||||
if (!handlers.length) {
|
emitLifecycleEvent(widget, 'beforeUpdate');
|
||||||
return true;
|
|
||||||
|
for (var i=0, len=handlers.length; i<len; i++) {
|
||||||
|
var handler = handlers[i];
|
||||||
|
var propertyName = handler[0];
|
||||||
|
handlerMethod = handler[1];
|
||||||
|
|
||||||
|
var newValue = stateChanges[propertyName];
|
||||||
|
var oldValue = oldState[propertyName];
|
||||||
|
handlerMethod.call(widget, newValue, oldValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
emitLifecycleEvent(widget, 'update');
|
||||||
|
|
||||||
|
widget.$__reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, there are handlers for all of the changed properties
|
|
||||||
// so apply the updates using those handlers
|
|
||||||
|
|
||||||
emitLifecycleEvent(widget, 'beforeUpdate');
|
|
||||||
|
|
||||||
for (var i=0, len=handlers.length; i<len; i++) {
|
|
||||||
var handler = handlers[i];
|
|
||||||
var propertyName = handler[0];
|
|
||||||
handlerMethod = handler[1];
|
|
||||||
|
|
||||||
var newValue = stateChanges[propertyName];
|
|
||||||
var oldValue = oldState[propertyName];
|
|
||||||
handlerMethod.call(widget, newValue, oldValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
emitLifecycleEvent(widget, 'update');
|
|
||||||
|
|
||||||
resetWidget(widget);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,20 +131,23 @@ var widgetProto;
|
|||||||
*
|
*
|
||||||
* NOTE: Any methods that are prefixed with an underscore should be considered private!
|
* NOTE: Any methods that are prefixed with an underscore should be considered private!
|
||||||
*/
|
*/
|
||||||
function Widget(id, document) {
|
function Widget(id, doc) {
|
||||||
EventEmitter.call(this);
|
EventEmitter.call(this);
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.el = null;
|
this.el =
|
||||||
this.$__bodyEl = null;
|
this.$__state =
|
||||||
this.$__state = null;
|
this.$__roots =
|
||||||
this.$__roots = null;
|
this.$__subscriptions =
|
||||||
this.$__subscriptions = null;
|
this.$__domEventListenerHandles =
|
||||||
this.$__domEventListenerHandles = null;
|
this.$__customEvents =
|
||||||
this.$__destroyed = false;
|
this.$__scope =
|
||||||
this.$__customEvents = null;
|
null;
|
||||||
this.$__scope = null;
|
|
||||||
this.$__updateQueued = false;
|
this.$__destroyed =
|
||||||
this.$__document = document;
|
this.$__updateQueued =
|
||||||
|
false;
|
||||||
|
|
||||||
|
this.$__document = doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget.prototype = widgetProto = {
|
Widget.prototype = widgetProto = {
|
||||||
@ -253,16 +158,13 @@ Widget.prototype = widgetProto = {
|
|||||||
throw TypeError();
|
throw TypeError();
|
||||||
}
|
}
|
||||||
|
|
||||||
var tracker = this.$__subscriptions;
|
var subscriptions = this.$__subscriptions || (subscriptions = new SubscriptionTracker());
|
||||||
if (!tracker) {
|
|
||||||
this.$__subscriptions = tracker = new SubscriptionTracker();
|
|
||||||
}
|
|
||||||
|
|
||||||
var subscribeToOptions = target.$__isWidget ?
|
var subscribeToOptions = target.$__isWidget ?
|
||||||
WIDGET_SUBSCRIBE_TO_OPTIONS :
|
WIDGET_SUBSCRIBE_TO_OPTIONS :
|
||||||
NON_WIDGET_SUBSCRIBE_TO_OPTIONS;
|
NON_WIDGET_SUBSCRIBE_TO_OPTIONS;
|
||||||
|
|
||||||
return tracker.subscribeTo(target, subscribeToOptions);
|
return subscriptions.subscribeTo(target, subscribeToOptions);
|
||||||
},
|
},
|
||||||
|
|
||||||
emit: function(eventType) {
|
emit: function(eventType) {
|
||||||
@ -286,19 +188,16 @@ Widget.prototype = widgetProto = {
|
|||||||
var doc = this.$__document;
|
var doc = this.$__document;
|
||||||
|
|
||||||
if (widgetElId != null) {
|
if (widgetElId != null) {
|
||||||
return doc.getElementById(getElIdHelper(this, widgetElId, index));
|
return getElementById(doc, getElIdHelper(this, widgetElId, index));
|
||||||
} else {
|
} else {
|
||||||
return this.el || doc.getElementById(getElIdHelper(this));
|
return this.el || getElementById(doc, getElIdHelper(this));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getEls: function(id) {
|
getEls: function(id) {
|
||||||
var els = [];
|
var els = [];
|
||||||
var i=0;
|
var i = 0;
|
||||||
while(true) {
|
var el;
|
||||||
var el = this.getEl(id, i);
|
while((el = this.getEl(id, i))) {
|
||||||
if (!el) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
els.push(el);
|
els.push(el);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
@ -309,18 +208,15 @@ Widget.prototype = widgetProto = {
|
|||||||
},
|
},
|
||||||
getWidgets: function(id) {
|
getWidgets: function(id) {
|
||||||
var widgets = [];
|
var widgets = [];
|
||||||
var i=0;
|
var i = 0;
|
||||||
while(true) {
|
var widget;
|
||||||
var widget = widgetLookup[getElIdHelper(this, id, i)];
|
while((widget = widgetLookup[getElIdHelper(this, id, i)])) {
|
||||||
if (!widget) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
widgets.push(widget);
|
widgets.push(widget);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
return widgets;
|
return widgets;
|
||||||
},
|
},
|
||||||
destroy: function () {
|
destroy: function() {
|
||||||
if (this.$__destroyed) {
|
if (this.$__destroyed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -346,25 +242,52 @@ Widget.prototype = widgetProto = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
destroyWidgetHelper(this);
|
this.$__destroyShallow();
|
||||||
},
|
},
|
||||||
isDestroyed: function () {
|
|
||||||
|
$__destroyShallow: function() {
|
||||||
|
if (this.$__destroyed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emitLifecycleEvent(this, 'beforeDestroy');
|
||||||
|
this.$__destroyed = true;
|
||||||
|
|
||||||
|
this.els = null;
|
||||||
|
this.el = null;
|
||||||
|
|
||||||
|
// Unsubscribe from all DOM events
|
||||||
|
this.$__removeDOMEventListeners();
|
||||||
|
|
||||||
|
var subscriptions = this.$__subscriptions;
|
||||||
|
if (subscriptions) {
|
||||||
|
subscriptions.removeAllListeners();
|
||||||
|
this.$__subscriptions = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete widgetLookup[this.id];
|
||||||
|
|
||||||
|
emitLifecycleEvent(this, 'destroy');
|
||||||
|
},
|
||||||
|
|
||||||
|
isDestroyed: function() {
|
||||||
return this.$__destroyed;
|
return this.$__destroyed;
|
||||||
},
|
},
|
||||||
get state() {
|
get state() {
|
||||||
return this.$__state;
|
return this.$__state;
|
||||||
},
|
},
|
||||||
set state(value) {
|
set state(value) {
|
||||||
if(!this.$__state && value) {
|
var state = this.$__state;
|
||||||
|
if(!state && value) {
|
||||||
this.$__state = new this.$__State(this, value);
|
this.$__state = new this.$__State(this, value);
|
||||||
} else {
|
} else {
|
||||||
this.$__state.$__replace(value);
|
state.$__replace(value);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setState: function(name, value) {
|
setState: function(name, value) {
|
||||||
var state = this.$__state;
|
var state = this.$__state;
|
||||||
|
|
||||||
if (typeof name === 'object') {
|
if (typeof name == 'object') {
|
||||||
// Merge in the new state with the old state
|
// Merge in the new state with the old state
|
||||||
var newState = name;
|
var newState = name;
|
||||||
for (var k in newState) {
|
for (var k in newState) {
|
||||||
@ -372,16 +295,15 @@ Widget.prototype = widgetProto = {
|
|||||||
state.$__set(k, newState[k], true /* ensure:true */);
|
state.$__set(k, newState[k], true /* ensure:true */);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
} else {
|
||||||
|
state.$__set(name, value, true /* ensure:true */);
|
||||||
}
|
}
|
||||||
|
|
||||||
state.$__set(name, value, true /* ensure:true */);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setStateDirty: function(name, value) {
|
setStateDirty: function(name, value) {
|
||||||
var state = this.$__state;
|
var state = this.$__state;
|
||||||
|
|
||||||
if (arguments.length === 1) {
|
if (arguments.length == 1) {
|
||||||
value = state[name];
|
value = state[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,25 +323,26 @@ Widget.prototype = widgetProto = {
|
|||||||
* @param {Object} props The widget's new props
|
* @param {Object} props The widget's new props
|
||||||
*/
|
*/
|
||||||
setProps: function(newProps) {
|
setProps: function(newProps) {
|
||||||
if (this.getInitialState) {
|
var onInput = this.onInput;
|
||||||
if (this.getInitialProps) {
|
var getInitialState;
|
||||||
newProps = this.getInitialProps(newProps) || {};
|
|
||||||
|
if (onInput) {
|
||||||
|
onInput.call(this, newProps || {});
|
||||||
|
} else if ((getInitialState = this.getInitialState)) {
|
||||||
|
var getInitialProps = this.getInitialProps;
|
||||||
|
|
||||||
|
if (getInitialProps) {
|
||||||
|
newProps = getInitialProps.call(this, newProps) || {};
|
||||||
|
}
|
||||||
|
var newState = getInitialState.call(this, newProps);
|
||||||
|
this.$__state.$__replace(newState);
|
||||||
|
} else {
|
||||||
|
if (!this.$__newProps) {
|
||||||
|
updateManager.$__queueWidgetUpdate(this);
|
||||||
}
|
}
|
||||||
var newState = this.getInitialState(newProps);
|
|
||||||
this.replaceState(newState);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.onInput) {
|
this.$__newProps = newProps;
|
||||||
this.onInput(newProps || {});
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.$__newProps) {
|
|
||||||
updateManager.$__queueWidgetUpdate(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$__newProps = newProps;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
update: function() {
|
update: function() {
|
||||||
@ -432,18 +355,16 @@ Widget.prototype = widgetProto = {
|
|||||||
var state = this.$__state;
|
var state = this.$__state;
|
||||||
|
|
||||||
if (this.shouldUpdate(newProps, state) === false) {
|
if (this.shouldUpdate(newProps, state) === false) {
|
||||||
resetWidget(this);
|
this.$__reset();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newProps) {
|
if (newProps) {
|
||||||
resetWidget(this);
|
this.$__reset();
|
||||||
this.rerender(newProps);
|
this.rerender(newProps);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (!state.$__dirty) {
|
if (!state.$__dirty) {
|
||||||
// Don't even bother trying to update this widget since it is
|
// Don't even bother trying to update this widget since it is
|
||||||
// not marked as dirty.
|
// not marked as dirty.
|
||||||
@ -458,7 +379,7 @@ Widget.prototype = widgetProto = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reset all internal properties for tracking state changes, etc.
|
// Reset all internal properties for tracking state changes, etc.
|
||||||
resetWidget(this);
|
this.$__reset();
|
||||||
},
|
},
|
||||||
|
|
||||||
$__replaceState: function(newState) {
|
$__replaceState: function(newState) {
|
||||||
@ -478,19 +399,16 @@ Widget.prototype = widgetProto = {
|
|||||||
return this.$__state.$__dirty;
|
return this.$__state.$__dirty;
|
||||||
},
|
},
|
||||||
|
|
||||||
$__reset: function(shouldRemoveDOMEventListeners) {
|
$__reset: function() {
|
||||||
resetWidget(this);
|
this.$__newProps = null;
|
||||||
|
this.$__state.$__reset();
|
||||||
if (shouldRemoveDOMEventListeners) {
|
|
||||||
removeDOMEventListeners(this);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
shouldUpdate: function(newState, newProps) {
|
shouldUpdate: function(newState, newProps) {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
doUpdate: function (stateChanges, oldState) {
|
doUpdate: function() {
|
||||||
this.rerender();
|
this.rerender();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -500,33 +418,32 @@ Widget.prototype = widgetProto = {
|
|||||||
|
|
||||||
rerender: function(props) {
|
rerender: function(props) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
if (!self.renderer) {
|
|
||||||
throw Error('No renderer');
|
|
||||||
}
|
|
||||||
|
|
||||||
var renderer = self.renderer;
|
var renderer = self.renderer;
|
||||||
|
|
||||||
|
if (!renderer) {
|
||||||
|
throw TypeError();
|
||||||
|
}
|
||||||
|
|
||||||
var state = self.$__state;
|
var state = self.$__state;
|
||||||
|
|
||||||
var globalData = {};
|
var globalData = {};
|
||||||
globalData.$w = [self, !props && state && state.$__raw];
|
globalData.$w = [self, !props && state && state.$__raw];
|
||||||
|
|
||||||
var fromEls = getRootEls(self, {});
|
var fromEls = self.$__getRootEls({});
|
||||||
var doc = self.$__document;
|
var doc = self.$__document;
|
||||||
|
|
||||||
updateManager.$__batchUpdate(function() {
|
updateManager.$__batchUpdate(function() {
|
||||||
var createOut = renderer.createOut || marko.createOut;
|
var createOut = renderer.createOut || marko.createOut;
|
||||||
var out = createOut(globalData);
|
var out = createOut(globalData);
|
||||||
|
out.$__document = self.$__document;
|
||||||
renderer(props, out);
|
renderer(props, out);
|
||||||
var result = new RenderResult(out);
|
var result = new RenderResult(out);
|
||||||
|
var targetNode = out.$__getOutput();
|
||||||
var targetNode = out.getOutput();
|
|
||||||
|
|
||||||
var widgetsContext = out.global.widgets;
|
var widgetsContext = out.global.widgets;
|
||||||
|
|
||||||
function onNodeDiscarded(node) {
|
function onNodeDiscarded(node) {
|
||||||
if (node.nodeType === 1) {
|
if (node.nodeType == 1) {
|
||||||
destroyWidgetForEl(node);
|
destroyWidgetForEl(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -535,20 +452,6 @@ Widget.prototype = widgetProto = {
|
|||||||
var id = fromEl.id;
|
var id = fromEl.id;
|
||||||
var existingWidget;
|
var existingWidget;
|
||||||
|
|
||||||
var preservedAttrs = !out.isVDOM && toEl.getAttribute('data-preserve-attrs');
|
|
||||||
if (preservedAttrs) {
|
|
||||||
preservedAttrs = preservedAttrs.split(/\s*[,]\s*/);
|
|
||||||
for (var i=0; i<preservedAttrs.length; i++) {
|
|
||||||
var preservedAttrName = preservedAttrs[i];
|
|
||||||
var preservedAttrValue = fromEl.getAttribute(preservedAttrName);
|
|
||||||
if (preservedAttrValue == null) {
|
|
||||||
toEl.removeAttribute(preservedAttrName);
|
|
||||||
} else {
|
|
||||||
toEl.setAttribute(preservedAttrName, preservedAttrValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (widgetsContext && id) {
|
if (widgetsContext && id) {
|
||||||
var preserved = widgetsContext.$__preserved[id];
|
var preserved = widgetsContext.$__preserved[id];
|
||||||
|
|
||||||
@ -558,12 +461,12 @@ Widget.prototype = widgetProto = {
|
|||||||
// the morphing will take place when the reused widget updates.
|
// the morphing will take place when the reused widget updates.
|
||||||
return MORPHDOM_SKIP;
|
return MORPHDOM_SKIP;
|
||||||
} else {
|
} else {
|
||||||
existingWidget = markoWidgets.getWidgetForEl(fromEl);
|
existingWidget = getWidgetForEl(fromEl);
|
||||||
if (existingWidget && !hasCompatibleWidget(widgetsContext, existingWidget)) {
|
if (existingWidget && !hasCompatibleWidget(widgetsContext, existingWidget)) {
|
||||||
// We found a widget in an old DOM node that does not have
|
// We found a widget in an old DOM node that does not have
|
||||||
// a compatible widget that was rendered so we need to
|
// a compatible widget that was rendered so we need to
|
||||||
// destroy the old widget
|
// destroy the old widget
|
||||||
destroyWidgetHelper(existingWidget);
|
existingWidget.$__destroyShallow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -612,9 +515,38 @@ Widget.prototype = widgetProto = {
|
|||||||
// widget was queued for update and the re-rendered
|
// widget was queued for update and the re-rendered
|
||||||
// before the update occurred then nothing will happen
|
// before the update occurred then nothing will happen
|
||||||
// at the time of the update.
|
// at the time of the update.
|
||||||
resetWidget(self);
|
self.$__reset();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
$__getRootEls: function(rootEls) {
|
||||||
|
var i, len;
|
||||||
|
|
||||||
|
var widgetEls = this.els;
|
||||||
|
|
||||||
|
for (i=0, len=widgetEls.length; i<len; i++) {
|
||||||
|
var widgetEl = widgetEls[i];
|
||||||
|
rootEls[widgetEl.id] = widgetEl;
|
||||||
|
}
|
||||||
|
|
||||||
|
var rootWidgets = this.$__rootWidgets;
|
||||||
|
if (rootWidgets) {
|
||||||
|
for (i=0, len=rootWidgets.length; i<len; i++) {
|
||||||
|
var rootWidget = rootWidgets[i];
|
||||||
|
rootWidget.$__getRootEls(rootEls);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rootEls;
|
||||||
|
},
|
||||||
|
|
||||||
|
$__removeDOMEventListeners: function() {
|
||||||
|
var eventListenerHandles = this.$__domEventListenerHandles;
|
||||||
|
if (eventListenerHandles) {
|
||||||
|
eventListenerHandles.forEach(removeListener);
|
||||||
|
this.$__domEventListenerHandles = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -639,7 +571,7 @@ domInsert(
|
|||||||
}
|
}
|
||||||
return fragment;
|
return fragment;
|
||||||
} else {
|
} else {
|
||||||
return this.els[0];
|
return els[0];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function afterInsert(widget) {
|
function afterInsert(widget) {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user