UNPKG

superviewify

Version:

Browserify transform turning superviews.js template language to Googles incremental-dom

1,227 lines (1,074 loc) 34.8 kB
(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. */ 'use strict'; /** * 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]);