Code size reductions

This commit is contained in:
Patrick Steele-Idem 2016-12-16 14:09:55 -07:00
parent a34b128f9f
commit ff5472a034
26 changed files with 269 additions and 262 deletions

View File

@ -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');

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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;
}
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -0,0 +1,6 @@
{
"minprops": {
"exclude": ["c", "ca", "e", "n", "sa", "t"],
"matchPrefix": "$__"
}
}

View File

@ -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();

View File

@ -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();
});
});

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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;

View File

@ -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

View File

@ -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');

View File

@ -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

View File

@ -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');

View File

@ -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]);
}

View File

@ -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;

View File

@ -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];

View File

@ -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 {

View File

@ -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": "$__"
}
}

View File

@ -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;
};

View File

@ -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;
}
}

View File

@ -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;