mirror of
https://github.com/marko-js/marko.git
synced 2025-12-08 19:26:05 +00:00
Code size reductions
This commit is contained in:
parent
a34b128f9f
commit
ff5472a034
@ -3,9 +3,13 @@ require('../patch-module');
|
||||
require('marko/node-require');
|
||||
require('marko/express');
|
||||
|
||||
var isProduction = process.env.NODE_ENV === 'production';
|
||||
|
||||
require('lasso').configure({
|
||||
outputDir: __dirname + '/static',
|
||||
bundlingEnabled: false
|
||||
bundlingEnabled: isProduction,
|
||||
fingerprintsEnabled: isProduction,
|
||||
minify: isProduction
|
||||
});
|
||||
|
||||
var express = require('express');
|
||||
|
||||
@ -69,9 +69,7 @@ AsyncStream.enableAsyncStackTrace = function() {
|
||||
|
||||
var proto = AsyncStream.prototype = {
|
||||
constructor: AsyncStream,
|
||||
isAsyncOut: true,
|
||||
isAsyncWriter: AsyncStream, // Legacy
|
||||
isAsyncStream: AsyncStream,
|
||||
isOut: true,
|
||||
|
||||
sync: function() {
|
||||
this._sync = true;
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
'use strict';
|
||||
require('raptor-polyfill/string/startsWith');
|
||||
|
||||
var warp10 = require('warp10');
|
||||
var extend = require('raptor-util/extend');
|
||||
|
||||
@ -69,7 +67,7 @@ function attr(name, value, shouldEscape) {
|
||||
} else if (value == null || value === false) {
|
||||
return '';
|
||||
} else if (typeof value === 'object') {
|
||||
if (name.startsWith('data-_')) {
|
||||
if (name.substring(0, 6) === 'data-_') {
|
||||
value = warp10.stringify(value);
|
||||
} else {
|
||||
value = JSON.stringify(value);
|
||||
|
||||
@ -73,7 +73,7 @@ module.exports = function(target, renderer) {
|
||||
finalData = {};
|
||||
}
|
||||
|
||||
if (out && out.isAsyncOut){
|
||||
if (out && out.isOut){
|
||||
finalOut = out;
|
||||
shouldEnd = false;
|
||||
extend(out.global, globalData);
|
||||
|
||||
@ -7,14 +7,16 @@ var virtualizeHTML = require('./virtualizeHTML');
|
||||
var documentProvider = require('../document-provider');
|
||||
var RenderResult = require('../RenderResult');
|
||||
|
||||
var FLAG_FINISHED = 1;
|
||||
var FLAG_LAST_FIRED = 2;
|
||||
|
||||
function State(tree) {
|
||||
this.remaining = 1;
|
||||
this.events = new EventEmitter();
|
||||
this.tree = tree;
|
||||
this.finished = false;
|
||||
this.last = undefined;
|
||||
this.lastFired = false;
|
||||
this.lastCount = 0;
|
||||
this.$__remaining = 1;
|
||||
this.$__events = new EventEmitter();
|
||||
this.$__tree = tree;
|
||||
this.$__last = undefined;
|
||||
this.$__lastCount = 0;
|
||||
this.$__flags = 0;
|
||||
}
|
||||
|
||||
function AsyncVDOMBuilder(globalData, parentNode, state) {
|
||||
@ -23,27 +25,26 @@ function AsyncVDOMBuilder(globalData, parentNode, state) {
|
||||
}
|
||||
|
||||
if (state) {
|
||||
state.remaining++;
|
||||
state.$__remaining++;
|
||||
} else {
|
||||
state = new State(parentNode);
|
||||
}
|
||||
|
||||
this.data = {};
|
||||
this._state = state;
|
||||
this._parent = parentNode;
|
||||
this.$__state = state;
|
||||
this.$__parent = parentNode;
|
||||
this.global = globalData || {};
|
||||
this._stack = [parentNode];
|
||||
this._sync = false;
|
||||
this.$__stack = [parentNode];
|
||||
this.$__sync = false;
|
||||
}
|
||||
|
||||
var proto = AsyncVDOMBuilder.prototype = {
|
||||
isAsyncOut: true,
|
||||
isAsyncVDOMBuilder: true,
|
||||
isOut: true,
|
||||
|
||||
element: function(name, attrs, childCount) {
|
||||
var element = new HTMLElement(name, attrs, childCount);
|
||||
|
||||
var parent = this._parent;
|
||||
var parent = this.$__parent;
|
||||
|
||||
if(parent) {
|
||||
parent.appendChild(element);
|
||||
@ -59,7 +60,7 @@ var proto = AsyncVDOMBuilder.prototype = {
|
||||
},
|
||||
|
||||
node: function(node) {
|
||||
var parent = this._parent;
|
||||
var parent = this.$__parent;
|
||||
if (parent) {
|
||||
parent.appendChild(node);
|
||||
}
|
||||
@ -83,7 +84,7 @@ var proto = AsyncVDOMBuilder.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
var parent = this._parent;
|
||||
var parent = this.$__parent;
|
||||
if (parent) {
|
||||
var lastChild = parent.lastChild;
|
||||
if (lastChild && lastChild.nodeType === 3) {
|
||||
@ -110,59 +111,59 @@ var proto = AsyncVDOMBuilder.prototype = {
|
||||
|
||||
beginElement: function(name, attrs) {
|
||||
var element = new HTMLElement(name, attrs);
|
||||
var parent = this._parent;
|
||||
var parent = this.$__parent;
|
||||
if (parent) {
|
||||
parent.appendChild(element);
|
||||
this._stack.push(element);
|
||||
this._parent = element;
|
||||
this.$__stack.push(element);
|
||||
this.$__parent = element;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
endElement: function() {
|
||||
var stack = this._stack;
|
||||
var stack = this.$__stack;
|
||||
stack.pop();
|
||||
this._parent = stack[stack.length-1];
|
||||
this.$__parent = stack[stack.length-1];
|
||||
},
|
||||
|
||||
end: function() {
|
||||
var state = this._state;
|
||||
var state = this.$__state;
|
||||
|
||||
this._parent = null;
|
||||
this.$__parent = null;
|
||||
|
||||
var remaining = --state.remaining;
|
||||
var remaining = --state.$__remaining;
|
||||
|
||||
if (!state.lastFired && (remaining - state.lastCount === 0)) {
|
||||
state.lastFired = true;
|
||||
state.lastCount = 0;
|
||||
state.events.emit('last');
|
||||
if (!(state.$__flags & FLAG_LAST_FIRED) && (remaining - state.$__lastCount === 0)) {
|
||||
state.$__flags |= FLAG_LAST_FIRED;
|
||||
state.$__lastCount = 0;
|
||||
state.$__events.emit('last');
|
||||
}
|
||||
|
||||
if (!remaining) {
|
||||
state.finished = true;
|
||||
state.events.emit('finish', this);
|
||||
state.$__flags |= FLAG_FINISHED;
|
||||
state.$__events.emit('finish', this);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
beginAsync: function(options) {
|
||||
if (this._sync) {
|
||||
if (this.$__sync) {
|
||||
throw new Error('beginAsync() not allowed when using renderSync()');
|
||||
}
|
||||
|
||||
var state = this._state;
|
||||
var state = this.$__state;
|
||||
|
||||
if (options) {
|
||||
if (options.last === true) {
|
||||
state.lastCount++;
|
||||
if (options.last) {
|
||||
state.$__lastCount++;
|
||||
}
|
||||
}
|
||||
|
||||
var documentFragment = this._parent.appendDocumentFragment();
|
||||
var documentFragment = this.$__parent.appendDocumentFragment();
|
||||
var asyncOut = new AsyncVDOMBuilder(this.global, documentFragment, state);
|
||||
|
||||
state.events.emit('beginAsync', {
|
||||
state.$__events.emit('beginAsync', {
|
||||
out: asyncOut,
|
||||
parentOut: this
|
||||
});
|
||||
@ -175,12 +176,12 @@ var proto = AsyncVDOMBuilder.prototype = {
|
||||
},
|
||||
|
||||
flush: function() {
|
||||
var state = this._state;
|
||||
state.events.emit('update', this);
|
||||
var state = this.$__state;
|
||||
state.$__events.emit('update', this);
|
||||
},
|
||||
|
||||
getOutput: function() {
|
||||
return this._state.tree;
|
||||
return this.$__state.$__tree;
|
||||
},
|
||||
|
||||
getResult: function() {
|
||||
@ -189,31 +190,31 @@ var proto = AsyncVDOMBuilder.prototype = {
|
||||
},
|
||||
|
||||
on: function(event, callback) {
|
||||
var state = this._state;
|
||||
var state = this.$__state;
|
||||
|
||||
if (event === 'finish' && state.finished) {
|
||||
if (event === 'finish' && (state.$__flags & FLAG_FINISHED)) {
|
||||
callback(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
state.events.on(event, callback);
|
||||
state.$__events.on(event, callback);
|
||||
return this;
|
||||
},
|
||||
|
||||
once: function(event, callback) {
|
||||
var state = this._state;
|
||||
var state = this.$__state;
|
||||
|
||||
if (event === 'finish' && state.finished) {
|
||||
if (event === 'finish' && (state.$__flags & FLAG_FINISHED)) {
|
||||
callback(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
state.events.once(event, callback);
|
||||
state.$__events.once(event, callback);
|
||||
return this;
|
||||
},
|
||||
|
||||
emit: function(type, arg) {
|
||||
var events = this._state.events;
|
||||
var events = this.$__state.$__events;
|
||||
switch(arguments.length) {
|
||||
case 1:
|
||||
events.emit(type);
|
||||
@ -229,32 +230,32 @@ var proto = AsyncVDOMBuilder.prototype = {
|
||||
},
|
||||
|
||||
removeListener: function() {
|
||||
var events = this._state.events;
|
||||
var events = this.$__state.$__events;
|
||||
events.removeListener.apply(events, arguments);
|
||||
return this;
|
||||
},
|
||||
|
||||
prependListener: function() {
|
||||
var events = this._state.events;
|
||||
var events = this.$__state.$__events;
|
||||
events.prependListener.apply(events, arguments);
|
||||
return this;
|
||||
},
|
||||
|
||||
sync: function() {
|
||||
this._sync = true;
|
||||
this.$__sync = true;
|
||||
},
|
||||
|
||||
isSync: function() {
|
||||
return this._sync === true;
|
||||
return this.$__sync;
|
||||
},
|
||||
|
||||
onLast: function(callback) {
|
||||
var state = this._state;
|
||||
var state = this.$__state;
|
||||
|
||||
var lastArray = state.last;
|
||||
var lastArray = state.$__last;
|
||||
|
||||
if (!lastArray) {
|
||||
lastArray = state.last = [];
|
||||
lastArray = state.$__last = [];
|
||||
var i = 0;
|
||||
var next = function next() {
|
||||
if (i === lastArray.length) {
|
||||
@ -285,11 +286,14 @@ var proto = AsyncVDOMBuilder.prototype = {
|
||||
node = vdomTree.actualize(doc);
|
||||
|
||||
if (node.nodeType === 11 /* DocumentFragment */) {
|
||||
// If the DocumentFragment only has one child
|
||||
// then just return that first child as the node
|
||||
var childNodes = node.childNodes;
|
||||
if (childNodes.length === 1) {
|
||||
node = childNodes[0];
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -4,8 +4,8 @@ var extend = require('raptor-util/extend');
|
||||
|
||||
function DocumentFragmentClone(other) {
|
||||
extend(this, other);
|
||||
this.parentNode = undefined;
|
||||
this._nextSibling = undefined;
|
||||
this.$__parentNode = undefined;
|
||||
this.$__nextSibling = undefined;
|
||||
}
|
||||
|
||||
function DocumentFragment(documentFragment) {
|
||||
@ -16,7 +16,7 @@ function DocumentFragment(documentFragment) {
|
||||
DocumentFragment.prototype = {
|
||||
nodeType: 11,
|
||||
|
||||
_nsAware: true,
|
||||
$__nsAware: true,
|
||||
|
||||
cloneNode: function() {
|
||||
return new DocumentFragmentClone(this);
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
require('raptor-polyfill/string/startsWith');
|
||||
var inherit = require('raptor-util/inherit');
|
||||
var extend = require('raptor-util/extend');
|
||||
var Text = require('./Text');
|
||||
@ -12,6 +11,8 @@ var ATTR_HREF = 'href';
|
||||
var EMPTY_OBJECT = require('./util').EMPTY_OBJECT;
|
||||
var ATTR_MARKO_CONST = 'data-marko-const';
|
||||
|
||||
var specialAttrRegexp = /^data-_/;
|
||||
|
||||
function removePreservedAttributes(attrs) {
|
||||
var preservedAttrs = attrs['data-preserve-attrs'];
|
||||
if (preservedAttrs) {
|
||||
@ -37,8 +38,8 @@ function convertAttrValue(type, value) {
|
||||
|
||||
function HTMLElementClone(other) {
|
||||
extend(this, other);
|
||||
this.parentNode = undefined;
|
||||
this._nextSibling = undefined;
|
||||
this.$__parentNode = undefined;
|
||||
this.$__nextSibling = undefined;
|
||||
}
|
||||
|
||||
function HTMLElement(tagName, attrs, childCount, constId) {
|
||||
@ -68,7 +69,7 @@ function HTMLElement(tagName, attrs, childCount, constId) {
|
||||
}
|
||||
|
||||
this.attributes = attrs || EMPTY_OBJECT;
|
||||
this._isTextArea = isTextArea;
|
||||
this.$__isTextArea = isTextArea;
|
||||
this.namespaceURI = namespaceURI;
|
||||
this.nodeName = tagName;
|
||||
this._value = undefined;
|
||||
@ -78,7 +79,7 @@ function HTMLElement(tagName, attrs, childCount, constId) {
|
||||
HTMLElement.prototype = {
|
||||
nodeType: 1,
|
||||
|
||||
_nsAware: true,
|
||||
$__nsAware: true,
|
||||
|
||||
assignAttributes: function(targetNode) {
|
||||
var attrs = this.attributes;
|
||||
@ -154,7 +155,7 @@ HTMLElement.prototype = {
|
||||
targetNode.removeAttribute(attrName);
|
||||
} else if (oldAttrs[attrName] !== attrValue) {
|
||||
|
||||
if (attrName.startsWith('data-_')) {
|
||||
if (specialAttrRegexp.test(attrName)) {
|
||||
// Special attributes aren't copied to the real DOM. They are only
|
||||
// kept in the virtual attributes map
|
||||
continue;
|
||||
@ -201,7 +202,7 @@ HTMLElement.prototype = {
|
||||
var child = this.appendChild(new HTMLElement(tagName, attrs, childCount, constId));
|
||||
|
||||
if (childCount === 0) {
|
||||
return this._finishChild();
|
||||
return this.$__finishChild();
|
||||
} else {
|
||||
return child;
|
||||
}
|
||||
@ -221,13 +222,13 @@ HTMLElement.prototype = {
|
||||
var safeHTML = value.safeHTML;
|
||||
var vdomNode = virtualizeHTML(safeHTML || '', documentProvider.document);
|
||||
this.appendChild(vdomNode);
|
||||
return this._finishChild();
|
||||
return this.$__finishChild();
|
||||
} else {
|
||||
value = value.toString();
|
||||
}
|
||||
}
|
||||
this.appendChild(new Text(value));
|
||||
return this._finishChild();
|
||||
return this.$__finishChild();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -236,7 +237,7 @@ HTMLElement.prototype = {
|
||||
*/
|
||||
c: function(value) {
|
||||
this.appendChild(new Comment(value));
|
||||
return this._finishChild();
|
||||
return this.$__finishChild();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -247,7 +248,7 @@ HTMLElement.prototype = {
|
||||
*/
|
||||
n: function(node) {
|
||||
this.appendChild(node.cloneNode());
|
||||
return this._finishChild();
|
||||
return this.$__finishChild();
|
||||
},
|
||||
|
||||
actualize: function(document) {
|
||||
@ -265,7 +266,7 @@ HTMLElement.prototype = {
|
||||
for (var attrName in attributes) {
|
||||
var attrValue = attributes[attrName];
|
||||
|
||||
if (attrName.startsWith('data-_')) {
|
||||
if (specialAttrRegexp.test(attrName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -286,7 +287,7 @@ HTMLElement.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
if (this._isTextArea) {
|
||||
if (this.$__isTextArea) {
|
||||
el.value = this.value;
|
||||
} else {
|
||||
var curChild = this.firstChild;
|
||||
|
||||
@ -4,12 +4,12 @@ var DocumentFragment;
|
||||
|
||||
function assignNamespace(node, namespaceURI) {
|
||||
node.namespaceURI = namespaceURI;
|
||||
var childNodes = node.childNodes;
|
||||
var childCount = node._childCount;
|
||||
var childNodes = node.$__childNodes;
|
||||
var childCount = node.$__childCount;
|
||||
|
||||
for (var i=0; i<childCount; i++) {
|
||||
var child = childNodes[i];
|
||||
if (child._nsAware) {
|
||||
if (child.$__nsAware) {
|
||||
assignNamespace(childNodes[i], namespaceURI);
|
||||
}
|
||||
}
|
||||
@ -29,27 +29,27 @@ function Node(finalChildCount) {
|
||||
childNodes = [];
|
||||
}
|
||||
|
||||
this.childNodes = childNodes;
|
||||
this._finalChildCount = finalChildCount;
|
||||
this._childCount = 0;
|
||||
this._firstChild = firstChild;
|
||||
this._lastChild = lastChild;
|
||||
this.$__childNodes = childNodes;
|
||||
this.$__finalChildCount = finalChildCount;
|
||||
this.$__childCount = 0;
|
||||
this.$__firstChild = firstChild;
|
||||
this.$__lastChild = lastChild;
|
||||
}
|
||||
|
||||
this.parentNode = undefined;
|
||||
this._nextSibling = undefined;
|
||||
this.$__parentNode = undefined;
|
||||
this.$__nextSibling = undefined;
|
||||
}
|
||||
|
||||
Node.prototype = {
|
||||
removeChildren: function() {
|
||||
this.childNodes.length = 0;
|
||||
this._firstChild = undefined;
|
||||
this._childCount = 0;
|
||||
this._lastChild = undefined;
|
||||
this.$__childNodes.length = 0;
|
||||
this.$__firstChild = undefined;
|
||||
this.$__childCount = 0;
|
||||
this.$__lastChild = undefined;
|
||||
},
|
||||
|
||||
get firstChild() {
|
||||
var firstChild = this._firstChild;
|
||||
var firstChild = this.$__firstChild;
|
||||
|
||||
if (firstChild && firstChild.nodeType === 11 /* DocumentFragment */) {
|
||||
var nestedFirstChild = firstChild.firstChild;
|
||||
@ -64,7 +64,7 @@ Node.prototype = {
|
||||
},
|
||||
|
||||
get lastChild() {
|
||||
var lastChild = this._lastChild;
|
||||
var lastChild = this.$__lastChild;
|
||||
|
||||
if (lastChild && lastChild.nodeType === 11 /* DocumentFragment */) {
|
||||
return lastChild.lastChild;
|
||||
@ -74,7 +74,7 @@ Node.prototype = {
|
||||
},
|
||||
|
||||
get nextSibling() {
|
||||
var nextSibling = this._nextSibling;
|
||||
var nextSibling = this.$__nextSibling;
|
||||
|
||||
if (nextSibling) {
|
||||
if (nextSibling.nodeType === 11 /* DocumentFragment */) {
|
||||
@ -82,7 +82,7 @@ Node.prototype = {
|
||||
return firstChild || nextSibling.nextSibling;
|
||||
}
|
||||
} else {
|
||||
var parentNode = this.parentNode;
|
||||
var parentNode = this.$__parentNode;
|
||||
if (parentNode && parentNode.nodeType === 11) {
|
||||
return parentNode.nextSibling;
|
||||
}
|
||||
@ -96,7 +96,7 @@ Node.prototype = {
|
||||
},
|
||||
|
||||
appendChild: function(child) {
|
||||
if (this._isTextArea) {
|
||||
if (this.$__isTextArea) {
|
||||
if (child.nodeType === 3) {
|
||||
var currentValue = this.value;
|
||||
this.value = currentValue ? currentValue + child.nodeValue : child.nodeValue;
|
||||
@ -106,30 +106,30 @@ Node.prototype = {
|
||||
} else {
|
||||
var namespaceURI;
|
||||
|
||||
if (child._nsAware && (namespaceURI = this.namespaceURI) && !child.namespaceURI) {
|
||||
if (child.$__nsAware && (namespaceURI = this.namespaceURI) && !child.namespaceURI) {
|
||||
assignNamespace(child, namespaceURI);
|
||||
}
|
||||
|
||||
var index = this._childCount++;
|
||||
this.childNodes[index] = child;
|
||||
var index = this.$__childCount++;
|
||||
this.$__childNodes[index] = child;
|
||||
|
||||
child.parentNode = this;
|
||||
child.$__parentNode = this;
|
||||
|
||||
if (index === 0) {
|
||||
this._firstChild = child;
|
||||
this.$__firstChild = child;
|
||||
} else {
|
||||
this._lastChild._nextSibling = child;
|
||||
this.$__lastChild.$__nextSibling = child;
|
||||
}
|
||||
|
||||
this._lastChild = child;
|
||||
this.$__lastChild = child;
|
||||
}
|
||||
|
||||
return child;
|
||||
},
|
||||
|
||||
_finishChild: function() {
|
||||
if (this._childCount === this._finalChildCount && this.parentNode) {
|
||||
return this.parentNode._finishChild();
|
||||
$__finishChild: function finishChild() {
|
||||
if (this.$__childCount === this.$__finalChildCount && this.$__parentNode) {
|
||||
return this.$__parentNode.$__finishChild();
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
|
||||
6
runtime/vdom/package.json
Normal file
6
runtime/vdom/package.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"minprops": {
|
||||
"exclude": ["c", "ca", "e", "n", "sa", "t"],
|
||||
"matchPrefix": "$__"
|
||||
}
|
||||
}
|
||||
@ -49,7 +49,7 @@ function virtualize(node) {
|
||||
return vdomEL;
|
||||
} else if (node.nodeType === 3) { // Text node
|
||||
return new Text(node.nodeValue);
|
||||
} else if (node.nodeType === 8) { // Text node
|
||||
} else if (node.nodeType === 8) { // Comment node
|
||||
return new Comment(node.nodeValue);
|
||||
} else if (node.nodeType === 11) { // DocumentFragment node
|
||||
var vdomDocFragment = new DocumentFragment();
|
||||
|
||||
@ -2,12 +2,23 @@ var AsyncVDOMBuilder = require('../runtime/vdom/AsyncVDOMBuilder');
|
||||
var HTMLElement = require('../runtime/vdom/HTMLElement');
|
||||
var expect = require('chai').expect;
|
||||
|
||||
function getChildNodes(parentNode) {
|
||||
var childNodes = [];
|
||||
|
||||
var curChild = parentNode.firstChild;
|
||||
while(curChild) {
|
||||
childNodes.push(curChild);
|
||||
curChild = curChild.nextSibling;
|
||||
}
|
||||
|
||||
return childNodes;
|
||||
}
|
||||
describe('AsyncVDOMBuilder', function() {
|
||||
it('sync', function() {
|
||||
var out = new AsyncVDOMBuilder();
|
||||
out.element('div', {}, 0);
|
||||
var tree = out.getOutput();
|
||||
expect(tree.childNodes.length).to.equal(1);
|
||||
expect(getChildNodes(tree).length).to.equal(1);
|
||||
});
|
||||
|
||||
it('end, then listen for finish', function(done) {
|
||||
@ -15,7 +26,7 @@ describe('AsyncVDOMBuilder', function() {
|
||||
out.element('div', {}, 0);
|
||||
out.end();
|
||||
out.on('finish', function(result) {
|
||||
expect(result.getOutput().childNodes.length).to.equal(1);
|
||||
expect(getChildNodes(result.getOutput()).length).to.equal(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -35,7 +46,7 @@ describe('AsyncVDOMBuilder', function() {
|
||||
out.end();
|
||||
out.on('finish', function(result) {
|
||||
var tree = result.getOutput();
|
||||
expect(tree.childNodes.length).to.equal(3);
|
||||
expect(getChildNodes(tree).length).to.equal(3);
|
||||
expect(tree.firstChild.nodeName).to.equal('div');
|
||||
expect(tree.firstChild.nextSibling.nodeName).to.equal('span');
|
||||
expect(tree.firstChild.nextSibling.nextSibling.nodeName).to.equal('section');
|
||||
@ -47,7 +58,7 @@ describe('AsyncVDOMBuilder', function() {
|
||||
const out = new AsyncVDOMBuilder();
|
||||
out.element('div', {}, 0);
|
||||
out.end().then((result) => {
|
||||
expect(result.getOutput().childNodes.length).to.equal(1);
|
||||
expect(getChildNodes(result.getOutput()).length).to.equal(1);
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
@ -55,10 +66,10 @@ describe('AsyncVDOMBuilder', function() {
|
||||
it('async flush', function(done) {
|
||||
var out = new AsyncVDOMBuilder();
|
||||
out.on('update', function(result) {
|
||||
expect(result.getOutput().childNodes.length).to.equal(1);
|
||||
expect(getChildNodes(result.getOutput()).length).to.equal(1);
|
||||
});
|
||||
out.once('finish', function(result) {
|
||||
expect(result.getOutput().childNodes.length).to.equal(2);
|
||||
expect(getChildNodes(result.getOutput()).length).to.equal(2);
|
||||
done();
|
||||
});
|
||||
|
||||
@ -79,12 +90,13 @@ describe('AsyncVDOMBuilder', function() {
|
||||
var out = new AsyncVDOMBuilder();
|
||||
out.once('finish', function(result) {
|
||||
var tree = result.getOutput();
|
||||
var header = tree.childNodes[0];
|
||||
var list = tree.childNodes[1];
|
||||
var paragraph = tree.childNodes[2];
|
||||
var childNodes = getChildNodes(tree);
|
||||
var header = childNodes[0];
|
||||
var list = childNodes[1];
|
||||
var paragraph = childNodes[2];
|
||||
expect(header.nodeName).to.equal('h1');
|
||||
expect(list.nodeName).to.equal('ul');
|
||||
expect(list.childNodes.length).to.equal(10);
|
||||
expect(getChildNodes(list).length).to.equal(10);
|
||||
expect(paragraph.nodeName).to.equal('p');
|
||||
done();
|
||||
});
|
||||
@ -115,9 +127,10 @@ describe('AsyncVDOMBuilder', function() {
|
||||
|
||||
out.once('finish', function(result) {
|
||||
var tree = result.getOutput();
|
||||
expect(tree.childNodes[0].nodeName).to.equal('div');
|
||||
expect(tree.childNodes[1].nodeValue).to.equal('Hello <em>World</em>');
|
||||
expect(tree.childNodes[2].nodeValue).to.equal('TODO: make this work');
|
||||
var childNodes = getChildNodes(tree);
|
||||
expect(childNodes[0].nodeName).to.equal('div');
|
||||
expect(childNodes[1].nodeValue).to.equal('Hello <em>World</em>');
|
||||
expect(childNodes[2].nodeValue).to.equal('TODO: make this work');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
@ -29,8 +29,8 @@ module.exports = function(helpers) {
|
||||
|
||||
root.appendChild(clone);
|
||||
|
||||
expect(el.parentNode).to.equal(undefined);
|
||||
expect(clone.parentNode).to.equal(root);
|
||||
expect(el.$__parentNode).to.equal(undefined);
|
||||
expect(clone.$__parentNode).to.equal(root);
|
||||
|
||||
return root;
|
||||
};
|
||||
@ -7,7 +7,6 @@ module.exports = function(helpers) {
|
||||
|
||||
div.removeChildren();
|
||||
expect(div.firstChild).to.equal(undefined);
|
||||
expect(div.childNodes.length).to.equal(0);
|
||||
|
||||
var newChild = helpers.vdom.createElement('h1', null, 1)
|
||||
.t('New child');
|
||||
@ -15,7 +14,7 @@ module.exports = function(helpers) {
|
||||
div.appendChild(newChild);
|
||||
|
||||
expect(div.firstChild).to.equal(newChild);
|
||||
expect(div.childNodes.length).to.equal(1);
|
||||
expect(div.firstChild.nextSibling).to.equal(undefined);
|
||||
|
||||
return div;
|
||||
};
|
||||
@ -12,11 +12,11 @@ module.exports = function(helpers) {
|
||||
|
||||
|
||||
expect(linkClone).to.not.equal(link);
|
||||
expect(link.parentNode).to.equal(undefined);
|
||||
expect(link.$__parentNode).to.equal(undefined);
|
||||
expect(link.nextSibling).to.equal(undefined);
|
||||
|
||||
expect(linkClone.nextSibling.nodeName).to.equal('span');
|
||||
expect(linkClone.parentNode.nodeName).to.equal('div');
|
||||
expect(linkClone.$__parentNode.nodeName).to.equal('div');
|
||||
|
||||
|
||||
return el;
|
||||
|
||||
@ -3,14 +3,14 @@ var expect = require('chai').expect;
|
||||
module.exports = function(helpers) {
|
||||
var widget = helpers.mount(require('./index'), {});
|
||||
|
||||
expect(Array.isArray(widget.__evHandles)).to.equal(true);
|
||||
expect(Array.isArray(widget.$__domEventListenerHandles)).to.equal(true);
|
||||
|
||||
var el = widget.el;
|
||||
var fooLink = widget.getEl('fooLink');
|
||||
|
||||
widget.destroy();
|
||||
|
||||
expect(widget.__evHandles).to.equal(null);
|
||||
expect(widget.$__domEventListenerHandles).to.equal(null);
|
||||
|
||||
// Make sure the widget is removed from the DOM tree
|
||||
|
||||
|
||||
@ -3,11 +3,11 @@ var expect = require('chai').expect;
|
||||
module.exports = function(helpers) {
|
||||
var widget = helpers.mount(require('./index'), {});
|
||||
|
||||
expect(widget.__document).to.exist;
|
||||
expect(widget.__document).to.equal(document);
|
||||
expect(widget.$__document).to.exist;
|
||||
expect(widget.$__document).to.equal(document);
|
||||
|
||||
var contentWidget = widget.renderIntoIframe();
|
||||
expect(contentWidget.__document).to.equal(widget.getFrameEl().contentWindow.document);
|
||||
expect(contentWidget.$__document).to.equal(widget.getFrameEl().contentWindow.document);
|
||||
expect(contentWidget.getEl('input').value).to.equal('test');
|
||||
|
||||
expect(contentWidget.getWidget('more').getValue()).to.equal('hello');
|
||||
|
||||
@ -3,14 +3,14 @@ var expect = require('chai').expect;
|
||||
module.exports = function(helpers) {
|
||||
var widget = helpers.mount(require('./index'), {});
|
||||
|
||||
expect(Array.isArray(widget.__evHandles)).to.equal(true);
|
||||
expect(Array.isArray(widget.$__domEventListenerHandles)).to.equal(true);
|
||||
|
||||
var el = widget.el;
|
||||
var fooLink = widget.getEl('fooLink');
|
||||
|
||||
widget.destroy();
|
||||
|
||||
expect(widget.__evHandles).to.equal(null);
|
||||
expect(widget.$__domEventListenerHandles).to.equal(null);
|
||||
|
||||
// Make sure the widget is removed from the DOM tree
|
||||
|
||||
|
||||
@ -3,11 +3,11 @@ var expect = require('chai').expect;
|
||||
module.exports = function(helpers) {
|
||||
var widget = helpers.mount(require('./index'), {});
|
||||
|
||||
expect(widget.__document != null).to.equal(true);
|
||||
expect(widget.__document).to.equal(document);
|
||||
expect(widget.$__document != null).to.equal(true);
|
||||
expect(widget.$__document).to.equal(document);
|
||||
|
||||
var contentWidget = widget.renderIntoIframe();
|
||||
expect(contentWidget.__document).to.equal(widget.getFrameEl().contentWindow.document);
|
||||
expect(contentWidget.$__document).to.equal(widget.getFrameEl().contentWindow.document);
|
||||
expect(contentWidget.getEl('input').value).to.equal('test');
|
||||
|
||||
expect(contentWidget.getWidget('more').getValue()).to.equal('hello');
|
||||
|
||||
@ -62,10 +62,10 @@ function emitLifecycleEvent(widget, eventType, eventArg) {
|
||||
}
|
||||
|
||||
function removeDOMEventListeners(widget) {
|
||||
var eventListenerHandles = widget.__evHandles;
|
||||
var eventListenerHandles = widget.$__domEventListenerHandles;
|
||||
if (eventListenerHandles) {
|
||||
eventListenerHandles.forEach(removeListener);
|
||||
widget.__evHandles = null;
|
||||
widget.$__domEventListenerHandles = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,8 +75,8 @@ function destroyWidgetForEl(el) {
|
||||
destroyWidgetHelper(widgetToDestroy);
|
||||
el.__widget = null;
|
||||
|
||||
while ((widgetToDestroy = widgetToDestroy.__rootFor)) {
|
||||
widgetToDestroy.__rootFor = null;
|
||||
while ((widgetToDestroy = widgetToDestroy.$__rootFor)) {
|
||||
widgetToDestroy.$__rootFor = null;
|
||||
destroyWidgetHelper(widgetToDestroy);
|
||||
}
|
||||
}
|
||||
@ -98,7 +98,7 @@ function destroyWidgetHelper(widget) {
|
||||
}
|
||||
|
||||
emitLifecycleEvent(widget, 'beforeDestroy');
|
||||
widget.__lifecycleState = 'destroyed';
|
||||
widget.$__lifecycleState = 'destroyed';
|
||||
|
||||
widget.els = null;
|
||||
widget.el = null;
|
||||
@ -106,9 +106,9 @@ function destroyWidgetHelper(widget) {
|
||||
// Unsubscribe from all DOM events
|
||||
removeDOMEventListeners(widget);
|
||||
|
||||
if (widget.__subscriptions) {
|
||||
widget.__subscriptions.removeAllListeners();
|
||||
widget.__subscriptions = null;
|
||||
if (widget.$__subscriptions) {
|
||||
widget.$__subscriptions.removeAllListeners();
|
||||
widget.$__subscriptions = null;
|
||||
}
|
||||
|
||||
delete widgetLookup[widget.id];
|
||||
@ -117,8 +117,8 @@ function destroyWidgetHelper(widget) {
|
||||
}
|
||||
|
||||
function resetWidget(widget) {
|
||||
widget.__newProps = null;
|
||||
widget.__state._reset();
|
||||
widget.$__newProps = null;
|
||||
widget.$__state._reset();
|
||||
}
|
||||
|
||||
function hasCompatibleWidget(widgetsContext, existingWidget) {
|
||||
@ -128,7 +128,7 @@ function hasCompatibleWidget(widgetsContext, existingWidget) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return existingWidget.__type === newWidgetDef.type;
|
||||
return existingWidget.$__type === newWidgetDef.type;
|
||||
}
|
||||
|
||||
function handleCustomEventWithMethodListener(widget, targetMethodName, args, extraArgs) {
|
||||
@ -140,7 +140,7 @@ function handleCustomEventWithMethodListener(widget, targetMethodName, args, ext
|
||||
}
|
||||
|
||||
|
||||
var targetWidget = widgetLookup[widget.__scope];
|
||||
var targetWidget = widgetLookup[widget.$__scope];
|
||||
var targetMethod = targetWidget[targetMethodName];
|
||||
if (!targetMethod) {
|
||||
throw new Error('Method not found for widget ' + targetWidget.id + ': ' + targetMethodName);
|
||||
@ -230,15 +230,15 @@ function Widget(id, document) {
|
||||
this.id = id;
|
||||
this.el = null;
|
||||
this.bodyEl = null;
|
||||
this.__state = null;
|
||||
this.__roots = null;
|
||||
this.__subscriptions = null;
|
||||
this.__evHandles = null;
|
||||
this.__lifecycleState = null;
|
||||
this.__customEvents = null;
|
||||
this.__scope = null;
|
||||
this.__updateQueued = false;
|
||||
this.__document = document;
|
||||
this.$__state = null;
|
||||
this.$__roots = null;
|
||||
this.$__subscriptions = null;
|
||||
this.$__domEventListenerHandles = null;
|
||||
this.$__lifecycleState = null;
|
||||
this.$__customEvents = null;
|
||||
this.$__scope = null;
|
||||
this.$__updateQueued = false;
|
||||
this.$__document = document;
|
||||
}
|
||||
|
||||
Widget.prototype = widgetProto = {
|
||||
@ -249,9 +249,9 @@ Widget.prototype = widgetProto = {
|
||||
throw new Error('target is required');
|
||||
}
|
||||
|
||||
var tracker = this.__subscriptions;
|
||||
var tracker = this.$__subscriptions;
|
||||
if (!tracker) {
|
||||
this.__subscriptions = tracker = listenerTracker.createTracker();
|
||||
this.$__subscriptions = tracker = listenerTracker.createTracker();
|
||||
}
|
||||
|
||||
|
||||
@ -263,7 +263,7 @@ Widget.prototype = widgetProto = {
|
||||
},
|
||||
|
||||
emit: function(eventType) {
|
||||
var customEvents = this.__customEvents;
|
||||
var customEvents = this.$__customEvents;
|
||||
var target;
|
||||
|
||||
if (customEvents && (target = customEvents[eventType])) {
|
||||
@ -280,7 +280,7 @@ Widget.prototype = widgetProto = {
|
||||
return getElIdHelper(this, widgetElId, index);
|
||||
},
|
||||
getEl: function (widgetElId, index) {
|
||||
var doc = this.__document;
|
||||
var doc = this.$__document;
|
||||
|
||||
if (widgetElId != null) {
|
||||
return doc.getElementById(getElIdHelper(this, widgetElId, index));
|
||||
@ -337,7 +337,7 @@ Widget.prototype = widgetProto = {
|
||||
}
|
||||
}
|
||||
|
||||
var rootWidgets = this.__rootWidgets;
|
||||
var rootWidgets = this.$__rootWidgets;
|
||||
if (rootWidgets) {
|
||||
for (i=0, len=rootWidgets.length; i<len; i++) {
|
||||
rootWidgets[i].destroy();
|
||||
@ -347,19 +347,19 @@ Widget.prototype = widgetProto = {
|
||||
destroyWidgetHelper(this);
|
||||
},
|
||||
isDestroyed: function () {
|
||||
return this.__lifecycleState === 'destroyed';
|
||||
return this.$__lifecycleState === 'destroyed';
|
||||
},
|
||||
getBodyEl: function() {
|
||||
return this.bodyEl;
|
||||
},
|
||||
get state() {
|
||||
return this.__state;
|
||||
return this.$__state;
|
||||
},
|
||||
set state(value) {
|
||||
if(!this.__state && value) {
|
||||
this.__state = new this.State(this, value);
|
||||
if(!this.$__state && value) {
|
||||
this.$__state = new this.State(this, value);
|
||||
} else {
|
||||
this.__state._replace(value);
|
||||
this.$__state._replace(value);
|
||||
}
|
||||
},
|
||||
setState: function(name, value) {
|
||||
@ -412,11 +412,11 @@ Widget.prototype = widgetProto = {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.__newProps) {
|
||||
if (!this.$__newProps) {
|
||||
updateManager.queueWidgetUpdate(this);
|
||||
}
|
||||
|
||||
this.__newProps = newProps;
|
||||
this.$__newProps = newProps;
|
||||
},
|
||||
|
||||
update: function() {
|
||||
@ -424,7 +424,7 @@ Widget.prototype = widgetProto = {
|
||||
return;
|
||||
}
|
||||
|
||||
var newProps = this.__newProps;
|
||||
var newProps = this.$__newProps;
|
||||
|
||||
if (this.shouldUpdate(newProps, this.state) === false) {
|
||||
resetWidget(this);
|
||||
@ -437,7 +437,7 @@ Widget.prototype = widgetProto = {
|
||||
return;
|
||||
}
|
||||
|
||||
var state = this.__state;
|
||||
var state = this.$__state;
|
||||
|
||||
if (!state._dirty) {
|
||||
// Don't even bother trying to update this widget since it is
|
||||
@ -457,7 +457,7 @@ Widget.prototype = widgetProto = {
|
||||
},
|
||||
|
||||
_replaceState: function(newState) {
|
||||
var state = this.__state;
|
||||
var state = this.$__state;
|
||||
|
||||
// Update the existing widget state using the internal/private
|
||||
// method to ensure that another update is not queued up
|
||||
@ -470,7 +470,7 @@ Widget.prototype = widgetProto = {
|
||||
},
|
||||
|
||||
isDirty: function() {
|
||||
return this.__state._dirty;
|
||||
return this.$__state._dirty;
|
||||
},
|
||||
|
||||
_reset: function(shouldRemoveDOMEventListeners) {
|
||||
@ -501,15 +501,15 @@ Widget.prototype = widgetProto = {
|
||||
}
|
||||
|
||||
var renderer = self.renderer;
|
||||
self.__lifecycleState = 'rerender';
|
||||
self.$__lifecycleState = 'rerender';
|
||||
|
||||
var state = self.__state;
|
||||
var state = self.$__state;
|
||||
|
||||
var globalData = {};
|
||||
globalData.$w = [self, !props && state && state._raw];
|
||||
|
||||
var fromEls = markoWidgets._roots(self, {});
|
||||
var doc = self.__document;
|
||||
var doc = self.$__document;
|
||||
|
||||
updateManager.batchUpdate(function() {
|
||||
var createOut = renderer.createOut || marko.createOut;
|
||||
@ -609,7 +609,7 @@ Widget.prototype = widgetProto = {
|
||||
|
||||
result.afterInsert(doc);
|
||||
|
||||
self.__lifecycleState = null;
|
||||
self.$__lifecycleState = null;
|
||||
|
||||
if (!props) {
|
||||
// We have re-rendered with the new state so our state
|
||||
@ -640,7 +640,7 @@ domInsert(
|
||||
var els = this.els;
|
||||
var elCount = els.length;
|
||||
if (elCount > 1) {
|
||||
var fragment = widget.__document.createDocumentFragment();
|
||||
var fragment = widget.$__document.createDocumentFragment();
|
||||
for (var i=0; i<elCount; i++) {
|
||||
fragment.appendChild(els[i]);
|
||||
}
|
||||
|
||||
@ -1,22 +1,6 @@
|
||||
/*
|
||||
* Copyright 2011 eBay Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
require('raptor-polyfill/string/endsWith');
|
||||
|
||||
'use strict';
|
||||
var repeatedId = require('./repeated-id');
|
||||
var repeatedRegExp = /\[\]$/;
|
||||
|
||||
/**
|
||||
* A WidgetDef is used to hold the metadata collected at runtime for
|
||||
@ -67,7 +51,7 @@ WidgetDef.prototype = {
|
||||
if (nestedId == null) {
|
||||
return this.id;
|
||||
} else {
|
||||
if (typeof nestedId === 'string' && nestedId.endsWith('[]')) {
|
||||
if (typeof nestedId === 'string' && repeatedRegExp.test(nestedId)) {
|
||||
return repeatedId.nextId(this.out, this.id, nestedId);
|
||||
} else {
|
||||
return this.id + '-' + nestedId;
|
||||
|
||||
@ -22,7 +22,7 @@ function getWidgetForEl(el, doc) {
|
||||
var widget = node.__widget;
|
||||
|
||||
while(widget) {
|
||||
var rootFor = widget.__rootFor;
|
||||
var rootFor = widget.$__rootFor;
|
||||
if (rootFor) {
|
||||
widget = rootFor;
|
||||
} else {
|
||||
@ -47,7 +47,7 @@ function getRootEls(widget, rootEls) {
|
||||
rootEls[widgetEl.id] = widgetEl;
|
||||
}
|
||||
|
||||
var rootWidgets = widget.__rootWidgets;
|
||||
var rootWidgets = widget.$__rootWidgets;
|
||||
if (rootWidgets) {
|
||||
for (i=0, len=rootWidgets.length; i<len; i++) {
|
||||
var rootWidget = rootWidgets[i];
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
'use strict';
|
||||
require('raptor-polyfill/string/endsWith');
|
||||
|
||||
var logger = require('raptor-logging').logger(module);
|
||||
var _addEventListener = require('./addEventListener');
|
||||
var warp10Finalize = require('warp10/finalize');
|
||||
var eventDelegation = require('./event-delegation');
|
||||
@ -73,7 +70,7 @@ function initWidget(widgetDef, doc) {
|
||||
existingWidget = widgetLookup[id];
|
||||
}
|
||||
|
||||
if (existingWidget && existingWidget.__type !== type) {
|
||||
if (existingWidget && existingWidget.$__type !== type) {
|
||||
existingWidget = null;
|
||||
}
|
||||
|
||||
@ -95,11 +92,11 @@ function initWidget(widgetDef, doc) {
|
||||
var nestedId = id + '-' + rootId;
|
||||
var rootWidget = widgetLookup[nestedId];
|
||||
if (rootWidget) {
|
||||
rootWidget.__rootFor = widget;
|
||||
rootWidget.$__rootFor = widget;
|
||||
if (rootWidgets) {
|
||||
rootWidgets.push(rootWidget);
|
||||
} else {
|
||||
rootWidgets = widget.__rootWidgets = [rootWidget];
|
||||
rootWidgets = widget.$__rootWidgets = [rootWidget];
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -133,11 +130,6 @@ function initWidget(widgetDef, doc) {
|
||||
|
||||
widget.state = state || {}; // First time rendering so use the provided state or an empty state object
|
||||
|
||||
// The user-provided constructor function
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug('Creating widget: ' + type + ' (' + id + ')');
|
||||
}
|
||||
|
||||
if (!config) {
|
||||
config = {};
|
||||
}
|
||||
@ -145,7 +137,7 @@ function initWidget(widgetDef, doc) {
|
||||
if (widget._isWidget) {
|
||||
widget.el = el;
|
||||
widget.els = els;
|
||||
widget.__rootWidgets = rootWidgets;
|
||||
widget.$__rootWidgets = rootWidgets;
|
||||
widget.bodyEl = getNestedEl(widget, bodyElId, doc);
|
||||
|
||||
if (domEvents) {
|
||||
@ -164,20 +156,20 @@ function initWidget(widgetDef, doc) {
|
||||
}
|
||||
|
||||
if (eventListenerHandles.length) {
|
||||
widget.__evHandles = eventListenerHandles;
|
||||
widget.$__domEventListenerHandles = eventListenerHandles;
|
||||
}
|
||||
}
|
||||
|
||||
if (customEvents) {
|
||||
widget.__customEvents = {};
|
||||
widget.__scope = scope;
|
||||
widget.$__customEvents = {};
|
||||
widget.$__scope = scope;
|
||||
|
||||
for (i=0, len=customEvents.length; i<len; i+=3) {
|
||||
eventType = customEvents[i];
|
||||
targetMethodName = customEvents[i+1];
|
||||
extraArgs = customEvents[i+2];
|
||||
|
||||
widget.__customEvents[eventType] = [targetMethodName, extraArgs];
|
||||
widget.$__customEvents[eventType] = [targetMethodName, extraArgs];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -1,8 +1,12 @@
|
||||
{
|
||||
"browser": {
|
||||
"./index.js": "./index-browser.js",
|
||||
"./uniqueId.js": "./uniqueId-browser.js",
|
||||
"./init-widgets.js": "./init-widgets-browser.js",
|
||||
"./defineWidget.js": "./defineWidget-browser.js"
|
||||
}
|
||||
}
|
||||
"browser": {
|
||||
"./index.js": "./index-browser.js",
|
||||
"./uniqueId.js": "./uniqueId-browser.js",
|
||||
"./init-widgets.js": "./init-widgets-browser.js",
|
||||
"./defineWidget.js": "./defineWidget-browser.js"
|
||||
},
|
||||
"minprops": {
|
||||
"exclude": ["r"],
|
||||
"matchPrefix": "$__"
|
||||
}
|
||||
}
|
||||
@ -79,7 +79,7 @@ function getWidgetClass(typeName) {
|
||||
}
|
||||
|
||||
// Make the widget "type" accessible on each widget instance
|
||||
WidgetClass.prototype.__type = typeName;
|
||||
WidgetClass.prototype.$__type = typeName;
|
||||
|
||||
widgetTypes[typeName] = WidgetClass;
|
||||
|
||||
@ -96,7 +96,7 @@ exports.createWidget = function(typeName, id, document) {
|
||||
widget = new WidgetClass(id, document);
|
||||
} else if (WidgetClass.initWidget) {
|
||||
widget = WidgetClass;
|
||||
widget.__document = document;
|
||||
widget.$__document = document;
|
||||
}
|
||||
return widget;
|
||||
};
|
||||
|
||||
@ -3,17 +3,20 @@ var widgetLookup = require('./lookup').widgets;
|
||||
var includeTag = require('./taglib/include-tag');
|
||||
var repeatedId = require('./repeated-id');
|
||||
var getRootEls = markoWidgets._roots;
|
||||
var repeatedRegExp = /\[\]$/;
|
||||
|
||||
var RERENDER_WIDGET_INDEX = 0;
|
||||
var RERENDER_WIDGET_STATE_INDEX = 1;
|
||||
|
||||
var WIDGETS_BEGIN_ASYNC_ADDED_KEY = '$wa';
|
||||
|
||||
function resolveWidgetRef(out, ref, scope) {
|
||||
if (ref.charAt(0) === '#') {
|
||||
return ref.substring(1);
|
||||
} else {
|
||||
var resolvedId;
|
||||
|
||||
if (ref.endsWith('[]')) {
|
||||
if (repeatedRegExp.test(ref)) {
|
||||
resolvedId = repeatedId.nextId(out, scope, ref);
|
||||
} else {
|
||||
resolvedId = scope + '-' + ref;
|
||||
@ -114,8 +117,8 @@ module.exports = function createRendererFunc(templateRenderFunc, widgetProps, re
|
||||
return function renderer(input, out, renderingLogicLegacy /* needed by defineRenderer */) {
|
||||
var outGlobal = out.global;
|
||||
|
||||
if (!outGlobal.__widgetsBeginAsyncAdded) {
|
||||
outGlobal.__widgetsBeginAsyncAdded = true;
|
||||
if (!outGlobal[WIDGETS_BEGIN_ASYNC_ADDED_KEY]) {
|
||||
outGlobal[WIDGETS_BEGIN_ASYNC_ADDED_KEY] = true;
|
||||
out.on('beginAsync', handleBeginAsync);
|
||||
}
|
||||
|
||||
@ -245,7 +248,7 @@ module.exports = function createRendererFunc(templateRenderFunc, widgetProps, re
|
||||
} else if (rerenderInfo) {
|
||||
// Look in in the DOM to see if a widget with the same ID and type already exists.
|
||||
existingWidget = widgetLookup[id];
|
||||
if (existingWidget && existingWidget.__type !== typeName) {
|
||||
if (existingWidget && existingWidget.$__type !== typeName) {
|
||||
existingWidget = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,29 +1,38 @@
|
||||
var AsyncValue = require('raptor-async/AsyncValue');
|
||||
'use strict';
|
||||
|
||||
var afterUpdateAsyncValue = null;
|
||||
var updatesScheduled = false;
|
||||
|
||||
var queuedListeners = [];
|
||||
var batchStack = []; // A stack of batched updates
|
||||
var unbatchedQueue = []; // Used for scheduled batched updates
|
||||
|
||||
function notifyAfterUpdateListeners() {
|
||||
var len = queuedListeners.length;
|
||||
if (len) {
|
||||
for (var i=0; i<len; i++) {
|
||||
queuedListeners[i]();
|
||||
}
|
||||
|
||||
queuedListeners.length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called when we schedule the update of "unbatched"
|
||||
* updates to widgets.
|
||||
*/
|
||||
function updateUnbatchedWidgets() {
|
||||
if (!unbatchedQueue.length) {
|
||||
// No widgets to update
|
||||
return;
|
||||
if (unbatchedQueue.length) {
|
||||
try {
|
||||
updateWidgets(unbatchedQueue);
|
||||
} finally {
|
||||
// Reset the flag now that this scheduled batch update
|
||||
// is complete so that we can later schedule another
|
||||
// batched update if needed
|
||||
updatesScheduled = false;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
updateWidgets(unbatchedQueue);
|
||||
} finally {
|
||||
// Reset the flag now that this scheduled batch update
|
||||
// is complete so that we can later schedule another
|
||||
// batched update if needed
|
||||
updatesScheduled = false;
|
||||
}
|
||||
notifyAfterUpdateListeners();
|
||||
}
|
||||
|
||||
function scheduleUpdates() {
|
||||
@ -39,22 +48,17 @@ function scheduleUpdates() {
|
||||
}
|
||||
|
||||
function onAfterUpdate(callback) {
|
||||
queuedListeners.push(callback);
|
||||
scheduleUpdates();
|
||||
|
||||
if (!afterUpdateAsyncValue) {
|
||||
afterUpdateAsyncValue = new AsyncValue();
|
||||
}
|
||||
|
||||
afterUpdateAsyncValue.done(callback);
|
||||
}
|
||||
|
||||
function updateWidgets(queue) {
|
||||
// Loop over the widgets in the queue and update them.
|
||||
// NOTE: Is it okay if the queue grows during the iteration
|
||||
// NOTE: It is okay if the queue grows during the iteration
|
||||
// since we will still get to them at the end
|
||||
for (var i=0; i<queue.length; i++) {
|
||||
var widget = queue[i];
|
||||
widget.__updateQueued = false; // Reset the "__updateQueued" flag
|
||||
widget.$__updateQueued = false; // Reset the "__updateQueued" flag
|
||||
widget.update(); // Do the actual widget update
|
||||
}
|
||||
|
||||
@ -92,17 +96,14 @@ function batchUpdate(func) {
|
||||
if (isOuter) {
|
||||
// If there were any listeners for the "afterUpdate" event
|
||||
// then notify those listeners now
|
||||
if (afterUpdateAsyncValue) {
|
||||
afterUpdateAsyncValue.resolve();
|
||||
afterUpdateAsyncValue = null;
|
||||
}
|
||||
notifyAfterUpdateListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function queueWidgetUpdate(widget) {
|
||||
if (widget.__updateQueued) {
|
||||
if (widget.$__updateQueued) {
|
||||
// The widget has already been queued up for an update. Once
|
||||
// the widget has actually been updated we will reset the
|
||||
// "__updateQueued" flag so that it can be queued up again.
|
||||
@ -111,7 +112,7 @@ function queueWidgetUpdate(widget) {
|
||||
return;
|
||||
}
|
||||
|
||||
widget.__updateQueued = true;
|
||||
widget.$__updateQueued = true;
|
||||
|
||||
var batchStackLen = batchStack.length;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user