superviewify
Version:
Browserify transform turning superviews.js template language to Googles incremental-dom
1,227 lines (1,074 loc) • 34.8 kB
JavaScript
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
/**
* @license
* Copyright 2015 The Incremental DOM Authors. All Rights Reserved.
*
* 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.
*/
;
/**
* Copyright 2015 The Incremental DOM Authors. All Rights Reserved.
*
* 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.
*/
/**
* A cached reference to the hasOwnProperty function.
*/
var hasOwnProperty = Object.prototype.hasOwnProperty;
/**
* A cached reference to the create function.
*/
var create = Object.create;
/**
* Used to prevent property collisions between our "map" and its prototype.
* @param {!Object<string, *>} map The map to check.
* @param {string} property The property to check.
* @return {boolean} Whether map has property.
*/
var has = function (map, property) {
return hasOwnProperty.call(map, property);
};
/**
* Creates an map object without a prototype.
* @return {!Object}
*/
var createMap = function () {
return create(null);
};
/**
* Keeps track of information needed to perform diffs for a given DOM node.
* @param {!string} nodeName
* @param {?string=} key
* @constructor
*/
function NodeData(nodeName, key) {
/**
* The attributes and their values.
* @const {!Object<string, *>}
*/
this.attrs = createMap();
/**
* An array of attribute name/value pairs, used for quickly diffing the
* incomming attributes to see if the DOM node's attributes need to be
* updated.
* @const {Array<*>}
*/
this.attrsArr = [];
/**
* The incoming attributes for this Node, before they are updated.
* @const {!Object<string, *>}
*/
this.newAttrs = createMap();
/**
* The key used to identify this node, used to preserve DOM nodes when they
* move within their parent.
* @const
*/
this.key = key;
/**
* Keeps track of children within this node by their key.
* {?Object<string, !Element>}
*/
this.keyMap = null;
/**
* Whether or not the keyMap is currently valid.
* {boolean}
*/
this.keyMapValid = true;
/**
* The node name for this node.
* @const {string}
*/
this.nodeName = nodeName;
/**
* @type {?string}
*/
this.text = null;
}
/**
* Initializes a NodeData object for a Node.
*
* @param {Node} node The node to initialize data for.
* @param {string} nodeName The node name of node.
* @param {?string=} key The key that identifies the node.
* @return {!NodeData} The newly initialized data object
*/
var initData = function (node, nodeName, key) {
var data = new NodeData(nodeName, key);
node['__incrementalDOMData'] = data;
return data;
};
/**
* Retrieves the NodeData object for a Node, creating it if necessary.
*
* @param {Node} node The node to retrieve the data for.
* @return {!NodeData} The NodeData for this Node.
*/
var getData = function (node) {
var data = node['__incrementalDOMData'];
if (!data) {
var nodeName = node.nodeName.toLowerCase();
var key = null;
if (node instanceof Element) {
key = node.getAttribute('key');
}
data = initData(node, nodeName, key);
}
return data;
};
/**
* Copyright 2015 The Incremental DOM Authors. All Rights Reserved.
*
* 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.
*/
/** @const */
var symbols = {
default: '__default',
placeholder: '__placeholder'
};
/**
* @param {string} name
* @return {string|undefined} The namespace to use for the attribute.
*/
var getNamespace = function (name) {
if (name.lastIndexOf('xml:', 0) === 0) {
return 'http://www.w3.org/XML/1998/namespace';
}
if (name.lastIndexOf('xlink:', 0) === 0) {
return 'http://www.w3.org/1999/xlink';
}
};
/**
* Applies an attribute or property to a given Element. If the value is null
* or undefined, it is removed from the Element. Otherwise, the value is set
* as an attribute.
* @param {!Element} el
* @param {string} name The attribute's name.
* @param {?(boolean|number|string)=} value The attribute's value.
*/
var applyAttr = function (el, name, value) {
if (value == null) {
el.removeAttribute(name);
} else {
var attrNS = getNamespace(name);
if (attrNS) {
el.setAttributeNS(attrNS, name, value);
} else {
el.setAttribute(name, value);
}
}
};
/**
* Applies a property to a given Element.
* @param {!Element} el
* @param {string} name The property's name.
* @param {*} value The property's value.
*/
var applyProp = function (el, name, value) {
el[name] = value;
};
/**
* Applies a style to an Element. No vendor prefix expansion is done for
* property names/values.
* @param {!Element} el
* @param {string} name The attribute's name.
* @param {*} style The style to set. Either a string of css or an object
* containing property-value pairs.
*/
var applyStyle = function (el, name, style) {
if (typeof style === 'string') {
el.style.cssText = style;
} else {
el.style.cssText = '';
var elStyle = el.style;
var obj = /** @type {!Object<string,string>} */style;
for (var prop in obj) {
if (has(obj, prop)) {
elStyle[prop] = obj[prop];
}
}
}
};
/**
* Updates a single attribute on an Element.
* @param {!Element} el
* @param {string} name The attribute's name.
* @param {*} value The attribute's value. If the value is an object or
* function it is set on the Element, otherwise, it is set as an HTML
* attribute.
*/
var applyAttributeTyped = function (el, name, value) {
var type = typeof value;
if (type === 'object' || type === 'function') {
applyProp(el, name, value);
} else {
applyAttr(el, name, /** @type {?(boolean|number|string)} */value);
}
};
/**
* Calls the appropriate attribute mutator for this attribute.
* @param {!Element} el
* @param {string} name The attribute's name.
* @param {*} value The attribute's value.
*/
var updateAttribute = function (el, name, value) {
var data = getData(el);
var attrs = data.attrs;
if (attrs[name] === value) {
return;
}
var mutator = attributes[name] || attributes[symbols.default];
mutator(el, name, value);
attrs[name] = value;
};
/**
* A publicly mutable object to provide custom mutators for attributes.
* @const {!Object<string, function(!Element, string, *)>}
*/
var attributes = createMap();
// Special generic mutator that's called for any attribute that does not
// have a specific mutator.
attributes[symbols.default] = applyAttributeTyped;
attributes[symbols.placeholder] = function () {};
attributes['style'] = applyStyle;
/**
* Gets the namespace to create an element (of a given tag) in.
* @param {string} tag The tag to get the namespace for.
* @param {?Node} parent
* @return {?string} The namespace to create the tag in.
*/
var getNamespaceForTag = function (tag, parent) {
if (tag === 'svg') {
return 'http://www.w3.org/2000/svg';
}
if (getData(parent).nodeName === 'foreignObject') {
return null;
}
return parent.namespaceURI;
};
/**
* Creates an Element.
* @param {Document} doc The document with which to create the Element.
* @param {?Node} parent
* @param {string} tag The tag for the Element.
* @param {?string=} key A key to identify the Element.
* @param {?Array<*>=} statics An array of attribute name/value pairs of the
* static attributes for the Element.
* @return {!Element}
*/
var createElement = function (doc, parent, tag, key, statics) {
var namespace = getNamespaceForTag(tag, parent);
var el = undefined;
if (namespace) {
el = doc.createElementNS(namespace, tag);
} else {
el = doc.createElement(tag);
}
initData(el, tag, key);
if (statics) {
for (var i = 0; i < statics.length; i += 2) {
updateAttribute(el, /** @type {!string}*/statics[i], statics[i + 1]);
}
}
return el;
};
/**
* Creates a Text Node.
* @param {Document} doc The document with which to create the Element.
* @return {!Text}
*/
var createText = function (doc) {
var node = doc.createTextNode('');
initData(node, '#text', null);
return node;
};
/**
* Creates a mapping that can be used to look up children using a key.
* @param {?Node} el
* @return {!Object<string, !Element>} A mapping of keys to the children of the
* Element.
*/
var createKeyMap = function (el) {
var map = createMap();
var child = el.firstElementChild;
while (child) {
var key = getData(child).key;
if (key) {
map[key] = child;
}
child = child.nextElementSibling;
}
return map;
};
/**
* Retrieves the mapping of key to child node for a given Element, creating it
* if necessary.
* @param {?Node} el
* @return {!Object<string, !Node>} A mapping of keys to child Elements
*/
var getKeyMap = function (el) {
var data = getData(el);
if (!data.keyMap) {
data.keyMap = createKeyMap(el);
}
return data.keyMap;
};
/**
* Retrieves a child from the parent with the given key.
* @param {?Node} parent
* @param {?string=} key
* @return {?Node} The child corresponding to the key.
*/
var getChild = function (parent, key) {
return key ? getKeyMap(parent)[key] : null;
};
/**
* Registers an element as being a child. The parent will keep track of the
* child using the key. The child can be retrieved using the same key using
* getKeyMap. The provided key should be unique within the parent Element.
* @param {?Node} parent The parent of child.
* @param {string} key A key to identify the child with.
* @param {!Node} child The child to register.
*/
var registerChild = function (parent, key, child) {
getKeyMap(parent)[key] = child;
};
/**
* Copyright 2015 The Incremental DOM Authors. All Rights Reserved.
*
* 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.
*/
/** @const */
var notifications = {
/**
* Called after patch has compleated with any Nodes that have been created
* and added to the DOM.
* @type {?function(Array<!Node>)}
*/
nodesCreated: null,
/**
* Called after patch has compleated with any Nodes that have been removed
* from the DOM.
* Note it's an applications responsibility to handle any childNodes.
* @type {?function(Array<!Node>)}
*/
nodesDeleted: null
};
/**
* Keeps track of the state of a patch.
* @constructor
*/
function Context() {
/**
* @type {(Array<!Node>|undefined)}
*/
this.created = notifications.nodesCreated && [];
/**
* @type {(Array<!Node>|undefined)}
*/
this.deleted = notifications.nodesDeleted && [];
}
/**
* @param {!Node} node
*/
Context.prototype.markCreated = function (node) {
if (this.created) {
this.created.push(node);
}
};
/**
* @param {!Node} node
*/
Context.prototype.markDeleted = function (node) {
if (this.deleted) {
this.deleted.push(node);
}
};
/**
* Notifies about nodes that were created during the patch opearation.
*/
Context.prototype.notifyChanges = function () {
if (this.created && this.created.length > 0) {
notifications.nodesCreated(this.created);
}
if (this.deleted && this.deleted.length > 0) {
notifications.nodesDeleted(this.deleted);
}
};
/**
* Makes sure that keyed Element matches the tag name provided.
* @param {!string} nodeName The nodeName of the node that is being matched.
* @param {string=} tag The tag name of the Element.
* @param {?string=} key The key of the Element.
*/
var assertKeyedTagMatches = function (nodeName, tag, key) {
if (nodeName !== tag) {
throw new Error('Was expecting node with key "' + key + '" to be a ' + tag + ', not a ' + nodeName + '.');
}
};
/** @type {?Context} */
var context = null;
/** @type {?Node} */
var currentNode = null;
/** @type {?Node} */
var currentParent = null;
/** @type {?Element|?DocumentFragment} */
var root = null;
/** @type {?Document} */
var doc = null;
/**
* Returns a patcher function that sets up and restores a patch context,
* running the run function with the provided data.
* @param {function((!Element|!DocumentFragment),!function(T),T=)} run
* @return {function((!Element|!DocumentFragment),!function(T),T=)}
* @template T
*/
var patchFactory = function (run) {
/**
* TODO(moz): These annotations won't be necessary once we switch to Closure
* Compiler's new type inference. Remove these once the switch is done.
*
* @param {(!Element|!DocumentFragment)} node
* @param {!function(T)} fn
* @param {T=} data
* @template T
*/
var f = function (node, fn, data) {
var prevContext = context;
var prevRoot = root;
var prevDoc = doc;
var prevCurrentNode = currentNode;
var prevCurrentParent = currentParent;
var previousInAttributes = false;
var previousInSkip = false;
context = new Context();
root = node;
doc = node.ownerDocument;
currentParent = node.parentNode;
if ('production' !== 'production') {}
run(node, fn, data);
if ('production' !== 'production') {}
context.notifyChanges();
context = prevContext;
root = prevRoot;
doc = prevDoc;
currentNode = prevCurrentNode;
currentParent = prevCurrentParent;
};
return f;
};
/**
* Patches the document starting at node with the provided function. This
* function may be called during an existing patch operation.
* @param {!Element|!DocumentFragment} node The Element or Document
* to patch.
* @param {!function(T)} fn A function containing elementOpen/elementClose/etc.
* calls that describe the DOM.
* @param {T=} data An argument passed to fn to represent DOM state.
* @template T
*/
var patchInner = patchFactory(function (node, fn, data) {
currentNode = node;
enterNode();
fn(data);
exitNode();
if ('production' !== 'production') {}
});
/**
* Patches an Element with the the provided function. Exactly one top level
* element call should be made corresponding to `node`.
* @param {!Element} node The Element where the patch should start.
* @param {!function(T)} fn A function containing elementOpen/elementClose/etc.
* calls that describe the DOM. This should have at most one top level
* element call.
* @param {T=} data An argument passed to fn to represent DOM state.
* @template T
*/
var patchOuter = patchFactory(function (node, fn, data) {
currentNode = /** @type {!Element} */{ nextSibling: node };
fn(data);
if ('production' !== 'production') {}
});
/**
* Checks whether or not the current node matches the specified nodeName and
* key.
*
* @param {?string} nodeName The nodeName for this node.
* @param {?string=} key An optional key that identifies a node.
* @return {boolean} True if the node matches, false otherwise.
*/
var matches = function (nodeName, key) {
var data = getData(currentNode);
// Key check is done using double equals as we want to treat a null key the
// same as undefined. This should be okay as the only values allowed are
// strings, null and undefined so the == semantics are not too weird.
return nodeName === data.nodeName && key == data.key;
};
/**
* Aligns the virtual Element definition with the actual DOM, moving the
* corresponding DOM node to the correct location or creating it if necessary.
* @param {string} nodeName For an Element, this should be a valid tag string.
* For a Text, this should be #text.
* @param {?string=} key The key used to identify this element.
* @param {?Array<*>=} statics For an Element, this should be an array of
* name-value pairs.
*/
var alignWithDOM = function (nodeName, key, statics) {
if (currentNode && matches(nodeName, key)) {
return;
}
var node = undefined;
// Check to see if the node has moved within the parent.
if (key) {
node = getChild(currentParent, key);
if (node && 'production' !== 'production') {
assertKeyedTagMatches(getData(node).nodeName, nodeName, key);
}
}
// Create the node if it doesn't exist.
if (!node) {
if (nodeName === '#text') {
node = createText(doc);
} else {
node = createElement(doc, currentParent, nodeName, key, statics);
}
if (key) {
registerChild(currentParent, key, node);
}
context.markCreated(node);
}
// If the node has a key, remove it from the DOM to prevent a large number
// of re-orders in the case that it moved far or was completely removed.
// Since we hold on to a reference through the keyMap, we can always add it
// back.
if (currentNode && getData(currentNode).key) {
currentParent.replaceChild(node, currentNode);
getData(currentParent).keyMapValid = false;
} else {
currentParent.insertBefore(node, currentNode);
}
currentNode = node;
};
/**
* Clears out any unvisited Nodes, as the corresponding virtual element
* functions were never called for them.
*/
var clearUnvisitedDOM = function () {
var node = currentParent;
var data = getData(node);
var keyMap = data.keyMap;
var keyMapValid = data.keyMapValid;
var child = node.lastChild;
var key = undefined;
if (child === currentNode && keyMapValid) {
return;
}
if (data.attrs[symbols.placeholder] && node !== root) {
if ('production' !== 'production') {}
return;
}
while (child !== currentNode) {
node.removeChild(child);
context.markDeleted( /** @type {!Node}*/child);
key = getData(child).key;
if (key) {
delete keyMap[key];
}
child = node.lastChild;
}
// Clean the keyMap, removing any unusued keys.
if (!keyMapValid) {
for (key in keyMap) {
child = keyMap[key];
if (child.parentNode !== node) {
context.markDeleted(child);
delete keyMap[key];
}
}
data.keyMapValid = true;
}
};
/**
* Changes to the first child of the current node.
*/
var enterNode = function () {
currentParent = currentNode;
currentNode = null;
};
/**
* Changes to the next sibling of the current node.
*/
var nextNode = function () {
if (currentNode) {
currentNode = currentNode.nextSibling;
} else {
currentNode = currentParent.firstChild;
}
};
/**
* Changes to the parent of the current node, removing any unvisited children.
*/
var exitNode = function () {
clearUnvisitedDOM();
currentNode = currentParent;
currentParent = currentParent.parentNode;
};
/**
* Makes sure that the current node is an Element with a matching tagName and
* key.
*
* @param {string} tag The element's tag.
* @param {?string=} key The key used to identify this element. This can be an
* empty string, but performance may be better if a unique value is used
* when iterating over an array of items.
* @param {?Array<*>=} statics An array of attribute name/value pairs of the
* static attributes for the Element. These will only be set once when the
* Element is created.
* @return {!Element} The corresponding Element.
*/
var coreElementOpen = function (tag, key, statics) {
nextNode();
alignWithDOM(tag, key, statics);
enterNode();
return (/** @type {!Element} */currentParent
);
};
/**
* Closes the currently open Element, removing any unvisited children if
* necessary.
*
* @return {!Element} The corresponding Element.
*/
var coreElementClose = function () {
if ('production' !== 'production') {}
exitNode();
return (/** @type {!Element} */currentNode
);
};
/**
* Makes sure the current node is a Text node and creates a Text node if it is
* not.
*
* @return {!Text} The corresponding Text Node.
*/
var coreText = function () {
nextNode();
alignWithDOM('#text', null, null);
return (/** @type {!Text} */currentNode
);
};
/**
* Gets the current Element being patched.
* @return {!Element}
*/
var currentElement = function () {
if ('production' !== 'production') {}
return (/** @type {!Element} */currentParent
);
};
/**
* Skips the children in a subtree, allowing an Element to be closed without
* clearing out the children.
*/
var skip = function () {
if ('production' !== 'production') {}
currentNode = currentParent.lastChild;
};
/**
* The offset in the virtual element declaration where the attributes are
* specified.
* @const
*/
var ATTRIBUTES_OFFSET = 3;
/**
* Builds an array of arguments for use with elementOpenStart, attr and
* elementOpenEnd.
* @const {Array<*>}
*/
var argsBuilder = [];
/**
* @param {string} tag The element's tag.
* @param {?string=} key The key used to identify this element. This can be an
* empty string, but performance may be better if a unique value is used
* when iterating over an array of items.
* @param {?Array<*>=} statics An array of attribute name/value pairs of the
* static attributes for the Element. These will only be set once when the
* Element is created.
* @param {...*} const_args Attribute name/value pairs of the dynamic attributes
* for the Element.
* @return {!Element} The corresponding Element.
*/
var elementOpen = function (tag, key, statics, const_args) {
if ('production' !== 'production') {}
var node = coreElementOpen(tag, key, statics);
var data = getData(node);
/*
* Checks to see if one or more attributes have changed for a given Element.
* When no attributes have changed, this is much faster than checking each
* individual argument. When attributes have changed, the overhead of this is
* minimal.
*/
var attrsArr = data.attrsArr;
var newAttrs = data.newAttrs;
var attrsChanged = false;
var i = ATTRIBUTES_OFFSET;
var j = 0;
for (; i < arguments.length; i += 1, j += 1) {
if (attrsArr[j] !== arguments[i]) {
attrsChanged = true;
break;
}
}
for (; i < arguments.length; i += 1, j += 1) {
attrsArr[j] = arguments[i];
}
if (j < attrsArr.length) {
attrsChanged = true;
attrsArr.length = j;
}
/*
* Actually perform the attribute update.
*/
if (attrsChanged) {
for (i = ATTRIBUTES_OFFSET; i < arguments.length; i += 2) {
newAttrs[arguments[i]] = arguments[i + 1];
}
for (var _attr in newAttrs) {
updateAttribute(node, _attr, newAttrs[_attr]);
newAttrs[_attr] = undefined;
}
}
return node;
};
/**
* Declares a virtual Element at the current location in the document. This
* corresponds to an opening tag and a elementClose tag is required. This is
* like elementOpen, but the attributes are defined using the attr function
* rather than being passed as arguments. Must be folllowed by 0 or more calls
* to attr, then a call to elementOpenEnd.
* @param {string} tag The element's tag.
* @param {?string=} key The key used to identify this element. This can be an
* empty string, but performance may be better if a unique value is used
* when iterating over an array of items.
* @param {?Array<*>=} statics An array of attribute name/value pairs of the
* static attributes for the Element. These will only be set once when the
* Element is created.
*/
var elementOpenStart = function (tag, key, statics) {
if ('production' !== 'production') {}
argsBuilder[0] = tag;
argsBuilder[1] = key;
argsBuilder[2] = statics;
};
/***
* Defines a virtual attribute at this point of the DOM. This is only valid
* when called between elementOpenStart and elementOpenEnd.
*
* @param {string} name
* @param {*} value
*/
var attr = function (name, value) {
if ('production' !== 'production') {}
argsBuilder.push(name, value);
};
/**
* Closes an open tag started with elementOpenStart.
* @return {!Element} The corresponding Element.
*/
var elementOpenEnd = function () {
if ('production' !== 'production') {}
var node = elementOpen.apply(null, argsBuilder);
argsBuilder.length = 0;
return node;
};
/**
* Closes an open virtual Element.
*
* @param {string} tag The element's tag.
* @return {!Element} The corresponding Element.
*/
var elementClose = function (tag) {
if ('production' !== 'production') {}
var node = coreElementClose();
if ('production' !== 'production') {}
return node;
};
/**
* Declares a virtual Element at the current location in the document that has
* no children.
* @param {string} tag The element's tag.
* @param {?string=} key The key used to identify this element. This can be an
* empty string, but performance may be better if a unique value is used
* when iterating over an array of items.
* @param {?Array<*>=} statics An array of attribute name/value pairs of the
* static attributes for the Element. These will only be set once when the
* Element is created.
* @param {...*} const_args Attribute name/value pairs of the dynamic attributes
* for the Element.
* @return {!Element} The corresponding Element.
*/
var elementVoid = function (tag, key, statics, const_args) {
elementOpen.apply(null, arguments);
return elementClose(tag);
};
/**
* Declares a virtual Element at the current location in the document that is a
* placeholder element. Children of this Element can be manually managed and
* will not be cleared by the library.
*
* A key must be specified to make sure that this node is correctly preserved
* across all conditionals.
*
* @param {string} tag The element's tag.
* @param {string} key The key used to identify this element.
* @param {?Array<*>=} statics An array of attribute name/value pairs of the
* static attributes for the Element. These will only be set once when the
* Element is created.
* @param {...*} const_args Attribute name/value pairs of the dynamic attributes
* for the Element.
* @return {!Element} The corresponding Element.
*/
var elementPlaceholder = function (tag, key, statics, const_args) {
if ('production' !== 'production') {}
elementOpen.apply(null, arguments);
skip();
return elementClose(tag);
};
/**
* Declares a virtual Text at this point in the document.
*
* @param {string|number|boolean} value The value of the Text.
* @param {...(function((string|number|boolean)):string)} const_args
* Functions to format the value which are called only when the value has
* changed.
* @return {!Text} The corresponding text node.
*/
var text = function (value, const_args) {
if ('production' !== 'production') {}
var node = coreText();
var data = getData(node);
if (data.text !== value) {
data.text = /** @type {string} */value;
var formatted = value;
for (var i = 1; i < arguments.length; i += 1) {
/*
* Call the formatter function directly to prevent leaking arguments.
* https://github.com/google/incremental-dom/pull/204#issuecomment-178223574
*/
var fn = arguments[i];
formatted = fn(formatted);
}
node.data = formatted;
}
return node;
};
exports.patch = patchInner;
exports.patchInner = patchInner;
exports.patchOuter = patchOuter;
exports.currentElement = currentElement;
exports.skip = skip;
exports.elementVoid = elementVoid;
exports.elementOpenStart = elementOpenStart;
exports.elementOpenEnd = elementOpenEnd;
exports.elementOpen = elementOpen;
exports.elementClose = elementClose;
exports.elementPlaceholder = elementPlaceholder;
exports.text = text;
exports.attr = attr;
exports.symbols = symbols;
exports.attributes = attributes;
exports.applyAttr = applyAttr;
exports.applyProp = applyProp;
exports.notifications = notifications;
},{}],2:[function(require,module,exports){
require('./readme.html')
},{"./readme.html":3}],3:[function(require,module,exports){
var IncrementalDOM = require('incremental-dom')
var patch = IncrementalDOM.patch
var elementOpen = IncrementalDOM.elementOpen
var elementClose = IncrementalDOM.elementClose
var skip = IncrementalDOM.skip
var currentElement = IncrementalDOM.currentElement
var text = IncrementalDOM.text
var hoisted1 = ["title", "I will render only once. Subsequent patches will be skipped.", "tag", "div"]
var hoisted2 = ["type", "text"]
var hoisted3 = ["type", "text"]
var hoisted4 = ["title", "hello"]
var hoisted5 = ["class", "list-header"]
module.exports = function bar (foo) {
function add (item) {
todos.push(item)
}
function remove () {
todos.pop()
}
elementOpen("placeholder", "bar", hoisted1)
elementClose("placeholder")
elementOpen("div", null, null, "class", data.cssClass)
elementOpen("a", null, null, "href", "http://www.google.co.uk?q=" + (data.query) + "")
elementClose("a")
text(" \
My name is " + (data.name) + " my age is " + (data.age) + " \
I live at " + (data.address) + " \
\
")
elementOpen("div", null, null, "title", JSON.stringify(data))
text("Hover for json")
elementClose("div")
elementOpen("button", null, null, "onclick", function ($event) {
$event.preventDefault();
var $element = this;
alert(hi)})
text("Say hi")
elementClose("button")
elementOpen("input", "f8ff7cb1-93a9-4e70-b4f9-078c37d296d6", hoisted2, "value", data.val, "onchange", function ($event) {
$event.preventDefault();
var $element = this;
data.val = this.value})
elementClose("input")
if (data.showMe) {
elementOpen("p")
elementOpen("span", null, null, "class", data.bar + ' other-css')
text("description")
elementClose("span")
elementOpen("input", "917d8b92-6fa1-403a-9509-2e200a4a282a", hoisted3, "disabled", data.isDisabled)
elementClose("input")
elementClose("p")
}
if (data.showMe) {
text(" \
I'm in an `if` block. \
")
}
elementOpen("aside")
elementOpen("div")
if (data.skipMe) {
skip()
} else {
elementOpen("span", null, null, "id", data.id)
elementClose("span")
}
elementClose("div")
elementClose("aside")
elementOpen("span", null, null, "style", { color: data.foo, backgroundColor: data.bar })
text("My style changes")
elementClose("span")
elementOpen("ul")
if (data.items) {
;(data.items.forEach ? data.items : Object.keys(data.items)).forEach(function($value, $item, $target) {
var item = $value
var $key = "9bb8d154-1a7a-4ec6-b371-1e330f72bf4a_" + $item
elementOpen("li", $key)
elementOpen("span", null, null, "class", $index % 2 ? 'odd' : 'even' )
text("" + ($index) + "")
elementClose("span")
elementOpen("input", null, null, "value", item.name)
elementClose("input")
elementClose("li")
}, data.items)
}
elementClose("ul")
elementOpen("ul")
if (data.arr) {
;(data.arr.forEach ? data.arr : Object.keys(data.arr)).forEach(function($value, $item, $target) {
var item = $value
var $key = "f498ae3d-1a2e-49d4-9fec-9adfb3c86e83_" + $item
elementOpen("li", $key)
elementOpen("span")
text("" + (item.name) + "")
elementClose("span")
elementClose("li")
}, data.arr)
}
elementClose("ul")
elementOpen("ul")
if (data.obj) {
;(data.obj.forEach ? data.obj : Object.keys(data.obj)).forEach(function($value, $item, $target) {
var key = $value
var $key = "41c921ce-e21e-4d2f-8bca-6d04b9be2607_" + $item
elementOpen("li", $key)
elementOpen("span", "dfe9ba10-585f-4112-9107-0611ccbb8b71_" + $key, hoisted4)
text("" + (key) + " - " + (data.obj[key]) + "")
elementClose("span")
elementClose("li")
}, data.obj)
}
elementClose("ul")
elementOpen("ul")
if (data.products) {
;(data.products.forEach ? data.products : Object.keys(data.products)).forEach(function($value, $item, $target) {
var product = $value
var $key = "d55861d6-3197-42aa-8a54-528ad3042c80_" + product.id
elementOpen("li", $key)
text(" \
" + (product.name) + " \
")
elementClose("li")
}, data.products)
}
elementClose("ul")
elementOpen("ul")
if (data.items.length) {
if (data.arr) {
;(data.arr.forEach ? data.arr : Object.keys(data.arr)).forEach(function($value, $item, $target) {
var item = $value
var $key = "3a378a22-70cd-43fa-a712-85c84ab9f04b_" + item.id
elementOpen("li", $key)
text(" \
" + (item.name) + " \
")
elementClose("li")
}, data.arr)
}
}
if (!data.items.length) {
elementOpen("li", "571cb2b3-64c6-46b3-aa7a-223e7f6439f8", hoisted5)
text(" \
No items found \
")
elementClose("li")
}
elementClose("ul")
elementClose("div")
}
},{"incremental-dom":1}]},{},[2]);