mirror of
https://github.com/marko-js/marko.git
synced 2025-12-08 19:26:05 +00:00
Merge of marko-vdom completed
This commit is contained in:
parent
35842ba70d
commit
32bacb7002
@ -9,4 +9,6 @@
|
||||
.DS_Store
|
||||
.vscode
|
||||
coverage
|
||||
.nvmrc
|
||||
.nvmrc
|
||||
/benchmark
|
||||
/.cache
|
||||
20
benchmark/patch-module.js
Normal file
20
benchmark/patch-module.js
Normal file
@ -0,0 +1,20 @@
|
||||
var nodePath = require('path');
|
||||
|
||||
var Module = require('module').Module;
|
||||
var oldResolveFilename = Module._resolveFilename;
|
||||
|
||||
var rootDir = nodePath.join(__dirname, '../');
|
||||
|
||||
Module._resolveFilename = function(request, parent, isMain) {
|
||||
if (request.charAt(0) !== '.') {
|
||||
var firstSlash = request.indexOf('/');
|
||||
var targetPackageName = firstSlash === -1 ? request : request.substring(0, firstSlash);
|
||||
|
||||
if (targetPackageName === 'marko') {
|
||||
request = request.substring('marko'.length);
|
||||
request = rootDir + request;
|
||||
}
|
||||
}
|
||||
|
||||
return oldResolveFilename.call(this, request, parent, isMain);
|
||||
};
|
||||
@ -1,4 +1,4 @@
|
||||
window.registerBenchmark('create', function(app) {
|
||||
module.exports = function(app) {
|
||||
var Suite = window.Benchmark.Suite;
|
||||
|
||||
var names = [
|
||||
@ -53,4 +53,4 @@ window.registerBenchmark('create', function(app) {
|
||||
|
||||
return promiseChain;
|
||||
};
|
||||
});
|
||||
};
|
||||
@ -1,6 +1,6 @@
|
||||
window.registerBenchmark('walk', function(app) {
|
||||
module.exports = function(app) {
|
||||
var Suite = window.Benchmark.Suite;
|
||||
var MarkoVDOM = window.MarkoVDOM;
|
||||
var MarkoVDOM = app.vdom;
|
||||
|
||||
var suite = new Suite('walk');
|
||||
|
||||
@ -91,4 +91,4 @@ window.registerBenchmark('walk', function(app) {
|
||||
return function() {
|
||||
return app.runSuite(suite);
|
||||
};
|
||||
});
|
||||
};
|
||||
11
benchmark/vdom/browser.json
Normal file
11
benchmark/vdom/browser.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "js",
|
||||
"url": "https://unpkg.com/react@15.3.1/dist/react.min.js"
|
||||
},
|
||||
"lodash/lodash.js",
|
||||
"benchmark/benchmark.js",
|
||||
"require-run: ./client.js"
|
||||
]
|
||||
}
|
||||
122
benchmark/vdom/client.js
Normal file
122
benchmark/vdom/client.js
Normal file
@ -0,0 +1,122 @@
|
||||
var HTMLElement = require('../../runtime/vdom/HTMLElement');
|
||||
var Text = require('../../runtime/vdom/Text');
|
||||
var Comment = require('../../runtime/vdom/Comment');
|
||||
var DocumentFragment = require('../../runtime/vdom/DocumentFragment');
|
||||
|
||||
var resultsEl = document.getElementById('results');
|
||||
var running = false;
|
||||
var benchmarks = {};
|
||||
|
||||
function loadScript(path) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var script = document.createElement('script');
|
||||
script.src = path;
|
||||
script.onload = function () {
|
||||
resolve();
|
||||
};
|
||||
|
||||
script.onerror = function(e) {
|
||||
reject(e);
|
||||
};
|
||||
|
||||
document.head.appendChild(script); //or something of the likes
|
||||
});
|
||||
}
|
||||
|
||||
function loadScripts(paths) {
|
||||
return Promise.all(paths.map(function(path) {
|
||||
return loadScript(path);
|
||||
}));
|
||||
}
|
||||
|
||||
function runSuite(suite) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (running) {
|
||||
return;
|
||||
}
|
||||
|
||||
running = true;
|
||||
|
||||
suite
|
||||
.on('start', function(event) {
|
||||
resultsEl.innerHTML += 'Running "' + suite.name + '"...\n';
|
||||
})
|
||||
.on('cycle', function(event) {
|
||||
resultsEl.innerHTML += String(event.target) + '\n';
|
||||
})
|
||||
.on('complete', function() {
|
||||
resultsEl.innerHTML += 'Fastest is ' + this.filter('fastest').map('name') + '\n\n--------------\n\n';
|
||||
|
||||
running = false;
|
||||
|
||||
suite.off('start cycle complete');
|
||||
resolve();
|
||||
})
|
||||
.on('error', function(e) {
|
||||
running = false;
|
||||
|
||||
suite.off('start cycle complete error');
|
||||
reject(e.target.error);
|
||||
})
|
||||
// run async
|
||||
.run({ 'async': true });
|
||||
});
|
||||
}
|
||||
|
||||
var vdom = window.MarkoVDOM = {
|
||||
virtualize: require('../../runtime/vdom/virtualize'),
|
||||
|
||||
createElement: function(tagName, attrs, childCount, constId) {
|
||||
return new HTMLElement(tagName, attrs, childCount, constId);
|
||||
},
|
||||
createText: function(value) {
|
||||
return new Text(value);
|
||||
},
|
||||
createComment: function(value) {
|
||||
return new Comment(value);
|
||||
},
|
||||
createDocumentFragment: function() {
|
||||
return new DocumentFragment();
|
||||
}
|
||||
};
|
||||
|
||||
var app = {
|
||||
loadScript,
|
||||
loadScripts,
|
||||
runSuite,
|
||||
vdom
|
||||
};
|
||||
|
||||
function registerBenchmark(name, func) {
|
||||
benchmarks[name] = func(app);
|
||||
}
|
||||
|
||||
registerBenchmark('create', require('./benchmark-create'));
|
||||
registerBenchmark('walk', require('./benchmark-walk'));
|
||||
|
||||
document.body.addEventListener('click', function(event) {
|
||||
if (running) {
|
||||
return;
|
||||
}
|
||||
var target = event.target;
|
||||
var benchmarkName = target.getAttribute('data-benchmark');
|
||||
if (benchmarkName) {
|
||||
var oldButtonLabel = target.innerHTML;
|
||||
target.innerHTML = oldButtonLabel + ' - running...';
|
||||
resultsEl.innerHTML = '';
|
||||
|
||||
var benchmarkFunc = benchmarks[benchmarkName];
|
||||
|
||||
benchmarkFunc()
|
||||
.then(function() {
|
||||
target.innerHTML = oldButtonLabel;
|
||||
|
||||
resultsEl.innerHTML += '\nDONE!';
|
||||
})
|
||||
.catch(function(e) {
|
||||
target.innerHTML = oldButtonLabel;
|
||||
console.error(e);
|
||||
resultsEl.innerHTML = e.toString();
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -1,8 +1,11 @@
|
||||
<lasso-page package-path="./browser.json"/>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>marko-vdom benchmarks</title>
|
||||
<lasso-head/>
|
||||
</head>
|
||||
<body>
|
||||
<button type="button" data-benchmark="walk">
|
||||
@ -90,12 +93,6 @@
|
||||
</footer>
|
||||
</div>
|
||||
</section>
|
||||
<script src="https://unpkg.com/react@15.3.1/dist/react.min.js"></script>
|
||||
<script src="../dist/marko-vdom-umd.js"></script>
|
||||
<script src="../node_modules/lodash/lodash.js"></script>
|
||||
<script src="../node_modules/benchmark/benchmark.js"></script>
|
||||
<script src="./app.js"></script>
|
||||
<script src="./benchmark-walk.js"></script>
|
||||
<script src="./benchmark-create.js"></script>
|
||||
<lasso-body/>
|
||||
</body>
|
||||
</html>
|
||||
27
benchmark/vdom/index.marko.js
Normal file
27
benchmark/vdom/index.marko.js
Normal file
@ -0,0 +1,27 @@
|
||||
function create(__markoHelpers) {
|
||||
var __browser_json = require.resolve("./browser.json"),
|
||||
marko_loadTag = __markoHelpers.t,
|
||||
lasso_page_tag = marko_loadTag(require("lasso/taglib/page-tag")),
|
||||
lasso_head_tag = marko_loadTag(require("lasso/taglib/head-tag")),
|
||||
lasso_body_tag = marko_loadTag(require("lasso/taglib/body-tag"));
|
||||
|
||||
return function render(data, out) {
|
||||
lasso_page_tag({
|
||||
packagePath: __browser_json,
|
||||
dirname: __dirname,
|
||||
filename: __filename
|
||||
}, out);
|
||||
|
||||
out.w("<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><title>marko-vdom benchmarks</title>");
|
||||
|
||||
lasso_head_tag({}, out);
|
||||
|
||||
out.w("</head><body><button type=\"button\" data-benchmark=\"walk\">Run benchmark: walk</button><button type=\"button\" data-benchmark=\"create\">Run benchmark: create</button><pre id=\"results\" style=\"width: 100%; border: 1px solid black;\">\n </pre><section id=\"todoapp\" style=\"display: none\"><div id=\"w0\"><header id=\"header\"><h1>todos</h1><form data-w-onsubmit=\"handleFormSubmit|header\"><input id=\"new-todo\" placeholder=\"What needs to be done?\"></form></header><section id=\"main\"><input id=\"toggle-all\" type=\"checkbox\" data-w-onchange=\"handleToggleAllOnChange|main\"><label for=\"toggle-all\">Mark all as complete</label><ul id=\"todo-list\"><li id=\"main-todo-0\"><div class=\"view\"><input class=\"toggle\" type=\"checkbox\" aria-label=\"Toggle todo completed\" data-w-onchange=\"handleCheckboxChange|main-todo-0\"><label data-w-ondblclick=\"handleLabelDblClick|main-todo-0\">Go to the grocery store</label><button class=\"destroy\" aria-label=\"Delete todo\" data-w-onclick=\"handleDestroyClick|main-todo-0\"></button></div><input title=\"Enter the new todo title\" type=\"text\" class=\"edit\" id=\"main-todo-0-titleInput\" data-w-onchange=\"handleInputChange|main-todo-0\" data-w-onkeydown=\"handleInputKeyDown|main-todo-0\"></li><li class=\"completed\" id=\"main-todo-1\"><div class=\"view\"><input class=\"toggle\" type=\"checkbox\" checked=\"\" aria-label=\"Toggle todo completed\" data-w-onchange=\"handleCheckboxChange|main-todo-1\"><label data-w-ondblclick=\"handleLabelDblClick|main-todo-1\">Ship item</label><button class=\"destroy\" aria-label=\"Delete todo\" data-w-onclick=\"handleDestroyClick|main-todo-1\"></button></div><input title=\"Enter the new todo title\" type=\"text\" class=\"edit\" id=\"main-todo-1-titleInput\" data-w-onchange=\"handleInputChange|main-todo-1\" data-w-onkeydown=\"handleInputKeyDown|main-todo-1\"></li><li id=\"main-todo-2\"><div class=\"view\"><input class=\"toggle\" type=\"checkbox\" aria-label=\"Toggle todo completed\" data-w-onchange=\"handleCheckboxChange|main-todo-2\"><label data-w-ondblclick=\"handleLabelDblClick|main-todo-2\">Respond to email</label><button class=\"destroy\" aria-label=\"Delete todo\" data-w-onclick=\"handleDestroyClick|main-todo-2\"></button></div><input title=\"Enter the new todo title\" type=\"text\" class=\"edit\" id=\"main-todo-2-titleInput\" data-w-onchange=\"handleInputChange|main-todo-2\" data-w-onkeydown=\"handleInputKeyDown|main-todo-2\"></li><li id=\"main-todo-3\"><div class=\"view\"><input class=\"toggle\" type=\"checkbox\" aria-label=\"Toggle todo completed\" data-w-onchange=\"handleCheckboxChange|main-todo-3\"><label data-w-ondblclick=\"handleLabelDblClick|main-todo-3\">Foo</label><button class=\"destroy\" aria-label=\"Delete todo\" data-w-onclick=\"handleDestroyClick|main-todo-3\"></button></div><input title=\"Enter the new todo title\" type=\"text\" class=\"edit\" id=\"main-todo-3-titleInput\" data-w-onchange=\"handleInputChange|main-todo-3\" data-w-onkeydown=\"handleInputKeyDown|main-todo-3\"></li><li id=\"main-todo-4\"><div class=\"view\"><input class=\"toggle\" type=\"checkbox\" aria-label=\"Toggle todo completed\" data-w-onchange=\"handleCheckboxChange|main-todo-4\"><label data-w-ondblclick=\"handleLabelDblClick|main-todo-4\">Bar</label><button class=\"destroy\" aria-label=\"Delete todo\" data-w-onclick=\"handleDestroyClick|main-todo-4\"></button></div><input title=\"Enter the new todo title\" type=\"text\" class=\"edit\" id=\"main-todo-4-titleInput\" data-w-onchange=\"handleInputChange|main-todo-4\" data-w-onkeydown=\"handleInputKeyDown|main-todo-4\"></li><li id=\"main-todo-5\"><div class=\"view\"><input class=\"toggle\" type=\"checkbox\" aria-label=\"Toggle todo completed\" data-w-onchange=\"handleCheckboxChange|main-todo-5\"><label data-w-ondblclick=\"handleLabelDblClick|main-todo-5\">Baz</label><button class=\"destroy\" aria-label=\"Delete todo\" data-w-onclick=\"handleDestroyClick|main-todo-5\"></button></div><input title=\"Enter the new todo title\" type=\"text\" class=\"edit\" id=\"main-todo-5-titleInput\" data-w-onchange=\"handleInputChange|main-todo-5\" data-w-onkeydown=\"handleInputKeyDown|main-todo-5\"></li></ul></section><footer id=\"footer\"><span id=\"todo-count\"><strong>5</strong> items left</span><ul id=\"filters\"><li><a href=\"#/\" class=\"selected\" data-w-onclick=\"handleAllFilterClick|footer\">All</a></li><li><a href=\"#/active\" data-w-onclick=\"handleActiveFilterClick|footer\">Active</a></li><li><a href=\"#/completed\" data-w-onclick=\"handleCompletedFilterClick|footer\">Completed</a></li></ul><button id=\"clear-completed\" data-w-onclick=\"handleClearCompletedClick|footer\">Clear completed (1)</button></footer></div></section>");
|
||||
|
||||
lasso_body_tag({}, out);
|
||||
|
||||
out.w("</body></html>");
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = require("marko/html").c(__filename, create);
|
||||
35
benchmark/vdom/run.js
Normal file
35
benchmark/vdom/run.js
Normal file
@ -0,0 +1,35 @@
|
||||
require('../patch-module');
|
||||
|
||||
require('marko/node-require');
|
||||
require('marko/express');
|
||||
|
||||
require('lasso').configure({
|
||||
outputDir: __dirname + '/static',
|
||||
bundlingEnabled: false
|
||||
});
|
||||
|
||||
var express = require('express');
|
||||
|
||||
var app = express();
|
||||
|
||||
var serveStatic = require('serve-static');
|
||||
|
||||
require('./codegen-create/run');
|
||||
|
||||
var template = require('./index.marko');
|
||||
|
||||
app.use('/codegen-create', serveStatic(__dirname + '/codegen-create'));
|
||||
|
||||
app.use(require('lasso/middleware').serveStatic());
|
||||
|
||||
app.get('/', function(req, res) {
|
||||
res.marko(template);
|
||||
});
|
||||
|
||||
app.listen(8080, function(err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
console.log('Server ready:\nhttp://localhost:8080');
|
||||
});
|
||||
13
marko-vdom/.gitignore
vendored
13
marko-vdom/.gitignore
vendored
@ -1,13 +0,0 @@
|
||||
/work
|
||||
/build
|
||||
/.idea/
|
||||
/npm-debug.log
|
||||
/node_modules
|
||||
/*.sublime-workspace
|
||||
*.orig
|
||||
.DS_Store
|
||||
.vscode
|
||||
coverage
|
||||
.nvmrc
|
||||
~*
|
||||
/dist
|
||||
@ -1,40 +0,0 @@
|
||||
{
|
||||
"predef": [
|
||||
|
||||
],
|
||||
|
||||
"globals": {
|
||||
"define": true,
|
||||
"require": true
|
||||
},
|
||||
|
||||
"node" : true,
|
||||
"esnext" : true,
|
||||
"browser" : false,
|
||||
"boss" : false,
|
||||
"curly": false,
|
||||
"debug": false,
|
||||
"devel": false,
|
||||
"eqeqeq": true,
|
||||
"evil": true,
|
||||
"forin": false,
|
||||
"immed": true,
|
||||
"laxbreak": false,
|
||||
"newcap": true,
|
||||
"noarg": true,
|
||||
"noempty": false,
|
||||
"nonew": true,
|
||||
"nomen": false,
|
||||
"onevar": false,
|
||||
"plusplus": false,
|
||||
"regexp": false,
|
||||
"undef": true,
|
||||
"sub": false,
|
||||
"white": false,
|
||||
"eqeqeq": false,
|
||||
"latedef": false,
|
||||
"unused": "vars",
|
||||
"jquery": true,
|
||||
"strict": false,
|
||||
"eqnull": true
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
/work
|
||||
/build
|
||||
/.idea/
|
||||
/npm-debug.log
|
||||
/node_modules
|
||||
/*.sublime-workspace
|
||||
*.orig
|
||||
.DS_Store
|
||||
.vscode
|
||||
coverage
|
||||
.nvmrc
|
||||
~*
|
||||
/test
|
||||
@ -1,8 +0,0 @@
|
||||
sudo: false
|
||||
node_js:
|
||||
- "4"
|
||||
- "5"
|
||||
- "6"
|
||||
language: node_js
|
||||
script: "npm run test-coverage"
|
||||
after_success: "npm run coveralls"
|
||||
@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Patrick Steele-Idem <pnidem@gmail.com> (psteeleidem.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@ -1,320 +0,0 @@
|
||||
marko-vdom
|
||||
==========
|
||||
|
||||
This module provides an optimized virtual DOM implementation where each virtual DOM node is API compatible with real DOM nodes for the minimal subset that is required to support DOM diffing/patching using [morphdom](https://github.com/patrick-steele-idem/morphdom).
|
||||
|
||||
[](https://travis-ci.org/marko-js/marko-vdom)
|
||||
[](https://coveralls.io/github/marko-js/marko-vdom?branch=master)
|
||||
[](https://www.npmjs.com/package/marko-vdom)
|
||||
|
||||
# Overview
|
||||
|
||||
Each virtual DOM node supports the following properties and methods required by [morphdom](https://github.com/patrick-steele-idem/morphdom):
|
||||
|
||||
- `node.firstChild`
|
||||
- `node.nextSibling`
|
||||
- `node.nodeType`
|
||||
- `node.nodeName`
|
||||
- `node.namespaceURI`
|
||||
- `node.nodeValue`
|
||||
- `node.attributes` <sup><a href="#attributes">[1]</a><sup>
|
||||
- `node.value`
|
||||
- `node.selected`
|
||||
- `node.disabled`
|
||||
- `node.actualize(document)` <sup><a href="#actualize">[2]</a><sup>
|
||||
- `node.hasAttributeNS(namespaceURI, name)`
|
||||
- `node.isSameNode(anotherNode)` <sup><a href="#isSameNode">[3]</a><sup>
|
||||
- `node.assignAttributes(targetNode)` <sup><a href="#assignAttributes">[4]</a><sup>
|
||||
|
||||
NOTES:
|
||||
|
||||
1. <a name="attributes"></a>Unlike with real DOM nodes, `node.attributes` can either be an `Array` of [Attr](https://developer.mozilla.org/en-US/docs/Web/API/Attr) objects or an `Object` (where each property represents an attribute. e.g., `{ "class": "foo", "id": "bar" }`)
|
||||
2. <a name="actualize"></a>In addition to the standard DOM node methods and properties, a virtual DOM node must also provide a `node.actualize(document)` method. The `node.actualize(document)` will be called when the virtual DOM node needs to be upgraded to a real DOM node so that it can be moved into the real DOM.
|
||||
3. <a name="isSameNode"></a>A virtual DOM node may choose to implement `isSameNode(anotherNode)` to short-circuit diffing/patching a particular DOM subtree by treating two nodes as the "same"
|
||||
4. <a name="assignAttributes"></a>A virtual DOM node may choose to implement the non-standard `assignAttributes(targetNode)` to optimize copying the attributes from the virtual DOM node to the target DOM node
|
||||
|
||||
`marko-vdom` is namespace aware and will work correctly with SVG and MathML elements.
|
||||
|
||||
While `marko-vdom` exposes an API that can be used directly, the terse API is designed to be used with a compiler that generates JavaScript code.
|
||||
|
||||
# Usage
|
||||
|
||||
## Create an element with a fixed number of attributes and a fixed number of children
|
||||
|
||||
```javascript
|
||||
var createElement = require('marko-vdom').createElement;
|
||||
|
||||
createElement('div', { class: 'foo', onclick: 'doSomething()' }, 2 /* childCount */)
|
||||
.e('span', null, 1)
|
||||
.e('b', null, 1)
|
||||
.t('Hello World!')
|
||||
.e('a', { href: 'http://ebay.com' }, 1)
|
||||
.t('eBay')
|
||||
```
|
||||
|
||||
The above code will generate a virtual DOM tree that mirrors the following:
|
||||
|
||||
```html
|
||||
<div class="foo" onclick="doSomething()">
|
||||
<span>
|
||||
<b>Hello World!</b>
|
||||
</span>
|
||||
<a href="http://ebay.com">eBay</a>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Dynamic HTML with a unknown number of children
|
||||
|
||||
```javascript
|
||||
var createElement = require('marko-vdom').createElement;
|
||||
|
||||
var el = createElement('div', { class: 'foo' });
|
||||
el.appendChild(createElement('span', { class: 'bar' }));
|
||||
```
|
||||
|
||||
The above code will generate a virtual DOM tree that mirrors the following:
|
||||
|
||||
```html
|
||||
<div class="foo">
|
||||
<span class="bar"></span>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Static subtree
|
||||
|
||||
```javascript
|
||||
var createElement = require('marko-vdom').createElement;
|
||||
|
||||
var staticLink = createElement('a', { href: 'http://ebay.com' }, 1 /* childCount */, 'abc123' /* key */)
|
||||
.t('eBay')
|
||||
|
||||
function render() {
|
||||
createElement('div', null, 1 /* childCount */)
|
||||
.n(staticLink);
|
||||
}
|
||||
```
|
||||
|
||||
The above code will generate a virtual DOM tree that, when converted to a real DOM, will be the following:
|
||||
|
||||
```html
|
||||
<div>
|
||||
<a href="http://ebay.com" data-marko-same-id="abc123">
|
||||
eBay
|
||||
</a>
|
||||
</div>
|
||||
```
|
||||
|
||||
For the static link, both the virtual DOM node and the real DOM node will be marked with an "id" that identifies the two nodes as the "same" node in order to short-circuit DOM/diffing patching. That is:
|
||||
|
||||
```javascript
|
||||
var realStaticLink = staticLink.actualize(document);
|
||||
console.log(staticLink.isSameNode(realStaticLink)); //Output: true
|
||||
```
|
||||
|
||||
## Document fragments
|
||||
|
||||
Document fragments are containers for child nodes that can be appended as children nodes, but the actual `DocumentFragment` node is never directly visited when walking the DOM using `node.firstChild` and `node.nextSibling`. Instead, the children (if any) of a `DocumentFragment` node are treated as direct children of the parent of the `DocumentFragment` node. A `DocumentFragment` node can be modified with new children even after it has been inserted into the DOM.
|
||||
|
||||
```javascript
|
||||
var createElement = require('marko-vdom').createElement;
|
||||
|
||||
var div = createElement('div');
|
||||
documentFragment.appendChild(createElement('div'));
|
||||
|
||||
var documentFragment = div.appendDocumentFragment();
|
||||
documentFragment.appendChild(createElement('span', { class: 'foo' }));
|
||||
documentFragment.appendChild(createElement('span', { class: 'bar' }));
|
||||
|
||||
/*
|
||||
|
||||
Output DOM:
|
||||
|
||||
<div>
|
||||
<span class="foo"></span>
|
||||
<span class="bar"></span>
|
||||
</div>
|
||||
*/
|
||||
|
||||
```
|
||||
|
||||
<a name="benchmarks"></a>
|
||||
|
||||
# Benchmarks
|
||||
|
||||
This library includes some benchmarks to compare performance with the real DOM (and React). To run the benchmarks:
|
||||
|
||||
```
|
||||
npm run benchmark
|
||||
```
|
||||
|
||||
This will open a web page in your browser that you can use to run a variety of benchmarks.
|
||||
|
||||
We are interested in the following performance characteristics:
|
||||
|
||||
- <b>Creation time</b> - the time it takes to construct a [virtual] DOM tree
|
||||
- <b>Walk time</b> - the time it takes to walk a [virtual] DOM tree using `firstChild` and `nextSibilng`
|
||||
|
||||
We encourage you to run the benchmarks on your machine and in various browsers. If you see any problems with the benchmarks, or if you would like clarifying information please open a Github issue.
|
||||
|
||||
Please see [Benchmark Results](./docs/benchmark-results.md) for more detailed numbers.
|
||||
|
||||
# API
|
||||
|
||||
## `marko-vdom`
|
||||
|
||||
### Methods
|
||||
|
||||
#### `createElement(tagName, attrCount, childCount, key)`
|
||||
|
||||
Returns a new [HTMLElement](#HTMLElement).
|
||||
|
||||
#### `createText(value)`
|
||||
|
||||
Returns a new [Text](#Text).
|
||||
|
||||
#### `createComment(value)`
|
||||
|
||||
Returns a new [Comment](#Comment).
|
||||
|
||||
#### `createAttributes(attrCount)`
|
||||
|
||||
Returns a new [AttributeCollection](#AttributeCollection).
|
||||
|
||||
#### `createDocumentFragment()`
|
||||
|
||||
Returns a new [DocumentFragment](#DocumentFragment)
|
||||
|
||||
---------------
|
||||
|
||||
<a name="AttributeCollection"></a>
|
||||
|
||||
## `AttributeCollection`
|
||||
|
||||
### Methods
|
||||
|
||||
<a name="AttributeCollection-a"></a>
|
||||
|
||||
#### `a(name, value)`
|
||||
|
||||
<a name="AttributeCollection-as"></a>
|
||||
|
||||
#### `as(attributes)`
|
||||
|
||||
---------------
|
||||
|
||||
<a name="Comment"></a>
|
||||
|
||||
## `Comment`
|
||||
|
||||
---------------
|
||||
|
||||
<a name="DocumentFragment"></a>
|
||||
|
||||
## `DocumentFragment`
|
||||
|
||||
---------------
|
||||
|
||||
<a name="HTMLElement"></a>
|
||||
|
||||
## `HTMLElement`
|
||||
|
||||
### Constructors
|
||||
|
||||
#### `HTMLElement(tagName, attrCount, childCount, key)`
|
||||
|
||||
Parameters:
|
||||
|
||||
- __tagName__ - The tag name for the new HTML element (`String`)
|
||||
- __attrCount__ - The number of attributes (if known) (an integer, `null` or `undefined`)
|
||||
- __childCount__ - The number of child nodes (if known) (an integer, `null` or `undefined`)
|
||||
- __key__ - A key for static nodes to use for `isSameNode()` checks
|
||||
|
||||
#### `HTMLElement(htmlElement)`
|
||||
|
||||
Used to do a shallow clone of another `HTMLElement`
|
||||
|
||||
### Properties
|
||||
|
||||
#### `nodeType`
|
||||
|
||||
Always set to `1`
|
||||
|
||||
### Methods
|
||||
|
||||
#### `a(name, value)` : [`Node`](#Node)
|
||||
|
||||
See [AttributeCollection#a](#AttributeCollection-a)
|
||||
|
||||
#### `actualize(document)` : `HTMLElement`
|
||||
|
||||
Converts the virtual `HTMLElement` tree to a real `HTMLElement` tree using the provided `document`.
|
||||
|
||||
#### `as(name, value)` : [`Node`](#Node)
|
||||
|
||||
See [AttributeCollection#a](#AttributeCollection-as)
|
||||
|
||||
#### `appendDocumentFragment()` : [`DocumentFragment`](#DocumentFragment)
|
||||
|
||||
See [Node#appendDocumentFragment](#Node-appendDocumentFragment)
|
||||
|
||||
#### `c(value)` : [`Node`](#Node)
|
||||
|
||||
Shorthand method for creating a [Comment](#Comment) node and appending it as a child.
|
||||
|
||||
#### `cloneNode()` : [`HTMLElement`](#HTMLElement)
|
||||
|
||||
Performs a shallow clone of the node (`nextSibling` and `parentNode` will be `undefined` since a cloned node will always start out as detached)
|
||||
|
||||
#### `e(tagName, attrCount, childCount, key)` : [`Node`](#Node)
|
||||
|
||||
Shorthand method for creating an [HTMLElement](#HTMLElement) node and appending it as a child.
|
||||
|
||||
#### `hasAttributeNS(namespaceURI, name)` : `boolean`
|
||||
|
||||
#### `isSameNode(otherNode)` : `boolean`
|
||||
|
||||
Called by `morphdom` to determine if the target `HTMLElement` (either virtual or real) node is the same as the current node. The `key` passed in to the constructor is used to do determine if the other node is the "same" node. If the other node is a real DOM node then the key is pulled from the `data-markokey` attribute.
|
||||
|
||||
#### `n(node)` : [`Node`](#Node)
|
||||
|
||||
Shorthand method for appending a node as a child. The provided is automatically cloned (using a shallow clone) since it is assumed that this method will be called to append a static/memoized DOM node and the original DOM node should not be modified.
|
||||
|
||||
#### `t(value)` : [`Node`](#Node)
|
||||
|
||||
Shorthand method for creating a [Text](#Text) node and appending it as a child.
|
||||
|
||||
---------------
|
||||
|
||||
<a name="Node"></a>
|
||||
|
||||
## `Node`
|
||||
|
||||
### Properties
|
||||
|
||||
#### `firstChild` : [`Node`](#Node)
|
||||
|
||||
Returns the first child node
|
||||
|
||||
#### `nextSibling` : [`Node`](#Node)
|
||||
|
||||
Returns the next sibling node
|
||||
|
||||
### Methods
|
||||
|
||||
<a name="Node-appendDocumentFragment"></a>
|
||||
|
||||
#### `appendDocumentFragment()` : [`DocumentFragment`](#DocumentFragment)
|
||||
|
||||
Creates and appends a new [DocumentFragment](#DocumentFragment) node and appends it as a child and the newly created [DocumentFragment](#DocumentFragment) node is returned.
|
||||
|
||||
#### `removeChildren()`
|
||||
|
||||
Clears out all child nodes
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
|
||||
<a name="Text"></a>
|
||||
|
||||
## `Text`
|
||||
@ -1,98 +0,0 @@
|
||||
(function() {
|
||||
var resultsEl = document.getElementById('results');
|
||||
var running = false;
|
||||
var benchmarks = {};
|
||||
|
||||
function loadScript(path) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var script = document.createElement('script');
|
||||
script.src = path;
|
||||
script.onload = function () {
|
||||
resolve();
|
||||
};
|
||||
|
||||
script.onerror = function(e) {
|
||||
reject(e);
|
||||
};
|
||||
|
||||
document.head.appendChild(script); //or something of the likes
|
||||
});
|
||||
}
|
||||
|
||||
function loadScripts(paths) {
|
||||
return Promise.all(paths.map(function(path) {
|
||||
return loadScript(path);
|
||||
}));
|
||||
}
|
||||
|
||||
function runSuite(suite) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (running) {
|
||||
return;
|
||||
}
|
||||
|
||||
running = true;
|
||||
|
||||
suite
|
||||
.on('start', function(event) {
|
||||
resultsEl.innerHTML += 'Running "' + suite.name + '"...\n';
|
||||
})
|
||||
.on('cycle', function(event) {
|
||||
resultsEl.innerHTML += String(event.target) + '\n';
|
||||
})
|
||||
.on('complete', function() {
|
||||
resultsEl.innerHTML += 'Fastest is ' + this.filter('fastest').map('name') + '\n\n--------------\n\n';
|
||||
|
||||
running = false;
|
||||
|
||||
suite.off('start cycle complete');
|
||||
resolve();
|
||||
})
|
||||
.on('error', function(e) {
|
||||
running = false;
|
||||
|
||||
suite.off('start cycle complete error');
|
||||
reject(e.target.error);
|
||||
})
|
||||
// run async
|
||||
.run({ 'async': true });
|
||||
});
|
||||
}
|
||||
|
||||
var app = {
|
||||
loadScript,
|
||||
loadScripts,
|
||||
runSuite
|
||||
};
|
||||
|
||||
window.registerBenchmark = function(name, func) {
|
||||
benchmarks[name] = func(app);
|
||||
};
|
||||
|
||||
document.body.addEventListener('click', function(event) {
|
||||
if (running) {
|
||||
return;
|
||||
}
|
||||
var target = event.target;
|
||||
var benchmarkName = target.getAttribute('data-benchmark');
|
||||
if (benchmarkName) {
|
||||
var oldButtonLabel = target.innerHTML;
|
||||
target.innerHTML = oldButtonLabel + ' - running...';
|
||||
resultsEl.innerHTML = '';
|
||||
|
||||
var benchmarkFunc = benchmarks[benchmarkName];
|
||||
|
||||
benchmarkFunc()
|
||||
.then(function() {
|
||||
target.innerHTML = oldButtonLabel;
|
||||
|
||||
resultsEl.innerHTML += '\nDONE!';
|
||||
})
|
||||
.catch(function(e) {
|
||||
target.innerHTML = oldButtonLabel;
|
||||
console.error(e);
|
||||
resultsEl.innerHTML = e.toString();
|
||||
});
|
||||
}
|
||||
});
|
||||
}());
|
||||
@ -1,5 +0,0 @@
|
||||
var open = require('open');
|
||||
var path = require('path');
|
||||
|
||||
require('./codegen-create/run');
|
||||
open(path.join(__dirname, 'index.html'));
|
||||
@ -1,40 +0,0 @@
|
||||
{
|
||||
"name": "marko-vdom",
|
||||
"version": "1.0.1",
|
||||
"description": "Virtual DOM implementation for use with Marko and/or morphdom",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
"test": "npm run mocha && npm run jshint",
|
||||
"mocha": "mocha --ui bdd --reporter spec ./test/",
|
||||
"mocha-debug": "node-debug _mocha ./test/",
|
||||
"jshint": "jshint src/",
|
||||
"benchmark": "node benchmark/run.js",
|
||||
"test-coverage": "istanbul cover _mocha -- --ui bdd --reporter spec ./test/ && npm run jshint",
|
||||
"coveralls": "cat ./coverage/lcov.info | coveralls",
|
||||
"dist": "mkdir -p dist && browserify src/all.js > dist/marko-vdom-umd.js --standalone MarkoVDOM"
|
||||
},
|
||||
"keywords": [
|
||||
"vdom",
|
||||
"dom",
|
||||
"marko",
|
||||
"morphdom",
|
||||
"virtual",
|
||||
"virtual-dom"
|
||||
],
|
||||
"author": "Patrick Steele-Idem <pnidem@gmail.com>",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"benchmark": "^2.1.1",
|
||||
"chai": "^3.5.0",
|
||||
"coveralls": "^2.11.12",
|
||||
"istanbul": "^0.4.5",
|
||||
"jsdom": "^9.4.2",
|
||||
"jshint": "^2.9.3",
|
||||
"lodash": "^4.15.0",
|
||||
"mocha": "^3.0.2",
|
||||
"open": "0.0.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"raptor-util": "^2.0.0"
|
||||
}
|
||||
}
|
||||
@ -1,2 +0,0 @@
|
||||
module.exports = require('./index');
|
||||
module.exports.virtualize = require('./virtualize');
|
||||
@ -1,27 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var HTMLElement = require('./HTMLElement');
|
||||
var Text = require('./Text');
|
||||
var Comment = require('./Comment');
|
||||
var DocumentFragment = require('./DocumentFragment');
|
||||
|
||||
function createElement(tagName, attrs, childCount, key) {
|
||||
return new HTMLElement(tagName, attrs, childCount, key);
|
||||
}
|
||||
|
||||
function createText(value) {
|
||||
return new Text(value);
|
||||
}
|
||||
|
||||
function createComment(value) {
|
||||
return new Comment(value);
|
||||
}
|
||||
|
||||
function createDocumentFragment() {
|
||||
return new DocumentFragment();
|
||||
}
|
||||
|
||||
exports.createElement = createElement;
|
||||
exports.createText = createText;
|
||||
exports.createComment = createComment;
|
||||
exports.createDocumentFragment = createDocumentFragment;
|
||||
3
marko-vdom/test/.gitignore
vendored
3
marko-vdom/test/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
*-actual*
|
||||
actual.*
|
||||
actualized-expected.html
|
||||
@ -1,43 +0,0 @@
|
||||
{
|
||||
"predef": [
|
||||
"it",
|
||||
"xit",
|
||||
"console",
|
||||
"describe",
|
||||
"xdescribe",
|
||||
"beforeEach",
|
||||
"before",
|
||||
"after",
|
||||
"waits",
|
||||
"waitsFor",
|
||||
"runs"
|
||||
],
|
||||
"node" : true,
|
||||
"es5" : false,
|
||||
"esnext": true,
|
||||
"browser" : true,
|
||||
"boss" : false,
|
||||
"curly": false,
|
||||
"debug": false,
|
||||
"devel": false,
|
||||
"eqeqeq": true,
|
||||
"evil": true,
|
||||
"forin": false,
|
||||
"immed": true,
|
||||
"laxbreak": false,
|
||||
"newcap": true,
|
||||
"noarg": true,
|
||||
"noempty": false,
|
||||
"nonew": true,
|
||||
"nomen": false,
|
||||
"onevar": false,
|
||||
"plusplus": false,
|
||||
"regexp": false,
|
||||
"undef": true,
|
||||
"sub": false,
|
||||
"white": false,
|
||||
"eqeqeq": false,
|
||||
"latedef": false,
|
||||
"unused": "vars",
|
||||
"eqnull": true
|
||||
}
|
||||
@ -1,27 +0,0 @@
|
||||
var path = require('path');
|
||||
var markoVDOM = require('../');
|
||||
var fs = require('fs');
|
||||
var toHTML = require('./util/toHTML');
|
||||
|
||||
var jsdom = require("jsdom").jsdom;
|
||||
var document = jsdom('<html><body></body></html>');
|
||||
|
||||
describe('marko-vdom', () => {
|
||||
require('./util/autotest').scanDir(
|
||||
path.join(__dirname, 'autotests-create'),
|
||||
function(dir, helpers, done) {
|
||||
helpers.vdom = markoVDOM;
|
||||
helpers.document = document;
|
||||
|
||||
var mainPath = path.join(dir, 'index.js');
|
||||
if (fs.existsSync(mainPath)) {
|
||||
var main = require(mainPath);
|
||||
var rootNode = main(helpers);
|
||||
|
||||
var rootNodeHTML = rootNode != null ? toHTML(rootNode) : '(null)';
|
||||
helpers.compare(rootNodeHTML, '.html');
|
||||
}
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
@ -1,75 +0,0 @@
|
||||
var fs = require('fs');
|
||||
var enabledTest = process.env.TEST;
|
||||
var path = require('path');
|
||||
var assert = require('assert');
|
||||
|
||||
|
||||
function compareHelper(dir, actual, prefix, suffix) {
|
||||
var actualPath = path.join(dir, prefix + 'actual' + suffix);
|
||||
var expectedPath = path.join(dir, prefix + 'expected' + suffix);
|
||||
|
||||
var isObject = typeof actual === 'string' ? false : true;
|
||||
var actualString = isObject ? JSON.stringify(actual, null, 4) : actual;
|
||||
fs.writeFileSync(actualPath, actualString, { encoding: 'utf8' });
|
||||
|
||||
var expectedString;
|
||||
|
||||
try {
|
||||
expectedString = fs.readFileSync(expectedPath, { encoding: 'utf8' });
|
||||
} catch(e) {
|
||||
expectedString = isObject ? '"TBD"' : 'TBD';
|
||||
fs.writeFileSync(expectedPath, expectedString, {encoding: 'utf8'});
|
||||
}
|
||||
|
||||
var expected = isObject ? JSON.parse(expectedString) : expectedString;
|
||||
assert.deepEqual(actual, expected);
|
||||
}
|
||||
|
||||
function autoTest(name, dir, run, options, done) {
|
||||
options = options || {};
|
||||
|
||||
var helpers = {
|
||||
compare(actual, prefix, suffix) {
|
||||
if (typeof prefix === 'object') {
|
||||
var options = prefix;
|
||||
suffix = options.suffix;
|
||||
prefix = options.prefix;
|
||||
} else if (arguments.length === 2) {
|
||||
suffix = prefix;
|
||||
prefix = null;
|
||||
}
|
||||
|
||||
compareHelper(dir, actual, prefix || '', suffix || '');
|
||||
},
|
||||
|
||||
readFileSync(relPath) {
|
||||
var fullPath = path.resolve(dir, relPath);
|
||||
return fs.readFileSync(fullPath, { encoding: 'utf8' });
|
||||
}
|
||||
};
|
||||
|
||||
run(dir, helpers, done);
|
||||
}
|
||||
|
||||
exports.scanDir = function(autoTestDir, run, options) {
|
||||
describe('autotest', function() {
|
||||
fs.readdirSync(autoTestDir)
|
||||
.forEach(function(name) {
|
||||
if (name.charAt(0) === '.') {
|
||||
return;
|
||||
}
|
||||
|
||||
var itFunc = it;
|
||||
|
||||
if (enabledTest && name === enabledTest) {
|
||||
itFunc = it.only;
|
||||
}
|
||||
|
||||
var dir = path.join(autoTestDir, name);
|
||||
|
||||
itFunc(`[${name}] `, function(done) {
|
||||
autoTest(name, dir, run, options, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
@ -1 +0,0 @@
|
||||
module.exports = require('./src/virtualize');
|
||||
@ -76,7 +76,7 @@ function getLoadedTemplate(path) {
|
||||
return cached && cached.exports.render ? cached.exports : undefined;
|
||||
}
|
||||
|
||||
exports.install = function(options) {
|
||||
function install(options) {
|
||||
options = options || {};
|
||||
|
||||
var compilerOptions = options.compilerOptions;
|
||||
@ -120,4 +120,8 @@ exports.install = function(options) {
|
||||
// source code that is being loaded. This allows stack traces to match up.
|
||||
module._compile(compiledSrc, targetFile);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
install();
|
||||
|
||||
exports.install = install;
|
||||
|
||||
13
package.json
13
package.json
@ -5,7 +5,15 @@
|
||||
"templating",
|
||||
"template",
|
||||
"async",
|
||||
"streaming"
|
||||
"streaming",
|
||||
"widgets",
|
||||
"components",
|
||||
"ui",
|
||||
"vdom",
|
||||
"dom",
|
||||
"morphdom",
|
||||
"virtual",
|
||||
"virtual-dom"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -37,7 +45,6 @@
|
||||
"dependencies": {
|
||||
"argly": "^1.0.0",
|
||||
"app-module-path": "^1.0.5",
|
||||
"async-vdom-builder": "^1.0.0",
|
||||
"browser-refresh-client": "^1.0.0",
|
||||
"char-props": "~0.1.5",
|
||||
"deresolve": "^1.0.0",
|
||||
@ -69,6 +76,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"async": "^0.9.0",
|
||||
"benchmark": "^2.1.1",
|
||||
"bluebird": "^2.9.30",
|
||||
"browser-refresh": "^1.6.0",
|
||||
"browser-refresh-taglib": "^1.1.0",
|
||||
@ -90,6 +98,7 @@
|
||||
"phantomjs-prebuilt": "^2.1.13",
|
||||
"request": "^2.72.0",
|
||||
"require-self-ref": "^2.0.1",
|
||||
"serve-static": "^1.11.1",
|
||||
"through": "^2.3.4",
|
||||
"through2": "^2.0.1"
|
||||
},
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var dom = require('marko-dom');
|
||||
var markoVdom = require('marko-vdom');
|
||||
var createElement = markoVdom.createElement;
|
||||
var createDocumentFragment = markoVdom.createDocumentFragment;
|
||||
var createComment = markoVdom.createComment;
|
||||
var createText = markoVdom.createText;
|
||||
var virtualize = require('marko-vdom/virtualize');
|
||||
|
||||
var HTMLElement = require('./HTMLElement');
|
||||
var DocumentFragment = require('./DocumentFragment');
|
||||
var Comment = require('./Comment');
|
||||
var Text = require('./Text');
|
||||
|
||||
var virtualize = require('./virtualize');
|
||||
var specialHtmlRegexp = /[&<]/;
|
||||
var defaultDocument = typeof document != 'undefined' && document;
|
||||
|
||||
@ -36,7 +37,7 @@ function State(tree) {
|
||||
|
||||
function AsyncVDOMBuilder(globalData, parentNode, state) {
|
||||
if (!parentNode) {
|
||||
parentNode = createDocumentFragment();
|
||||
parentNode = new DocumentFragment();
|
||||
}
|
||||
|
||||
if (state) {
|
||||
@ -59,7 +60,7 @@ var proto = AsyncVDOMBuilder.prototype = {
|
||||
isAsyncVDOMBuilder: true,
|
||||
|
||||
element: function(name, attrs, childCount) {
|
||||
var element = createElement(name, attrs, childCount);
|
||||
var element = new HTMLElement(name, attrs, childCount);
|
||||
|
||||
var parent = this._parent;
|
||||
|
||||
@ -91,14 +92,14 @@ var proto = AsyncVDOMBuilder.prototype = {
|
||||
if (lastChild && lastChild.nodeType === 3) {
|
||||
lastChild.nodeValue += text;
|
||||
} else {
|
||||
parent.appendChild(createText(text));
|
||||
parent.appendChild(new Text(text));
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
comment: function(comment) {
|
||||
return this.node(createComment(comment));
|
||||
return this.node(new Comment(comment));
|
||||
},
|
||||
|
||||
html: function(html) {
|
||||
@ -125,7 +126,7 @@ var proto = AsyncVDOMBuilder.prototype = {
|
||||
|
||||
var curChild = container.firstChild;
|
||||
if (curChild) {
|
||||
vdomFragment = createDocumentFragment();
|
||||
vdomFragment = new DocumentFragment();
|
||||
while(curChild) {
|
||||
vdomFragment.appendChild(virtualize(curChild));
|
||||
curChild = curChild.nextSibling;
|
||||
@ -141,7 +142,7 @@ var proto = AsyncVDOMBuilder.prototype = {
|
||||
},
|
||||
|
||||
beginElement: function(name, attrs) {
|
||||
var element = createElement(name, attrs);
|
||||
var element = new HTMLElement(name, attrs);
|
||||
var parent = this._parent;
|
||||
if (parent) {
|
||||
parent.appendChild(element);
|
||||
|
||||
@ -16,15 +16,20 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var markoVDOM = require('marko-vdom');
|
||||
var HTMLElement = require('./HTMLElement');
|
||||
var Text = require('./Text');
|
||||
var commonHelpers = require('../helpers');
|
||||
var extend = require('raptor-util/extend');
|
||||
|
||||
var classList = commonHelpers.cl;
|
||||
|
||||
module.exports = extend({
|
||||
e: markoVDOM.createElement,
|
||||
t: markoVDOM.createText,
|
||||
e: function(tagName, attrs, childCount, constId) {
|
||||
return new HTMLElement(tagName, attrs, childCount, constId);
|
||||
},
|
||||
t: function(value) {
|
||||
return new Text(value);
|
||||
},
|
||||
const: function(id) {
|
||||
var i=0;
|
||||
return function() {
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
var markoVDOM = require('./');
|
||||
|
||||
var createElement = markoVDOM.createElement;
|
||||
var createText = markoVDOM.createText;
|
||||
var createComment = markoVDOM.createComment;
|
||||
var createDocumentFragment = markoVDOM.createDocumentFragment;
|
||||
var HTMLElement = require('./HTMLElement');
|
||||
var DocumentFragment = require('./DocumentFragment');
|
||||
var Comment = require('./Comment');
|
||||
var Text = require('./Text');
|
||||
|
||||
function virtualizeChildNodes(node, vdomParent) {
|
||||
var curChild = node.firstChild;
|
||||
@ -40,7 +38,7 @@ function virtualize(node) {
|
||||
}
|
||||
}
|
||||
|
||||
var vdomEL = createElement(node.nodeName, attrs, childCount);
|
||||
var vdomEL = new HTMLElement(node.nodeName, attrs, childCount);
|
||||
|
||||
if (vdomEL._isTextArea) {
|
||||
vdomEL.value = node.value;
|
||||
@ -50,11 +48,11 @@ function virtualize(node) {
|
||||
|
||||
return vdomEL;
|
||||
} else if (node.nodeType === 3) { // Text node
|
||||
return createText(node.nodeValue);
|
||||
return new Text(node.nodeValue);
|
||||
} else if (node.nodeType === 8) { // Text node
|
||||
return createComment(node.nodeValue);
|
||||
return new Comment(node.nodeValue);
|
||||
} else if (node.nodeType === 11) { // DocumentFragment node
|
||||
var vdomDocFragment = createDocumentFragment();
|
||||
var vdomDocFragment = new DocumentFragment();
|
||||
virtualizeChildNodes(node, vdomDocFragment);
|
||||
}
|
||||
}
|
||||
8
test/.gitignore
vendored
8
test/.gitignore
vendored
@ -2,8 +2,10 @@
|
||||
/scratch.js
|
||||
*.generated.js
|
||||
|
||||
actual.js
|
||||
actual.html
|
||||
*.actual.js
|
||||
*.actual.html
|
||||
/generated
|
||||
/generated
|
||||
|
||||
*-actual*
|
||||
actual.*
|
||||
actualized-expected.html
|
||||
@ -52,7 +52,11 @@ function autoTest(name, dir, run, options, done) {
|
||||
|
||||
var helpers = {
|
||||
compare(actual, prefix, suffix) {
|
||||
if (arguments.length === 2) {
|
||||
if (typeof prefix === 'object') {
|
||||
var options = prefix;
|
||||
prefix = options.prefix;
|
||||
suffix = options.suffix;
|
||||
} else if (arguments.length === 2) {
|
||||
suffix = prefix;
|
||||
prefix = null;
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 10 B After Width: | Height: | Size: 10 B |
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