| Index: tests/io-element.js |
| =================================================================== |
| new file mode 100644 |
| --- /dev/null |
| +++ b/tests/io-element.js |
| @@ -0,0 +1,3315 @@ |
| +/* eslint-disable */(function(){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}return e})()({1:[function(require,module,exports){ |
| +/* globals module, require */ |
| + |
| +"use strict"; |
| + |
| +// Custom Elements polyfill |
| +const customElementsPonyfill = require("document-register-element/pony"); |
| +if (typeof customElements !== "object") |
| + customElementsPonyfill(window); |
| + |
| +// external dependencies |
| +const {default: HyperHTMLElement} = require("hyperhtml-element/cjs"); |
| + |
| +// provides a unique-id suffix per each component |
| +let counter = 0; |
| + |
| +// common Custom Element class to extend |
| +class IOElement extends HyperHTMLElement |
| +{ |
| + // get a unique ID or, if null, set one and returns it |
| + static getID(element) |
| + { |
| + return element.getAttribute("id") || IOElement.setID(element); |
| + } |
| + |
| + // set a unique ID to a generic element and returns the ID |
| + static setID(element) |
| + { |
| + const id = `${element.nodeName.toLowerCase()}-${counter++}`; |
| + element.setAttribute("id", id); |
| + return id; |
| + } |
| + |
| + // lazily retrieve or define a custom element ID |
| + get id() |
| + { |
| + return IOElement.getID(this); |
| + } |
| + |
| + // whenever an element is created, render its content once |
| + created() { this.render(); } |
| + |
| + // by default, render is a no-op |
| + render() {} |
| +} |
| + |
| +// whenever an interpolation with ${{i18n: 'string-id'}} is found |
| +// transform such value into the expected content |
| +// example: |
| +// render() { |
| +// return this.html`<div>${{i18n:'about-abp'}}</div>`; |
| +// } |
| +const {setElementText} = ext.i18n; |
| +IOElement.intent("i18n", id => |
| +{ |
| + const fragment = document.createDocumentFragment(); |
| + setElementText(fragment, id); |
| + return fragment; |
| +}); |
| + |
| +module.exports = IOElement; |
| + |
| +},{"document-register-element/pony":2,"hyperhtml-element/cjs":3}],2:[function(require,module,exports){ |
| +/*! |
| + |
| +Copyright (C) 2014-2016 by Andrea Giammarchi - @WebReflection |
| + |
| +Permission is hereby granted, free of charge, to any person obtaining a copy |
| +of this software and associated documentation files (the "Software"), to deal |
| +in the Software without restriction, including without limitation the rights |
| +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| +copies of the Software, and to permit persons to whom the Software is |
| +furnished to do so, subject to the following conditions: |
| + |
| +The above copyright notice and this permission notice shall be included in |
| +all copies or substantial portions of the Software. |
| + |
| +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| +THE SOFTWARE. |
| + |
| +*/ |
| +// global window Object |
| +// optional polyfill info |
| +// 'auto' used by default, everything is feature detected |
| +// 'force' use the polyfill even if not fully needed |
| +function installCustomElements(window, polyfill) {'use strict'; |
| + |
| + // DO NOT USE THIS FILE DIRECTLY, IT WON'T WORK |
| + // THIS IS A PROJECT BASED ON A BUILD SYSTEM |
| + // THIS FILE IS JUST WRAPPED UP RESULTING IN |
| + // build/document-register-element.node.js |
| + |
| + var |
| + document = window.document, |
| + Object = window.Object |
| + ; |
| + |
| + var htmlClass = (function (info) { |
| + // (C) Andrea Giammarchi - @WebReflection - MIT Style |
| + var |
| + catchClass = /^[A-Z]+[a-z]/, |
| + filterBy = function (re) { |
| + var arr = [], tag; |
| + for (tag in register) { |
| + if (re.test(tag)) arr.push(tag); |
| + } |
| + return arr; |
| + }, |
| + add = function (Class, tag) { |
| + tag = tag.toLowerCase(); |
| + if (!(tag in register)) { |
| + register[Class] = (register[Class] || []).concat(tag); |
| + register[tag] = (register[tag.toUpperCase()] = Class); |
| + } |
| + }, |
| + register = (Object.create || Object)(null), |
| + htmlClass = {}, |
| + i, section, tags, Class |
| + ; |
| + for (section in info) { |
| + for (Class in info[section]) { |
| + tags = info[section][Class]; |
| + register[Class] = tags; |
| + for (i = 0; i < tags.length; i++) { |
| + register[tags[i].toLowerCase()] = |
| + register[tags[i].toUpperCase()] = Class; |
| + } |
| + } |
| + } |
| + htmlClass.get = function get(tagOrClass) { |
| + return typeof tagOrClass === 'string' ? |
| + (register[tagOrClass] || (catchClass.test(tagOrClass) ? [] : '')) : |
| + filterBy(tagOrClass); |
| + }; |
| + htmlClass.set = function set(tag, Class) { |
| + return (catchClass.test(tag) ? |
| + add(tag, Class) : |
| + add(Class, tag) |
| + ), htmlClass; |
| + }; |
| + return htmlClass; |
| + }({ |
| + "collections": { |
| + "HTMLAllCollection": [ |
| + "all" |
| + ], |
| + "HTMLCollection": [ |
| + "forms" |
| + ], |
| + "HTMLFormControlsCollection": [ |
| + "elements" |
| + ], |
| + "HTMLOptionsCollection": [ |
| + "options" |
| + ] |
| + }, |
| + "elements": { |
| + "Element": [ |
| + "element" |
| + ], |
| + "HTMLAnchorElement": [ |
| + "a" |
| + ], |
| + "HTMLAppletElement": [ |
| + "applet" |
| + ], |
| + "HTMLAreaElement": [ |
| + "area" |
| + ], |
| + "HTMLAttachmentElement": [ |
| + "attachment" |
| + ], |
| + "HTMLAudioElement": [ |
| + "audio" |
| + ], |
| + "HTMLBRElement": [ |
| + "br" |
| + ], |
| + "HTMLBaseElement": [ |
| + "base" |
| + ], |
| + "HTMLBodyElement": [ |
| + "body" |
| + ], |
| + "HTMLButtonElement": [ |
| + "button" |
| + ], |
| + "HTMLCanvasElement": [ |
| + "canvas" |
| + ], |
| + "HTMLContentElement": [ |
| + "content" |
| + ], |
| + "HTMLDListElement": [ |
| + "dl" |
| + ], |
| + "HTMLDataElement": [ |
| + "data" |
| + ], |
| + "HTMLDataListElement": [ |
| + "datalist" |
| + ], |
| + "HTMLDetailsElement": [ |
| + "details" |
| + ], |
| + "HTMLDialogElement": [ |
| + "dialog" |
| + ], |
| + "HTMLDirectoryElement": [ |
| + "dir" |
| + ], |
| + "HTMLDivElement": [ |
| + "div" |
| + ], |
| + "HTMLDocument": [ |
| + "document" |
| + ], |
| + "HTMLElement": [ |
| + "element", |
| + "abbr", |
| + "address", |
| + "article", |
| + "aside", |
| + "b", |
| + "bdi", |
| + "bdo", |
| + "cite", |
| + "code", |
| + "command", |
| + "dd", |
| + "dfn", |
| + "dt", |
| + "em", |
| + "figcaption", |
| + "figure", |
| + "footer", |
| + "header", |
| + "i", |
| + "kbd", |
| + "mark", |
| + "nav", |
| + "noscript", |
| + "rp", |
| + "rt", |
| + "ruby", |
| + "s", |
| + "samp", |
| + "section", |
| + "small", |
| + "strong", |
| + "sub", |
| + "summary", |
| + "sup", |
| + "u", |
| + "var", |
| + "wbr" |
| + ], |
| + "HTMLEmbedElement": [ |
| + "embed" |
| + ], |
| + "HTMLFieldSetElement": [ |
| + "fieldset" |
| + ], |
| + "HTMLFontElement": [ |
| + "font" |
| + ], |
| + "HTMLFormElement": [ |
| + "form" |
| + ], |
| + "HTMLFrameElement": [ |
| + "frame" |
| + ], |
| + "HTMLFrameSetElement": [ |
| + "frameset" |
| + ], |
| + "HTMLHRElement": [ |
| + "hr" |
| + ], |
| + "HTMLHeadElement": [ |
| + "head" |
| + ], |
| + "HTMLHeadingElement": [ |
| + "h1", |
| + "h2", |
| + "h3", |
| + "h4", |
| + "h5", |
| + "h6" |
| + ], |
| + "HTMLHtmlElement": [ |
| + "html" |
| + ], |
| + "HTMLIFrameElement": [ |
| + "iframe" |
| + ], |
| + "HTMLImageElement": [ |
| + "img" |
| + ], |
| + "HTMLInputElement": [ |
| + "input" |
| + ], |
| + "HTMLKeygenElement": [ |
| + "keygen" |
| + ], |
| + "HTMLLIElement": [ |
| + "li" |
| + ], |
| + "HTMLLabelElement": [ |
| + "label" |
| + ], |
| + "HTMLLegendElement": [ |
| + "legend" |
| + ], |
| + "HTMLLinkElement": [ |
| + "link" |
| + ], |
| + "HTMLMapElement": [ |
| + "map" |
| + ], |
| + "HTMLMarqueeElement": [ |
| + "marquee" |
| + ], |
| + "HTMLMediaElement": [ |
| + "media" |
| + ], |
| + "HTMLMenuElement": [ |
| + "menu" |
| + ], |
| + "HTMLMenuItemElement": [ |
| + "menuitem" |
| + ], |
| + "HTMLMetaElement": [ |
| + "meta" |
| + ], |
| + "HTMLMeterElement": [ |
| + "meter" |
| + ], |
| + "HTMLModElement": [ |
| + "del", |
| + "ins" |
| + ], |
| + "HTMLOListElement": [ |
| + "ol" |
| + ], |
| + "HTMLObjectElement": [ |
| + "object" |
| + ], |
| + "HTMLOptGroupElement": [ |
| + "optgroup" |
| + ], |
| + "HTMLOptionElement": [ |
| + "option" |
| + ], |
| + "HTMLOutputElement": [ |
| + "output" |
| + ], |
| + "HTMLParagraphElement": [ |
| + "p" |
| + ], |
| + "HTMLParamElement": [ |
| + "param" |
| + ], |
| + "HTMLPictureElement": [ |
| + "picture" |
| + ], |
| + "HTMLPreElement": [ |
| + "pre" |
| + ], |
| + "HTMLProgressElement": [ |
| + "progress" |
| + ], |
| + "HTMLQuoteElement": [ |
| + "blockquote", |
| + "q", |
| + "quote" |
| + ], |
| + "HTMLScriptElement": [ |
| + "script" |
| + ], |
| + "HTMLSelectElement": [ |
| + "select" |
| + ], |
| + "HTMLShadowElement": [ |
| + "shadow" |
| + ], |
| + "HTMLSlotElement": [ |
| + "slot" |
| + ], |
| + "HTMLSourceElement": [ |
| + "source" |
| + ], |
| + "HTMLSpanElement": [ |
| + "span" |
| + ], |
| + "HTMLStyleElement": [ |
| + "style" |
| + ], |
| + "HTMLTableCaptionElement": [ |
| + "caption" |
| + ], |
| + "HTMLTableCellElement": [ |
| + "td", |
| + "th" |
| + ], |
| + "HTMLTableColElement": [ |
| + "col", |
| + "colgroup" |
| + ], |
| + "HTMLTableElement": [ |
| + "table" |
| + ], |
| + "HTMLTableRowElement": [ |
| + "tr" |
| + ], |
| + "HTMLTableSectionElement": [ |
| + "thead", |
| + "tbody", |
| + "tfoot" |
| + ], |
| + "HTMLTemplateElement": [ |
| + "template" |
| + ], |
| + "HTMLTextAreaElement": [ |
| + "textarea" |
| + ], |
| + "HTMLTimeElement": [ |
| + "time" |
| + ], |
| + "HTMLTitleElement": [ |
| + "title" |
| + ], |
| + "HTMLTrackElement": [ |
| + "track" |
| + ], |
| + "HTMLUListElement": [ |
| + "ul" |
| + ], |
| + "HTMLUnknownElement": [ |
| + "unknown", |
| + "vhgroupv", |
| + "vkeygen" |
| + ], |
| + "HTMLVideoElement": [ |
| + "video" |
| + ] |
| + }, |
| + "nodes": { |
| + "Attr": [ |
| + "node" |
| + ], |
| + "Audio": [ |
| + "audio" |
| + ], |
| + "CDATASection": [ |
| + "node" |
| + ], |
| + "CharacterData": [ |
| + "node" |
| + ], |
| + "Comment": [ |
| + "#comment" |
| + ], |
| + "Document": [ |
| + "#document" |
| + ], |
| + "DocumentFragment": [ |
| + "#document-fragment" |
| + ], |
| + "DocumentType": [ |
| + "node" |
| + ], |
| + "HTMLDocument": [ |
| + "#document" |
| + ], |
| + "Image": [ |
| + "img" |
| + ], |
| + "Option": [ |
| + "option" |
| + ], |
| + "ProcessingInstruction": [ |
| + "node" |
| + ], |
| + "ShadowRoot": [ |
| + "#shadow-root" |
| + ], |
| + "Text": [ |
| + "#text" |
| + ], |
| + "XMLDocument": [ |
| + "xml" |
| + ] |
| + } |
| + })); |
| + |
| + |
| + |
| + // passed at runtime, configurable via nodejs module |
| + if (typeof polyfill !== 'object') polyfill = {type: polyfill || 'auto'}; |
| + |
| + var |
| + // V0 polyfill entry |
| + REGISTER_ELEMENT = 'registerElement', |
| + |
| + // IE < 11 only + old WebKit for attributes + feature detection |
| + EXPANDO_UID = '__' + REGISTER_ELEMENT + (window.Math.random() * 10e4 >> 0), |
| + |
| + // shortcuts and costants |
| + ADD_EVENT_LISTENER = 'addEventListener', |
| + ATTACHED = 'attached', |
| + CALLBACK = 'Callback', |
| + DETACHED = 'detached', |
| + EXTENDS = 'extends', |
| + |
| + ATTRIBUTE_CHANGED_CALLBACK = 'attributeChanged' + CALLBACK, |
| + ATTACHED_CALLBACK = ATTACHED + CALLBACK, |
| + CONNECTED_CALLBACK = 'connected' + CALLBACK, |
| + DISCONNECTED_CALLBACK = 'disconnected' + CALLBACK, |
| + CREATED_CALLBACK = 'created' + CALLBACK, |
| + DETACHED_CALLBACK = DETACHED + CALLBACK, |
| + |
| + ADDITION = 'ADDITION', |
| + MODIFICATION = 'MODIFICATION', |
| + REMOVAL = 'REMOVAL', |
| + |
| + DOM_ATTR_MODIFIED = 'DOMAttrModified', |
| + DOM_CONTENT_LOADED = 'DOMContentLoaded', |
| + DOM_SUBTREE_MODIFIED = 'DOMSubtreeModified', |
| + |
| + PREFIX_TAG = '<', |
| + PREFIX_IS = '=', |
| + |
| + // valid and invalid node names |
| + validName = /^[A-Z][A-Z0-9]*(?:-[A-Z0-9]+)+$/, |
| + invalidNames = [ |
| + 'ANNOTATION-XML', |
| + 'COLOR-PROFILE', |
| + 'FONT-FACE', |
| + 'FONT-FACE-SRC', |
| + 'FONT-FACE-URI', |
| + 'FONT-FACE-FORMAT', |
| + 'FONT-FACE-NAME', |
| + 'MISSING-GLYPH' |
| + ], |
| + |
| + // registered types and their prototypes |
| + types = [], |
| + protos = [], |
| + |
| + // to query subnodes |
| + query = '', |
| + |
| + // html shortcut used to feature detect |
| + documentElement = document.documentElement, |
| + |
| + // ES5 inline helpers || basic patches |
| + indexOf = types.indexOf || function (v) { |
| + for(var i = this.length; i-- && this[i] !== v;){} |
| + return i; |
| + }, |
| + |
| + // other helpers / shortcuts |
| + OP = Object.prototype, |
| + hOP = OP.hasOwnProperty, |
| + iPO = OP.isPrototypeOf, |
| + |
| + defineProperty = Object.defineProperty, |
| + empty = [], |
| + gOPD = Object.getOwnPropertyDescriptor, |
| + gOPN = Object.getOwnPropertyNames, |
| + gPO = Object.getPrototypeOf, |
| + sPO = Object.setPrototypeOf, |
| + |
| + // jshint proto: true |
| + hasProto = !!Object.__proto__, |
| + |
| + // V1 helpers |
| + fixGetClass = false, |
| + DRECEV1 = '__dreCEv1', |
| + customElements = window.customElements, |
| + usableCustomElements = !/^force/.test(polyfill.type) && !!( |
| + customElements && |
| + customElements.define && |
| + customElements.get && |
| + customElements.whenDefined |
| + ), |
| + Dict = Object.create || Object, |
| + Map = window.Map || function Map() { |
| + var K = [], V = [], i; |
| + return { |
| + get: function (k) { |
| + return V[indexOf.call(K, k)]; |
| + }, |
| + set: function (k, v) { |
| + i = indexOf.call(K, k); |
| + if (i < 0) V[K.push(k) - 1] = v; |
| + else V[i] = v; |
| + } |
| + }; |
| + }, |
| + Promise = window.Promise || function (fn) { |
| + var |
| + notify = [], |
| + done = false, |
| + p = { |
| + 'catch': function () { |
| + return p; |
| + }, |
| + 'then': function (cb) { |
| + notify.push(cb); |
| + if (done) setTimeout(resolve, 1); |
| + return p; |
| + } |
| + } |
| + ; |
| + function resolve(value) { |
| + done = true; |
| + while (notify.length) notify.shift()(value); |
| + } |
| + fn(resolve); |
| + return p; |
| + }, |
| + justCreated = false, |
| + constructors = Dict(null), |
| + waitingList = Dict(null), |
| + nodeNames = new Map(), |
| + secondArgument = function (is) { |
| + return is.toLowerCase(); |
| + }, |
| + |
| + // used to create unique instances |
| + create = Object.create || function Bridge(proto) { |
| + // silly broken polyfill probably ever used but short enough to work |
| + return proto ? ((Bridge.prototype = proto), new Bridge()) : this; |
| + }, |
| + |
| + // will set the prototype if possible |
| + // or copy over all properties |
| + setPrototype = sPO || ( |
| + hasProto ? |
| + function (o, p) { |
| + o.__proto__ = p; |
| + return o; |
| + } : ( |
| + (gOPN && gOPD) ? |
| + (function(){ |
| + function setProperties(o, p) { |
| + for (var |
| + key, |
| + names = gOPN(p), |
| + i = 0, length = names.length; |
| + i < length; i++ |
| + ) { |
| + key = names[i]; |
| + if (!hOP.call(o, key)) { |
| + defineProperty(o, key, gOPD(p, key)); |
| + } |
| + } |
| + } |
| + return function (o, p) { |
| + do { |
| + setProperties(o, p); |
| + } while ((p = gPO(p)) && !iPO.call(p, o)); |
| + return o; |
| + }; |
| + }()) : |
| + function (o, p) { |
| + for (var key in p) { |
| + o[key] = p[key]; |
| + } |
| + return o; |
| + } |
| + )), |
| + |
| + // DOM shortcuts and helpers, if any |
| + |
| + MutationObserver = window.MutationObserver || |
| + window.WebKitMutationObserver, |
| + |
| + HTMLElementPrototype = ( |
| + window.HTMLElement || |
| + window.Element || |
| + window.Node |
| + ).prototype, |
| + |
| + IE8 = !iPO.call(HTMLElementPrototype, documentElement), |
| + |
| + safeProperty = IE8 ? function (o, k, d) { |
| + o[k] = d.value; |
| + return o; |
| + } : defineProperty, |
| + |
| + isValidNode = IE8 ? |
| + function (node) { |
| + return node.nodeType === 1; |
| + } : |
| + function (node) { |
| + return iPO.call(HTMLElementPrototype, node); |
| + }, |
| + |
| + targets = IE8 && [], |
| + |
| + attachShadow = HTMLElementPrototype.attachShadow, |
| + cloneNode = HTMLElementPrototype.cloneNode, |
| + dispatchEvent = HTMLElementPrototype.dispatchEvent, |
| + getAttribute = HTMLElementPrototype.getAttribute, |
| + hasAttribute = HTMLElementPrototype.hasAttribute, |
| + removeAttribute = HTMLElementPrototype.removeAttribute, |
| + setAttribute = HTMLElementPrototype.setAttribute, |
| + |
| + // replaced later on |
| + createElement = document.createElement, |
| + patchedCreateElement = createElement, |
| + |
| + // shared observer for all attributes |
| + attributesObserver = MutationObserver && { |
| + attributes: true, |
| + characterData: true, |
| + attributeOldValue: true |
| + }, |
| + |
| + // useful to detect only if there's no MutationObserver |
| + DOMAttrModified = MutationObserver || function(e) { |
| + doesNotSupportDOMAttrModified = false; |
| + documentElement.removeEventListener( |
| + DOM_ATTR_MODIFIED, |
| + DOMAttrModified |
| + ); |
| + }, |
| + |
| + // will both be used to make DOMNodeInserted asynchronous |
| + asapQueue, |
| + asapTimer = 0, |
| + |
| + // internal flags |
| + V0 = REGISTER_ELEMENT in document && |
| + !/^force-all/.test(polyfill.type), |
| + setListener = true, |
| + justSetup = false, |
| + doesNotSupportDOMAttrModified = true, |
| + dropDomContentLoaded = true, |
| + |
| + // needed for the innerHTML helper |
| + notFromInnerHTMLHelper = true, |
| + |
| + // optionally defined later on |
| + onSubtreeModified, |
| + callDOMAttrModified, |
| + getAttributesMirror, |
| + observer, |
| + observe, |
| + |
| + // based on setting prototype capability |
| + // will check proto or the expando attribute |
| + // in order to setup the node once |
| + patchIfNotAlready, |
| + patch |
| + ; |
| + |
| + // only if needed |
| + if (!V0) { |
| + |
| + if (sPO || hasProto) { |
| + patchIfNotAlready = function (node, proto) { |
| + if (!iPO.call(proto, node)) { |
| + setupNode(node, proto); |
| + } |
| + }; |
| + patch = setupNode; |
| + } else { |
| + patchIfNotAlready = function (node, proto) { |
| + if (!node[EXPANDO_UID]) { |
| + node[EXPANDO_UID] = Object(true); |
| + setupNode(node, proto); |
| + } |
| + }; |
| + patch = patchIfNotAlready; |
| + } |
| + |
| + if (IE8) { |
| + doesNotSupportDOMAttrModified = false; |
| + (function (){ |
| + var |
| + descriptor = gOPD(HTMLElementPrototype, ADD_EVENT_LISTENER), |
| + addEventListener = descriptor.value, |
| + patchedRemoveAttribute = function (name) { |
| + var e = new CustomEvent(DOM_ATTR_MODIFIED, {bubbles: true}); |
| + e.attrName = name; |
| + e.prevValue = getAttribute.call(this, name); |
| + e.newValue = null; |
| + e[REMOVAL] = e.attrChange = 2; |
| + removeAttribute.call(this, name); |
| + dispatchEvent.call(this, e); |
| + }, |
| + patchedSetAttribute = function (name, value) { |
| + var |
| + had = hasAttribute.call(this, name), |
| + old = had && getAttribute.call(this, name), |
| + e = new CustomEvent(DOM_ATTR_MODIFIED, {bubbles: true}) |
| + ; |
| + setAttribute.call(this, name, value); |
| + e.attrName = name; |
| + e.prevValue = had ? old : null; |
| + e.newValue = value; |
| + if (had) { |
| + e[MODIFICATION] = e.attrChange = 1; |
| + } else { |
| + e[ADDITION] = e.attrChange = 0; |
| + } |
| + dispatchEvent.call(this, e); |
| + }, |
| + onPropertyChange = function (e) { |
| + // jshint eqnull:true |
| + var |
| + node = e.currentTarget, |
| + superSecret = node[EXPANDO_UID], |
| + propertyName = e.propertyName, |
| + event |
| + ; |
| + if (superSecret.hasOwnProperty(propertyName)) { |
| + superSecret = superSecret[propertyName]; |
| + event = new CustomEvent(DOM_ATTR_MODIFIED, {bubbles: true}); |
| + event.attrName = superSecret.name; |
| + event.prevValue = superSecret.value || null; |
| + event.newValue = (superSecret.value = node[propertyName] || null); |
| + if (event.prevValue == null) { |
| + event[ADDITION] = event.attrChange = 0; |
| + } else { |
| + event[MODIFICATION] = event.attrChange = 1; |
| + } |
| + dispatchEvent.call(node, event); |
| + } |
| + } |
| + ; |
| + descriptor.value = function (type, handler, capture) { |
| + if ( |
| + type === DOM_ATTR_MODIFIED && |
| + this[ATTRIBUTE_CHANGED_CALLBACK] && |
| + this.setAttribute !== patchedSetAttribute |
| + ) { |
| + this[EXPANDO_UID] = { |
| + className: { |
| + name: 'class', |
| + value: this.className |
| + } |
| + }; |
| + this.setAttribute = patchedSetAttribute; |
| + this.removeAttribute = patchedRemoveAttribute; |
| + addEventListener.call(this, 'propertychange', onPropertyChange); |
| + } |
| + addEventListener.call(this, type, handler, capture); |
| + }; |
| + defineProperty(HTMLElementPrototype, ADD_EVENT_LISTENER, descriptor); |
| + }()); |
| + } else if (!MutationObserver) { |
| + documentElement[ADD_EVENT_LISTENER](DOM_ATTR_MODIFIED, DOMAttrModified); |
| + documentElement.setAttribute(EXPANDO_UID, 1); |
| + documentElement.removeAttribute(EXPANDO_UID); |
| + if (doesNotSupportDOMAttrModified) { |
| + onSubtreeModified = function (e) { |
| + var |
| + node = this, |
| + oldAttributes, |
| + newAttributes, |
| + key |
| + ; |
| + if (node === e.target) { |
| + oldAttributes = node[EXPANDO_UID]; |
| + node[EXPANDO_UID] = (newAttributes = getAttributesMirror(node)); |
| + for (key in newAttributes) { |
| + if (!(key in oldAttributes)) { |
| + // attribute was added |
| + return callDOMAttrModified( |
| + 0, |
| + node, |
| + key, |
| + oldAttributes[key], |
| + newAttributes[key], |
| + ADDITION |
| + ); |
| + } else if (newAttributes[key] !== oldAttributes[key]) { |
| + // attribute was changed |
| + return callDOMAttrModified( |
| + 1, |
| + node, |
| + key, |
| + oldAttributes[key], |
| + newAttributes[key], |
| + MODIFICATION |
| + ); |
| + } |
| + } |
| + // checking if it has been removed |
| + for (key in oldAttributes) { |
| + if (!(key in newAttributes)) { |
| + // attribute removed |
| + return callDOMAttrModified( |
| + 2, |
| + node, |
| + key, |
| + oldAttributes[key], |
| + newAttributes[key], |
| + REMOVAL |
| + ); |
| + } |
| + } |
| + } |
| + }; |
| + callDOMAttrModified = function ( |
| + attrChange, |
| + currentTarget, |
| + attrName, |
| + prevValue, |
| + newValue, |
| + action |
| + ) { |
| + var e = { |
| + attrChange: attrChange, |
| + currentTarget: currentTarget, |
| + attrName: attrName, |
| + prevValue: prevValue, |
| + newValue: newValue |
| + }; |
| + e[action] = attrChange; |
| + onDOMAttrModified(e); |
| + }; |
| + getAttributesMirror = function (node) { |
| + for (var |
| + attr, name, |
| + result = {}, |
| + attributes = node.attributes, |
| + i = 0, length = attributes.length; |
| + i < length; i++ |
| + ) { |
| + attr = attributes[i]; |
| + name = attr.name; |
| + if (name !== 'setAttribute') { |
| + result[name] = attr.value; |
| + } |
| + } |
| + return result; |
| + }; |
| + } |
| + } |
| + |
| + // set as enumerable, writable and configurable |
| + document[REGISTER_ELEMENT] = function registerElement(type, options) { |
| + upperType = type.toUpperCase(); |
| + if (setListener) { |
| + // only first time document.registerElement is used |
| + // we need to set this listener |
| + // setting it by default might slow down for no reason |
| + setListener = false; |
| + if (MutationObserver) { |
| + observer = (function(attached, detached){ |
| + function checkEmAll(list, callback) { |
| + for (var i = 0, length = list.length; i < length; callback(list[i++])){} |
| + } |
| + return new MutationObserver(function (records) { |
| + for (var |
| + current, node, newValue, |
| + i = 0, length = records.length; i < length; i++ |
| + ) { |
| + current = records[i]; |
| + if (current.type === 'childList') { |
| + checkEmAll(current.addedNodes, attached); |
| + checkEmAll(current.removedNodes, detached); |
| + } else { |
| + node = current.target; |
| + if (notFromInnerHTMLHelper && |
| + node[ATTRIBUTE_CHANGED_CALLBACK] && |
| + current.attributeName !== 'style') { |
| + newValue = getAttribute.call(node, current.attributeName); |
| + if (newValue !== current.oldValue) { |
| + node[ATTRIBUTE_CHANGED_CALLBACK]( |
| + current.attributeName, |
| + current.oldValue, |
| + newValue |
| + ); |
| + } |
| + } |
| + } |
| + } |
| + }); |
| + }(executeAction(ATTACHED), executeAction(DETACHED))); |
| + observe = function (node) { |
| + observer.observe( |
| + node, |
| + { |
| + childList: true, |
| + subtree: true |
| + } |
| + ); |
| + return node; |
| + }; |
| + observe(document); |
| + if (attachShadow) { |
| + HTMLElementPrototype.attachShadow = function () { |
| + return observe(attachShadow.apply(this, arguments)); |
| + }; |
| + } |
| + } else { |
| + asapQueue = []; |
| + document[ADD_EVENT_LISTENER]('DOMNodeInserted', onDOMNode(ATTACHED)); |
| + document[ADD_EVENT_LISTENER]('DOMNodeRemoved', onDOMNode(DETACHED)); |
| + } |
| + |
| + document[ADD_EVENT_LISTENER](DOM_CONTENT_LOADED, onReadyStateChange); |
| + document[ADD_EVENT_LISTENER]('readystatechange', onReadyStateChange); |
| + |
| + HTMLElementPrototype.cloneNode = function (deep) { |
| + var |
| + node = cloneNode.call(this, !!deep), |
| + i = getTypeIndex(node) |
| + ; |
| + if (-1 < i) patch(node, protos[i]); |
| + if (deep && query.length) loopAndSetup(node.querySelectorAll(query)); |
| + return node; |
| + }; |
| + } |
| + |
| + if (justSetup) return (justSetup = false); |
| + |
| + if (-2 < ( |
| + indexOf.call(types, PREFIX_IS + upperType) + |
| + indexOf.call(types, PREFIX_TAG + upperType) |
| + )) { |
| + throwTypeError(type); |
| + } |
| + |
| + if (!validName.test(upperType) || -1 < indexOf.call(invalidNames, upperType)) { |
| + throw new Error('The type ' + type + ' is invalid'); |
| + } |
| + |
| + var |
| + constructor = function () { |
| + return extending ? |
| + document.createElement(nodeName, upperType) : |
| + document.createElement(nodeName); |
| + }, |
| + opt = options || OP, |
| + extending = hOP.call(opt, EXTENDS), |
| + nodeName = extending ? options[EXTENDS].toUpperCase() : upperType, |
| + upperType, |
| + i |
| + ; |
| + |
| + if (extending && -1 < ( |
| + indexOf.call(types, PREFIX_TAG + nodeName) |
| + )) { |
| + throwTypeError(nodeName); |
| + } |
| + |
| + i = types.push((extending ? PREFIX_IS : PREFIX_TAG) + upperType) - 1; |
| + |
| + query = query.concat( |
| + query.length ? ',' : '', |
| + extending ? nodeName + '[is="' + type.toLowerCase() + '"]' : nodeName |
| + ); |
| + |
| + constructor.prototype = ( |
| + protos[i] = hOP.call(opt, 'prototype') ? |
| + opt.prototype : |
| + create(HTMLElementPrototype) |
| + ); |
| + |
| + if (query.length) loopAndVerify( |
| + document.querySelectorAll(query), |
| + ATTACHED |
| + ); |
| + |
| + return constructor; |
| + }; |
| + |
| + document.createElement = (patchedCreateElement = function (localName, typeExtension) { |
| + var |
| + is = getIs(typeExtension), |
| + node = is ? |
| + createElement.call(document, localName, secondArgument(is)) : |
| + createElement.call(document, localName), |
| + name = '' + localName, |
| + i = indexOf.call( |
| + types, |
| + (is ? PREFIX_IS : PREFIX_TAG) + |
| + (is || name).toUpperCase() |
| + ), |
| + setup = -1 < i |
| + ; |
| + if (is) { |
| + node.setAttribute('is', is = is.toLowerCase()); |
| + if (setup) { |
| + setup = isInQSA(name.toUpperCase(), is); |
| + } |
| + } |
| + notFromInnerHTMLHelper = !document.createElement.innerHTMLHelper; |
| + if (setup) patch(node, protos[i]); |
| + return node; |
| + }); |
| + |
| + } |
| + |
| + function ASAP() { |
| + var queue = asapQueue.splice(0, asapQueue.length); |
| + asapTimer = 0; |
| + while (queue.length) { |
| + queue.shift().call( |
| + null, queue.shift() |
| + ); |
| + } |
| + } |
| + |
| + function loopAndVerify(list, action) { |
| + for (var i = 0, length = list.length; i < length; i++) { |
| + verifyAndSetupAndAction(list[i], action); |
| + } |
| + } |
| + |
| + function loopAndSetup(list) { |
| + for (var i = 0, length = list.length, node; i < length; i++) { |
| + node = list[i]; |
| + patch(node, protos[getTypeIndex(node)]); |
| + } |
| + } |
| + |
| + function executeAction(action) { |
| + return function (node) { |
| + if (isValidNode(node)) { |
| + verifyAndSetupAndAction(node, action); |
| + if (query.length) loopAndVerify( |
| + node.querySelectorAll(query), |
| + action |
| + ); |
| + } |
| + }; |
| + } |
| + |
| + function getTypeIndex(target) { |
| + var |
| + is = getAttribute.call(target, 'is'), |
| + nodeName = target.nodeName.toUpperCase(), |
| + i = indexOf.call( |
| + types, |
| + is ? |
| + PREFIX_IS + is.toUpperCase() : |
| + PREFIX_TAG + nodeName |
| + ) |
| + ; |
| + return is && -1 < i && !isInQSA(nodeName, is) ? -1 : i; |
| + } |
| + |
| + function isInQSA(name, type) { |
| + return -1 < query.indexOf(name + '[is="' + type + '"]'); |
| + } |
| + |
| + function onDOMAttrModified(e) { |
| + var |
| + node = e.currentTarget, |
| + attrChange = e.attrChange, |
| + attrName = e.attrName, |
| + target = e.target, |
| + addition = e[ADDITION] || 2, |
| + removal = e[REMOVAL] || 3 |
| + ; |
| + if (notFromInnerHTMLHelper && |
| + (!target || target === node) && |
| + node[ATTRIBUTE_CHANGED_CALLBACK] && |
| + attrName !== 'style' && ( |
| + e.prevValue !== e.newValue || |
| + // IE9, IE10, and Opera 12 gotcha |
| + e.newValue === '' && ( |
| + attrChange === addition || |
| + attrChange === removal |
| + ) |
| + )) { |
| + node[ATTRIBUTE_CHANGED_CALLBACK]( |
| + attrName, |
| + attrChange === addition ? null : e.prevValue, |
| + attrChange === removal ? null : e.newValue |
| + ); |
| + } |
| + } |
| + |
| + function onDOMNode(action) { |
| + var executor = executeAction(action); |
| + return function (e) { |
| + asapQueue.push(executor, e.target); |
| + if (asapTimer) clearTimeout(asapTimer); |
| + asapTimer = setTimeout(ASAP, 1); |
| + }; |
| + } |
| + |
| + function onReadyStateChange(e) { |
| + if (dropDomContentLoaded) { |
| + dropDomContentLoaded = false; |
| + e.currentTarget.removeEventListener(DOM_CONTENT_LOADED, onReadyStateChange); |
| + } |
| + if (query.length) loopAndVerify( |
| + (e.target || document).querySelectorAll(query), |
| + e.detail === DETACHED ? DETACHED : ATTACHED |
| + ); |
| + if (IE8) purge(); |
| + } |
| + |
| + function patchedSetAttribute(name, value) { |
| + // jshint validthis:true |
| + var self = this; |
| + setAttribute.call(self, name, value); |
| + onSubtreeModified.call(self, {target: self}); |
| + } |
| + |
| + function setupNode(node, proto) { |
| + setPrototype(node, proto); |
| + if (observer) { |
| + observer.observe(node, attributesObserver); |
| + } else { |
| + if (doesNotSupportDOMAttrModified) { |
| + node.setAttribute = patchedSetAttribute; |
| + node[EXPANDO_UID] = getAttributesMirror(node); |
| + node[ADD_EVENT_LISTENER](DOM_SUBTREE_MODIFIED, onSubtreeModified); |
| + } |
| + node[ADD_EVENT_LISTENER](DOM_ATTR_MODIFIED, onDOMAttrModified); |
| + } |
| + if (node[CREATED_CALLBACK] && notFromInnerHTMLHelper) { |
| + node.created = true; |
| + node[CREATED_CALLBACK](); |
| + node.created = false; |
| + } |
| + } |
| + |
| + function purge() { |
| + for (var |
| + node, |
| + i = 0, |
| + length = targets.length; |
| + i < length; i++ |
| + ) { |
| + node = targets[i]; |
| + if (!documentElement.contains(node)) { |
| + length--; |
| + targets.splice(i--, 1); |
| + verifyAndSetupAndAction(node, DETACHED); |
| + } |
| + } |
| + } |
| + |
| + function throwTypeError(type) { |
| + throw new Error('A ' + type + ' type is already registered'); |
| + } |
| + |
| + function verifyAndSetupAndAction(node, action) { |
| + var |
| + fn, |
| + i = getTypeIndex(node), |
| + counterAction |
| + ; |
| + if (-1 < i) { |
| + patchIfNotAlready(node, protos[i]); |
| + i = 0; |
| + if (action === ATTACHED && !node[ATTACHED]) { |
| + node[DETACHED] = false; |
| + node[ATTACHED] = true; |
| + counterAction = 'connected'; |
| + i = 1; |
| + if (IE8 && indexOf.call(targets, node) < 0) { |
| + targets.push(node); |
| + } |
| + } else if (action === DETACHED && !node[DETACHED]) { |
| + node[ATTACHED] = false; |
| + node[DETACHED] = true; |
| + counterAction = 'disconnected'; |
| + i = 1; |
| + } |
| + if (i && (fn = ( |
| + node[action + CALLBACK] || |
| + node[counterAction + CALLBACK] |
| + ))) fn.call(node); |
| + } |
| + } |
| + |
| + |
| + |
| + // V1 in da House! |
| + function CustomElementRegistry() {} |
| + |
| + CustomElementRegistry.prototype = { |
| + constructor: CustomElementRegistry, |
| + // a workaround for the stubborn WebKit |
| + define: usableCustomElements ? |
| + function (name, Class, options) { |
| + if (options) { |
| + CERDefine(name, Class, options); |
| + } else { |
| + var NAME = name.toUpperCase(); |
| + constructors[NAME] = { |
| + constructor: Class, |
| + create: [NAME] |
| + }; |
| + nodeNames.set(Class, NAME); |
| + customElements.define(name, Class); |
| + } |
| + } : |
| + CERDefine, |
| + get: usableCustomElements ? |
| + function (name) { |
| + return customElements.get(name) || get(name); |
| + } : |
| + get, |
| + whenDefined: usableCustomElements ? |
| + function (name) { |
| + return Promise.race([ |
| + customElements.whenDefined(name), |
| + whenDefined(name) |
| + ]); |
| + } : |
| + whenDefined |
| + }; |
| + |
| + function CERDefine(name, Class, options) { |
| + var |
| + is = options && options[EXTENDS] || '', |
| + CProto = Class.prototype, |
| + proto = create(CProto), |
| + attributes = Class.observedAttributes || empty, |
| + definition = {prototype: proto} |
| + ; |
| + // TODO: is this needed at all since it's inherited? |
| + // defineProperty(proto, 'constructor', {value: Class}); |
| + safeProperty(proto, CREATED_CALLBACK, { |
| + value: function () { |
| + if (justCreated) justCreated = false; |
| + else if (!this[DRECEV1]) { |
| + this[DRECEV1] = true; |
| + new Class(this); |
| + if (CProto[CREATED_CALLBACK]) |
| + CProto[CREATED_CALLBACK].call(this); |
| + var info = constructors[nodeNames.get(Class)]; |
| + if (!usableCustomElements || info.create.length > 1) { |
| + notifyAttributes(this); |
| + } |
| + } |
| + } |
| + }); |
| + safeProperty(proto, ATTRIBUTE_CHANGED_CALLBACK, { |
| + value: function (name) { |
| + if (-1 < indexOf.call(attributes, name)) |
| + CProto[ATTRIBUTE_CHANGED_CALLBACK].apply(this, arguments); |
| + } |
| + }); |
| + if (CProto[CONNECTED_CALLBACK]) { |
| + safeProperty(proto, ATTACHED_CALLBACK, { |
| + value: CProto[CONNECTED_CALLBACK] |
| + }); |
| + } |
| + if (CProto[DISCONNECTED_CALLBACK]) { |
| + safeProperty(proto, DETACHED_CALLBACK, { |
| + value: CProto[DISCONNECTED_CALLBACK] |
| + }); |
| + } |
| + if (is) definition[EXTENDS] = is; |
| + name = name.toUpperCase(); |
| + constructors[name] = { |
| + constructor: Class, |
| + create: is ? [is, secondArgument(name)] : [name] |
| + }; |
| + nodeNames.set(Class, name); |
| + document[REGISTER_ELEMENT](name.toLowerCase(), definition); |
| + whenDefined(name); |
| + waitingList[name].r(); |
| + } |
| + |
| + function get(name) { |
| + var info = constructors[name.toUpperCase()]; |
| + return info && info.constructor; |
| + } |
| + |
| + function getIs(options) { |
| + return typeof options === 'string' ? |
| + options : (options && options.is || ''); |
| + } |
| + |
| + function notifyAttributes(self) { |
| + var |
| + callback = self[ATTRIBUTE_CHANGED_CALLBACK], |
| + attributes = callback ? self.attributes : empty, |
| + i = attributes.length, |
| + attribute |
| + ; |
| + while (i--) { |
| + attribute = attributes[i]; // || attributes.item(i); |
| + callback.call( |
| + self, |
| + attribute.name || attribute.nodeName, |
| + null, |
| + attribute.value || attribute.nodeValue |
| + ); |
| + } |
| + } |
| + |
| + function whenDefined(name) { |
| + name = name.toUpperCase(); |
| + if (!(name in waitingList)) { |
| + waitingList[name] = {}; |
| + waitingList[name].p = new Promise(function (resolve) { |
| + waitingList[name].r = resolve; |
| + }); |
| + } |
| + return waitingList[name].p; |
| + } |
| + |
| + function polyfillV1() { |
| + if (customElements) delete window.customElements; |
| + defineProperty(window, 'customElements', { |
| + configurable: true, |
| + value: new CustomElementRegistry() |
| + }); |
| + defineProperty(window, 'CustomElementRegistry', { |
| + configurable: true, |
| + value: CustomElementRegistry |
| + }); |
| + for (var |
| + patchClass = function (name) { |
| + var Class = window[name]; |
| + if (Class) { |
| + window[name] = function CustomElementsV1(self) { |
| + var info, isNative; |
| + if (!self) self = this; |
| + if (!self[DRECEV1]) { |
| + justCreated = true; |
| + info = constructors[nodeNames.get(self.constructor)]; |
| + isNative = usableCustomElements && info.create.length === 1; |
| + self = isNative ? |
| + Reflect.construct(Class, empty, info.constructor) : |
| + document.createElement.apply(document, info.create); |
| + self[DRECEV1] = true; |
| + justCreated = false; |
| + if (!isNative) notifyAttributes(self); |
| + } |
| + return self; |
| + }; |
| + window[name].prototype = Class.prototype; |
| + try { |
| + Class.prototype.constructor = window[name]; |
| + } catch(WebKit) { |
| + fixGetClass = true; |
| + defineProperty(Class, DRECEV1, {value: window[name]}); |
| + } |
| + } |
| + }, |
| + Classes = htmlClass.get(/^HTML[A-Z]*[a-z]/), |
| + i = Classes.length; |
| + i--; |
| + patchClass(Classes[i]) |
| + ) {} |
| + (document.createElement = function (name, options) { |
| + var is = getIs(options); |
| + return is ? |
| + patchedCreateElement.call(this, name, secondArgument(is)) : |
| + patchedCreateElement.call(this, name); |
| + }); |
| + if (!V0) { |
| + justSetup = true; |
| + document[REGISTER_ELEMENT](''); |
| + } |
| + } |
| + |
| + // if customElements is not there at all |
| + if (!customElements || /^force/.test(polyfill.type)) polyfillV1(); |
| + else if(!polyfill.noBuiltIn) { |
| + // if available test extends work as expected |
| + try { |
| + (function (DRE, options, name) { |
| + options[EXTENDS] = 'a'; |
| + DRE.prototype = create(HTMLAnchorElement.prototype); |
| + DRE.prototype.constructor = DRE; |
| + window.customElements.define(name, DRE, options); |
| + if ( |
| + getAttribute.call(document.createElement('a', {is: name}), 'is') !== name || |
| + (usableCustomElements && getAttribute.call(new DRE(), 'is') !== name) |
| + ) { |
| + throw options; |
| + } |
| + }( |
| + function DRE() { |
| + return Reflect.construct(HTMLAnchorElement, [], DRE); |
| + }, |
| + {}, |
| + 'document-register-element-a' |
| + )); |
| + } catch(o_O) { |
| + // or force the polyfill if not |
| + // and keep internal original reference |
| + polyfillV1(); |
| + } |
| + } |
| + |
| + // FireFox only issue |
| + if(!polyfill.noBuiltIn) { |
| + try { |
| + createElement.call(document, 'a', 'a'); |
| + } catch(FireFox) { |
| + secondArgument = function (is) { |
| + return {is: is.toLowerCase()}; |
| + }; |
| + } |
| + } |
| + |
| +} |
| + |
| +module.exports = installCustomElements; |
| + |
| +},{}],3:[function(require,module,exports){ |
| +'use strict'; |
| +/*! (C) 2017 Andrea Giammarchi - ISC Style License */ |
| + |
| +const {Component, bind, define, hyper, wire} = require('hyperhtml/cjs'); |
| + |
| +const _init$ = {value: false}; |
| + |
| +const defineProperty = Object.defineProperty; |
| + |
| +const extend = (target, source) => { |
| + for (const key in source) target[key] = source[key]; |
| +}; |
| + |
| +class HyperHTMLElement extends HTMLElement { |
| + |
| + // define a custom-element in the CustomElementsRegistry |
| + // class MyEl extends HyperHTMLElement {} |
| + // MyEl.define('my-el'); |
| + static define(name) { |
| + const Class = this; |
| + const proto = Class.prototype; |
| + |
| + // if observedAttributes contains attributes to observe |
| + // HyperHTMLElement will directly reflect get/setAttribute |
| + // operation once these attributes are used, example: |
| + // el.observed = 123; |
| + // will automatically do |
| + // el.setAttribute('observed', 123); |
| + // triggering also the attributeChangedCallback |
| + (Class.observedAttributes || []).forEach(name => { |
| + if (!(name in proto)) defineProperty( |
| + proto, |
| + name.replace(/-([a-z])/g, ($0, $1) => $1.toUpperCase()), |
| + { |
| + configurable: true, |
| + get() { return this.getAttribute(name); }, |
| + set(value) { this.setAttribute(name, value); } |
| + } |
| + ); |
| + }); |
| + |
| + const onChanged = proto.attributeChangedCallback; |
| + const hasChange = !!onChanged; |
| + |
| + // created() {} is the entry point to do whatever you want. |
| + // Once the node is live and upgraded as Custom Element. |
| + // This method grants to be triggered at the right time, |
| + // which is always once, and right before either |
| + // attributeChangedCallback or connectedCallback |
| + const created = proto.created; |
| + if (created) { |
| + // used to ensure create() is called once and once only |
| + defineProperty( |
| + proto, |
| + '_init$', |
| + { |
| + configurable: true, |
| + writable: true, |
| + value: true |
| + } |
| + ); |
| + |
| + // ⚠️ if you need to overwrite/change attributeChangedCallback method |
| + // at runtime after class definition, be sure you do so |
| + // via Object.defineProperty to preserve its non-enumerable nature. |
| + defineProperty( |
| + proto, |
| + 'attributeChangedCallback', |
| + { |
| + configurable: true, |
| + value(name, prev, curr) { |
| + if (this._init$) { |
| + created.call(defineProperty(this, '_init$', _init$)); |
| + } |
| + // ensure setting same value twice |
| + // won't trigger twice attributeChangedCallback |
| + if (hasChange && prev !== curr) { |
| + onChanged.apply(this, arguments); |
| + } |
| + } |
| + } |
| + ); |
| + |
| + // ⚠️ if you need to overwrite/change connectedCallback method |
| + // at runtime after class definition, be sure you do so |
| + // via Object.defineProperty to preserve its non-enumerable nature. |
| + const onConnected = proto.connectedCallback; |
| + const hasConnect = !!onConnected; |
| + defineProperty( |
| + proto, |
| + 'connectedCallback', |
| + { |
| + configurable: true, |
| + value() { |
| + if (this._init$) { |
| + created.call(defineProperty(this, '_init$', _init$)); |
| + } |
| + if (hasConnect) { |
| + onConnected.apply(this, arguments); |
| + } |
| + } |
| + } |
| + ); |
| + } else if (hasChange) { |
| + // ⚠️ if you need to overwrite/change attributeChangedCallback method |
| + // at runtime after class definition, be sure you do so |
| + // via Object.defineProperty to preserve its non-enumerable nature. |
| + defineProperty( |
| + proto, |
| + 'attributeChangedCallback', |
| + { |
| + configurable: true, |
| + value(name, prev, curr) { |
| + // ensure setting same value twice |
| + // won't trigger twice attributeChangedCallback |
| + if (prev !== curr) { |
| + onChanged.apply(this, arguments); |
| + } |
| + } |
| + } |
| + ); |
| + } |
| + |
| + // define lazily all handlers |
| + // class { handleClick() { ... } |
| + // render() { `<a onclick=${this.handleClick}>` } } |
| + Object.getOwnPropertyNames(proto).forEach(key => { |
| + if (/^handle[A-Z]/.test(key)) { |
| + const _key$ = '_' + key + '$'; |
| + const method = proto[key]; |
| + defineProperty(proto, key, { |
| + configurable: true, |
| + get() { |
| + return this[_key$] || |
| + (this[_key$] = method.bind(this)); |
| + } |
| + }); |
| + } |
| + }); |
| + |
| + // whenever you want to directly use the component itself |
| + // as EventListener, you can pass it directly. |
| + // https://medium.com/@WebReflection/dom-handleevent-a-cross-platform-standard-since-year-2000-5bf17287fd38 |
| + // class Reactive extends HyperHTMLElement { |
| + // oninput(e) { console.log(this, 'changed', e.target.value); } |
| + // render() { this.html`<input oninput="${this}">`; } |
| + // } |
| + if (!('handleEvent' in proto)) { |
| + // ⚠️ if you need to overwrite/change handleEvent method |
| + // at runtime after class definition, be sure you do so |
| + // via Object.defineProperty to preserve its non-enumerable nature. |
| + defineProperty( |
| + proto, |
| + 'handleEvent', |
| + { |
| + configurable: true, |
| + value(event) { |
| + this[ |
| + (event.currentTarget.dataset || {}).call || |
| + ('on' + event.type) |
| + ](event); |
| + } |
| + } |
| + ); |
| + } |
| + |
| + customElements.define(name, Class); |
| + return Class; |
| + } |
| + |
| + // lazily bind once hyperHTML logic |
| + // to either the shadowRoot, if present and open, |
| + // the _shadowRoot property, if set due closed shadow root, |
| + // or the custom-element itself if no Shadow DOM is used. |
| + get html() { |
| + return this._html$ || (this.html = bind( |
| + // in case of Shadow DOM {mode: "open"}, use it |
| + this.shadowRoot || |
| + // in case of Shadow DOM {mode: "close"}, use it |
| + // this needs the following reference created upfront |
| + // this._shadowRoot = this.attachShadow({mode: "close"}); |
| + this._shadowRoot || |
| + // if no Shadow DOM is used, simply use the component |
| + // as container for its own content (it just works too) |
| + this |
| + )); |
| + } |
| + |
| + // it can be set too if necessary, it won't invoke render() |
| + set html(value) { |
| + defineProperty(this, '_html$', {configurable: true, value: value}); |
| + } |
| + |
| + // ---------------------// |
| + // Basic State Handling // |
| + // ---------------------// |
| + |
| + // overwrite this method with your own render |
| + render() {} |
| + |
| + // define the default state object |
| + // you could use observed properties too |
| + get defaultState() { return {}; } |
| + |
| + // the state with a default |
| + get state() { |
| + return this._state$ || (this.state = this.defaultState); |
| + } |
| + |
| + // it can be set too if necessary, it won't invoke render() |
| + set state(value) { |
| + defineProperty(this, '_state$', {configurable: true, value: value}); |
| + } |
| + |
| + // currently a state is a shallow copy, like in Preact or other libraries. |
| + // after the state is updated, the render() method will be invoked. |
| + // ⚠️ do not ever call this.setState() inside this.render() |
| + setState(state) { |
| + extend( |
| + this.state, |
| + typeof state === 'function' ? |
| + state.call(this, this.state) : state |
| + ); |
| + this.render(); |
| + } |
| + |
| +}; |
| + |
| +// exposing hyperHTML utilities |
| +HyperHTMLElement.Component = Component; |
| +HyperHTMLElement.bind = bind; |
| +HyperHTMLElement.intent = define; |
| +HyperHTMLElement.wire = wire; |
| +HyperHTMLElement.hyper = hyper; |
| + |
| +Object.defineProperty(exports, '__esModule', {value: true}).default = HyperHTMLElement; |
| + |
| +},{"hyperhtml/cjs":8}],4:[function(require,module,exports){ |
| +'use strict'; |
| +const { UID } = require('../shared/constants.js'); |
| +const { WeakMap } = require('../shared/poorlyfills.js'); |
| + |
| +// hyperHTML.Component is a very basic class |
| +// able to create Custom Elements like components |
| +// including the ability to listen to connect/disconnect |
| +// events via onconnect/ondisconnect attributes |
| +// Components can be created imperatively or declaratively. |
| +// The main difference is that declared components |
| +// will not automatically render on setState(...) |
| +// to simplify state handling on render. |
| +function Component() {} |
| +Object.defineProperty(exports, '__esModule', {value: true}).default = Component |
| + |
| +// components will lazily define html or svg properties |
| +// as soon as these are invoked within the .render() method |
| +// Such render() method is not provided by the base class |
| +// but it must be available through the Component extend. |
| +// Declared components could implement a |
| +// render(props) method too and use props as needed. |
| +function setup(content) { |
| + const children = new WeakMap; |
| + const create = Object.create; |
| + const createEntry = (wm, id, component) => { |
| + wm.set(id, component); |
| + return component; |
| + }; |
| + const get = (Class, info, id) => { |
| + switch (typeof id) { |
| + case 'object': |
| + case 'function': |
| + const wm = info.w || (info.w = new WeakMap); |
| + return wm.get(id) || createEntry(wm, id, new Class); |
| + default: |
| + const sm = info.p || (info.p = create(null)); |
| + return sm[id] || (sm[id] = new Class); |
| + } |
| + }; |
| + const set = context => { |
| + const info = {w: null, p: null}; |
| + children.set(context, info); |
| + return info; |
| + }; |
| + Object.defineProperties( |
| + Component, |
| + { |
| + for: { |
| + configurable: true, |
| + value(context, id) { |
| + const info = children.get(context) || set(context); |
| + return get(this, info, id == null ? 'default' : id); |
| + } |
| + } |
| + } |
| + ); |
| + Object.defineProperties( |
| + Component.prototype, |
| + { |
| + handleEvent: {value(e) { |
| + const ct = e.currentTarget; |
| + this[ |
| + ('getAttribute' in ct && ct.getAttribute('data-call')) || |
| + ('on' + e.type) |
| + ](e); |
| + }}, |
| + html: lazyGetter('html', content), |
| + svg: lazyGetter('svg', content), |
| + state: lazyGetter('state', function () { return this.defaultState; }), |
| + defaultState: {get() { return {}; }}, |
| + setState: {value(state, render) { |
| + const target = this.state; |
| + const source = typeof state === 'function' ? state.call(this, target) : state; |
| + for (const key in source) target[key] = source[key]; |
| + if (render !== false) this.render(); |
| + return this; |
| + }} |
| + } |
| + ); |
| +} |
| +exports.setup = setup |
| + |
| +// instead of a secret key I could've used a WeakMap |
| +// However, attaching a property directly will result |
| +// into better performance with thousands of components |
| +// hanging around, and less memory pressure caused by the WeakMap |
| +const lazyGetter = (type, fn) => { |
| + const secret = '_' + type + '$'; |
| + return { |
| + get() { |
| + return this[secret] || (this[type] = fn.call(this, type)); |
| + }, |
| + set(value) { |
| + Object.defineProperty(this, secret, {configurable: true, value}); |
| + } |
| + }; |
| +}; |
| + |
| +},{"../shared/constants.js":13,"../shared/poorlyfills.js":17}],5:[function(require,module,exports){ |
| +'use strict'; |
| +const { append } = require('../shared/utils.js'); |
| +const { doc, fragment } = require('../shared/easy-dom.js'); |
| + |
| +function Wire(childNodes) { |
| + this.childNodes = childNodes; |
| + this.length = childNodes.length; |
| + this.first = childNodes[0]; |
| + this.last = childNodes[this.length - 1]; |
| +} |
| +Object.defineProperty(exports, '__esModule', {value: true}).default = Wire |
| + |
| +// when a wire is inserted, all its nodes will follow |
| +Wire.prototype.insert = function insert() { |
| + const df = fragment(this.first); |
| + append(df, this.childNodes); |
| + return df; |
| +}; |
| + |
| +// when a wire is removed, all its nodes must be removed as well |
| +Wire.prototype.remove = function remove() { |
| + const first = this.first; |
| + const last = this.last; |
| + if (this.length === 2) { |
| + last.parentNode.removeChild(last); |
| + } else { |
| + const range = doc(first).createRange(); |
| + range.setStartBefore(this.childNodes[1]); |
| + range.setEndAfter(last); |
| + range.deleteContents(); |
| + } |
| + return first; |
| +}; |
| + |
| +},{"../shared/easy-dom.js":15,"../shared/utils.js":19}],6:[function(require,module,exports){ |
| +'use strict'; |
| +const {Map, WeakMap} = require('../shared/poorlyfills.js'); |
| +const {UIDC, VOID_ELEMENTS} = require('../shared/constants.js'); |
| +const Updates = (m => m.__esModule ? m.default : m)(require('../objects/Updates.js')); |
| +const { |
| + createFragment, |
| + importNode, |
| + unique |
| +} = require('../shared/utils.js'); |
| + |
| +const {selfClosing} = require('../shared/re.js'); |
| + |
| +// a weak collection of contexts that |
| +// are already known to hyperHTML |
| +const bewitched = new WeakMap; |
| + |
| +// the collection of all template literals |
| +// since these are unique and immutable |
| +// for the whole application life-cycle |
| +const templates = new Map; |
| + |
| +// better known as hyper.bind(node), the render is |
| +// the main tag function in charge of fully upgrading |
| +// or simply updating, contexts used as hyperHTML targets. |
| +// The `this` context is either a regular DOM node or a fragment. |
| +function render(template) { |
| + const wicked = bewitched.get(this); |
| + if (wicked && wicked.template === unique(template)) { |
| + update.apply(wicked.updates, arguments); |
| + } else { |
| + upgrade.apply(this, arguments); |
| + } |
| + return this; |
| +} |
| + |
| +// an upgrade is in charge of collecting template info, |
| +// parse it once, if unknown, to map all interpolations |
| +// as single DOM callbacks, relate such template |
| +// to the current context, and render it after cleaning the context up |
| +function upgrade(template) { |
| + template = unique(template); |
| + const info = templates.get(template) || |
| + createTemplate.call(this, template); |
| + const fragment = importNode(this.ownerDocument, info.fragment); |
| + const updates = Updates.create(fragment, info.paths); |
| + bewitched.set(this, {template, updates}); |
| + update.apply(updates, arguments); |
| + this.textContent = ''; |
| + this.appendChild(fragment); |
| +} |
| + |
| +// an update simply loops over all mapped DOM operations |
| +function update() { |
| + const length = arguments.length; |
| + for (let i = 1; i < length; i++) { |
| + this[i - 1](arguments[i]); |
| + } |
| +} |
| + |
| +// a template can be used to create a document fragment |
| +// aware of all interpolations and with a list |
| +// of paths used to find once those nodes that need updates, |
| +// no matter if these are attributes, text nodes, or regular one |
| +function createTemplate(template) { |
| + const paths = []; |
| + const html = template.join(UIDC).replace(SC_RE, SC_PLACE); |
| + const fragment = createFragment(this, html); |
| + Updates.find(fragment, paths, template.slice()); |
| + const info = {fragment, paths}; |
| + templates.set(template, info); |
| + return info; |
| +} |
| + |
| +// some node could be special though, like a custom element |
| +// with a self closing tag, which should work through these changes. |
| +const SC_RE = selfClosing; |
| +const SC_PLACE = ($0, $1, $2) => { |
| + return VOID_ELEMENTS.test($1) ? $0 : ('<' + $1 + $2 + '></' + $1 + '>'); |
| +}; |
| + |
| +Object.defineProperty(exports, '__esModule', {value: true}).default = render; |
| + |
| +},{"../objects/Updates.js":12,"../shared/constants.js":13,"../shared/poorlyfills.js":17,"../shared/re.js":18,"../shared/utils.js":19}],7:[function(require,module,exports){ |
| +'use strict'; |
| +const {ELEMENT_NODE, SVG_NAMESPACE} = require('../shared/constants.js'); |
| +const {WeakMap, trim} = require('../shared/poorlyfills.js'); |
| +const {fragment} = require('../shared/easy-dom.js'); |
| +const {append, slice, unique} = require('../shared/utils.js'); |
| +const Wire = (m => m.__esModule ? m.default : m)(require('../classes/Wire.js')); |
| +const render = (m => m.__esModule ? m.default : m)(require('./render.js')); |
| + |
| +// all wires used per each context |
| +const wires = new WeakMap; |
| + |
| +// A wire is a callback used as tag function |
| +// to lazily relate a generic object to a template literal. |
| +// hyper.wire(user)`<div id=user>${user.name}</div>`; => the div#user |
| +// This provides the ability to have a unique DOM structure |
| +// related to a unique JS object through a reusable template literal. |
| +// A wire can specify a type, as svg or html, and also an id |
| +// via html:id or :id convention. Such :id allows same JS objects |
| +// to be associated to different DOM structures accordingly with |
| +// the used template literal without losing previously rendered parts. |
| +const wire = (obj, type) => obj == null ? |
| + content(type || 'html') : |
| + weakly(obj, type || 'html'); |
| + |
| +// A wire content is a virtual reference to one or more nodes. |
| +// It's represented by either a DOM node, or an Array. |
| +// In both cases, the wire content role is to simply update |
| +// all nodes through the list of related callbacks. |
| +// In few words, a wire content is like an invisible parent node |
| +// in charge of updating its content like a bound element would do. |
| +const content = type => { |
| + let wire, container, content, template, updates; |
| + return function (statics) { |
| + statics = unique(statics); |
| + let setup = template !== statics; |
| + if (setup) { |
| + template = statics; |
| + content = fragment(document); |
| + container = type === 'svg' ? |
| + document.createElementNS(SVG_NAMESPACE, 'svg') : |
| + content; |
| + updates = render.bind(container); |
| + } |
| + updates.apply(null, arguments); |
| + if (setup) { |
| + if (type === 'svg') { |
| + append(content, slice.call(container.childNodes)); |
| + } |
| + wire = wireContent(content); |
| + } |
| + return wire; |
| + }; |
| +}; |
| + |
| +// wires are weakly created through objects. |
| +// Each object can have multiple wires associated |
| +// and this is thanks to the type + :id feature. |
| +const weakly = (obj, type) => { |
| + const i = type.indexOf(':'); |
| + let wire = wires.get(obj); |
| + let id = type; |
| + if (-1 < i) { |
| + id = type.slice(i + 1); |
| + type = type.slice(0, i) || 'html'; |
| + } |
| + if (!wire) wires.set(obj, wire = {}); |
| + return wire[id] || (wire[id] = content(type)); |
| +}; |
| + |
| +// a document fragment loses its nodes as soon |
| +// as it's appended into another node. |
| +// This would easily lose wired content |
| +// so that on a second render call, the parent |
| +// node wouldn't know which node was there |
| +// associated to the interpolation. |
| +// To prevent hyperHTML to forget about wired nodes, |
| +// these are either returned as Array or, if there's ony one entry, |
| +// as single referenced node that won't disappear from the fragment. |
| +// The initial fragment, at this point, would be used as unique reference. |
| +const wireContent = node => { |
| + const childNodes = node.childNodes; |
| + const length = childNodes.length; |
| + const wireNodes = []; |
| + for (let i = 0; i < length; i++) { |
| + let child = childNodes[i]; |
| + if ( |
| + child.nodeType === ELEMENT_NODE || |
| + trim.call(child.textContent).length !== 0 |
| + ) { |
| + wireNodes.push(child); |
| + } |
| + } |
| + return wireNodes.length === 1 ? wireNodes[0] : new Wire(wireNodes); |
| +}; |
| + |
| +exports.content = content; |
| +exports.weakly = weakly; |
| +Object.defineProperty(exports, '__esModule', {value: true}).default = wire; |
| + |
| +},{"../classes/Wire.js":5,"../shared/constants.js":13,"../shared/easy-dom.js":15,"../shared/poorlyfills.js":17,"../shared/utils.js":19,"./render.js":6}],8:[function(require,module,exports){ |
| +'use strict'; |
| +/*! (c) Andrea Giammarchi (ISC) */ |
| + |
| +const Component = (m => m.__esModule ? m.default : m)(require('./classes/Component.js')); |
| +const {setup} = require('./classes/Component.js'); |
| +const Intent = (m => m.__esModule ? m.default : m)(require('./objects/Intent.js')); |
| +const wire = (m => m.__esModule ? m.default : m)(require('./hyper/wire.js')); |
| +const {content, weakly} = require('./hyper/wire.js'); |
| +const render = (m => m.__esModule ? m.default : m)(require('./hyper/render.js')); |
| +const diff = (m => m.__esModule ? m.default : m)(require('./shared/domdiff.js')); |
| + |
| +// all functions are self bound to the right context |
| +// you can do the following |
| +// const {bind, wire} = hyperHTML; |
| +// and use them right away: bind(node)`hello!`; |
| +const bind = context => render.bind(context); |
| +const define = Intent.define; |
| + |
| +hyper.Component = Component; |
| +hyper.bind = bind; |
| +hyper.define = define; |
| +hyper.diff = diff; |
| +hyper.hyper = hyper; |
| +hyper.wire = wire; |
| + |
| +// the wire content is the lazy defined |
| +// html or svg property of each hyper.Component |
| +setup(content); |
| + |
| +// everything is exported directly or through the |
| +// hyperHTML callback, when used as top level script |
| +exports.Component = Component; |
| +exports.bind = bind; |
| +exports.define = define; |
| +exports.diff = diff; |
| +exports.hyper = hyper; |
| +exports.wire = wire; |
| + |
| +// by default, hyperHTML is a smart function |
| +// that "magically" understands what's the best |
| +// thing to do with passed arguments |
| +function hyper(HTML) { |
| + return arguments.length < 2 ? |
| + (HTML == null ? |
| + content('html') : |
| + (typeof HTML === 'string' ? |
| + hyper.wire(null, HTML) : |
| + ('raw' in HTML ? |
| + content('html')(HTML) : |
| + ('nodeType' in HTML ? |
| + hyper.bind(HTML) : |
| + weakly(HTML, 'html') |
| + ) |
| + ) |
| + )) : |
| + ('raw' in HTML ? |
| + content('html') : hyper.wire |
| + ).apply(null, arguments); |
| +} |
| +Object.defineProperty(exports, '__esModule', {value: true}).default = hyper |
| + |
| +},{"./classes/Component.js":4,"./hyper/render.js":6,"./hyper/wire.js":7,"./objects/Intent.js":9,"./shared/domdiff.js":14}],9:[function(require,module,exports){ |
| +'use strict'; |
| +const intents = {}; |
| +const keys = []; |
| +const hasOwnProperty = intents.hasOwnProperty; |
| + |
| +let length = 0; |
| + |
| +Object.defineProperty(exports, '__esModule', {value: true}).default = { |
| + |
| + // hyperHTML.define('intent', (object, update) => {...}) |
| + // can be used to define a third parts update mechanism |
| + // when every other known mechanism failed. |
| + // hyper.define('user', info => info.name); |
| + // hyper(node)`<p>${{user}}</p>`; |
| + define: (intent, callback) => { |
| + if (!(intent in intents)) { |
| + length = keys.push(intent); |
| + } |
| + intents[intent] = callback; |
| + }, |
| + |
| + // this method is used internally as last resort |
| + // to retrieve a value out of an object |
| + invoke: (object, callback) => { |
| + for (let i = 0; i < length; i++) { |
| + let key = keys[i]; |
| + if (hasOwnProperty.call(object, key)) { |
| + return intents[key](object[key], callback); |
| + } |
| + } |
| + } |
| +}; |
| + |
| +},{}],10:[function(require,module,exports){ |
| +'use strict'; |
| +const { |
| + COMMENT_NODE, |
| + DOCUMENT_FRAGMENT_NODE, |
| + ELEMENT_NODE |
| +} = require('../shared/constants.js'); |
| + |
| +// every template literal interpolation indicates |
| +// a precise target in the DOM the template is representing. |
| +// `<p id=${'attribute'}>some ${'content'}</p>` |
| +// hyperHTML finds only once per template literal, |
| +// hence once per entire application life-cycle, |
| +// all nodes that are related to interpolations. |
| +// These nodes are stored as indexes used to retrieve, |
| +// once per upgrade, nodes that will change on each future update. |
| +// A path example is [2, 0, 1] representing the operation: |
| +// node.childNodes[2].childNodes[0].childNodes[1] |
| +// Attributes are addressed via their owner node and their name. |
| +const createPath = node => { |
| + const path = []; |
| + let parentNode; |
| + switch (node.nodeType) { |
| + case ELEMENT_NODE: |
| + case DOCUMENT_FRAGMENT_NODE: |
| + parentNode = node; |
| + break; |
| + case COMMENT_NODE: |
| + parentNode = node.parentNode; |
| + prepend(path, parentNode, node); |
| + break; |
| + default: |
| + parentNode = node.ownerElement; |
| + break; |
| + } |
| + for ( |
| + node = parentNode; |
| + (parentNode = parentNode.parentNode); |
| + node = parentNode |
| + ) { |
| + prepend(path, parentNode, node); |
| + } |
| + return path; |
| +}; |
| + |
| +const prepend = (path, parent, node) => { |
| + path.unshift(path.indexOf.call(parent.childNodes, node)); |
| +}; |
| + |
| +Object.defineProperty(exports, '__esModule', {value: true}).default = { |
| + create: (type, node, name) => ({type, name, node, path: createPath(node)}), |
| + find: (node, path) => { |
| + const length = path.length; |
| + for (let i = 0; i < length; i++) { |
| + node = node.childNodes[path[i]]; |
| + } |
| + return node; |
| + } |
| +} |
| + |
| +},{"../shared/constants.js":13}],11:[function(require,module,exports){ |
| +'use strict'; |
| +// from https://github.com/developit/preact/blob/33fc697ac11762a1cb6e71e9847670d047af7ce5/src/constants.js |
| +const IS_NON_DIMENSIONAL = /acit|ex(?:s|g|n|p|$)|rph|ows|mnc|ntw|ine[ch]|zoo|^ord/i; |
| + |
| +// style is handled as both string and object |
| +// even if the target is an SVG element (consistency) |
| +Object.defineProperty(exports, '__esModule', {value: true}).default = (node, original, isSVG) => { |
| + if (isSVG) { |
| + const style = original.cloneNode(true); |
| + style.value = ''; |
| + node.setAttributeNode(style); |
| + return update(style, isSVG); |
| + } |
| + return update(node.style, isSVG); |
| +}; |
| + |
| +// the update takes care or changing/replacing |
| +// only properties that are different or |
| +// in case of string, the whole node |
| +const update = (style, isSVG) => { |
| + let oldType, oldValue; |
| + return newValue => { |
| + switch (typeof newValue) { |
| + case 'object': |
| + if (newValue) { |
| + if (oldType === 'object') { |
| + if (!isSVG) { |
| + if (oldValue !== newValue) { |
| + for (const key in oldValue) { |
| + if (!(key in newValue)) { |
| + style[key] = ''; |
| + } |
| + } |
| + } |
| + } |
| + } else { |
| + if (isSVG) style.value = ''; |
| + else style.cssText = ''; |
| + } |
| + const info = isSVG ? {} : style; |
| + for (const key in newValue) { |
| + const value = newValue[key]; |
| + info[key] = typeof value === 'number' && |
| + !IS_NON_DIMENSIONAL.test(key) ? |
| + (value + 'px') : value; |
| + } |
| + oldType = 'object'; |
| + if (isSVG) style.value = toStyle((oldValue = info)); |
| + else oldValue = newValue; |
| + break; |
| + } |
| + default: |
| + if (oldValue != newValue) { |
| + oldType = 'string'; |
| + oldValue = newValue; |
| + if (isSVG) style.value = newValue || ''; |
| + else style.cssText = newValue || ''; |
| + } |
| + break; |
| + } |
| + }; |
| +}; |
| + |
| +const hyphen = /([^A-Z])([A-Z]+)/g; |
| +const ized = ($0, $1, $2) => $1 + '-' + $2.toLowerCase(); |
| +const toStyle = object => { |
| + const css = []; |
| + for (const key in object) { |
| + css.push(key.replace(hyphen, ized), ':', object[key], ';'); |
| + } |
| + return css.join(''); |
| +}; |
| +},{}],12:[function(require,module,exports){ |
| +'use strict'; |
| +const { |
| + CONNECTED, DISCONNECTED, COMMENT_NODE, DOCUMENT_FRAGMENT_NODE, ELEMENT_NODE, TEXT_NODE, OWNER_SVG_ELEMENT, SHOULD_USE_TEXT_CONTENT, UID, UIDC |
| +} = require('../shared/constants.js'); |
| + |
| +const Component = (m => m.__esModule ? m.default : m)(require('../classes/Component.js')); |
| +const Wire = (m => m.__esModule ? m.default : m)(require('../classes/Wire.js')); |
| +const Path = (m => m.__esModule ? m.default : m)(require('./Path.js')); |
| +const Style = (m => m.__esModule ? m.default : m)(require('./Style.js')); |
| +const Intent = (m => m.__esModule ? m.default : m)(require('./Intent.js')); |
| +const domdiff = (m => m.__esModule ? m.default : m)(require('../shared/domdiff.js')); |
| +const { create: createElement, text } = require('../shared/easy-dom.js'); |
| +const { Event, WeakSet, isArray, trim } = require('../shared/poorlyfills.js'); |
| +const { createFragment, slice } = require('../shared/utils.js'); |
| + |
| +// hyper.Component have a connected/disconnected |
| +// mechanism provided by MutationObserver |
| +// This weak set is used to recognize components |
| +// as DOM node that needs to trigger connected/disconnected events |
| +const components = new WeakSet; |
| + |
| +// a basic dictionary used to filter already cached attributes |
| +// while looking for special hyperHTML values. |
| +function Cache() {} |
| +Cache.prototype = Object.create(null); |
| + |
| +// returns an intent to explicitly inject content as html |
| +const asHTML = html => ({html}); |
| + |
| +// returns nodes from wires and components |
| +const asNode = (item, i) => { |
| + return 'ELEMENT_NODE' in item ? |
| + item : |
| + (item.constructor === Wire ? |
| + // in the Wire case, the content can be |
| + // removed, post-pended, inserted, or pre-pended and |
| + // all these cases are handled by domdiff already |
| + /* istanbul ignore next */ |
| + ((1 / i) < 0 ? |
| + (i ? item.remove() : item.last) : |
| + (i ? item.insert() : item.first)) : |
| + asNode(item.render(), i)); |
| +} |
| + |
| +// returns true if domdiff can handle the value |
| +const canDiff = value => 'ELEMENT_NODE' in value || |
| +value instanceof Wire || |
| +value instanceof Component; |
| + |
| +// updates are created once per context upgrade |
| +// within the main render function (../hyper/render.js) |
| +// These are an Array of callbacks to invoke passing |
| +// each interpolation value. |
| +// Updates can be related to any kind of content, |
| +// attributes, or special text-only cases such <style> |
| +// elements or <textarea> |
| +const create = (root, paths) => { |
| + const updates = []; |
| + const length = paths.length; |
| + for (let i = 0; i < length; i++) { |
| + const info = paths[i]; |
| + const node = Path.find(root, info.path); |
| + switch (info.type) { |
| + case 'any': |
| + updates.push(setAnyContent(node, [])); |
| + break; |
| + case 'attr': |
| + updates.push(setAttribute(node, info.name, info.node)); |
| + break; |
| + case 'text': |
| + updates.push(setTextContent(node)); |
| + break; |
| + } |
| + } |
| + return updates; |
| +}; |
| + |
| +// finding all paths is a one-off operation performed |
| +// when a new template literal is used. |
| +// The goal is to map all target nodes that will be |
| +// used to update content/attributes every time |
| +// the same template literal is used to create content. |
| +// The result is a list of paths related to the template |
| +// with all the necessary info to create updates as |
| +// list of callbacks that target directly affected nodes. |
| +const find = (node, paths, parts) => { |
| + const childNodes = node.childNodes; |
| + const length = childNodes.length; |
| + for (let i = 0; i < length; i++) { |
| + let child = childNodes[i]; |
| + switch (child.nodeType) { |
| + case ELEMENT_NODE: |
| + findAttributes(child, paths, parts); |
| + find(child, paths, parts); |
| + break; |
| + case COMMENT_NODE: |
| + if (child.textContent === UID) { |
| + parts.shift(); |
| + paths.push( |
| + // basicHTML or other non standard engines |
| + // might end up having comments in nodes |
| + // where they shouldn't, hence this check. |
| + SHOULD_USE_TEXT_CONTENT.test(node.nodeName) ? |
| + Path.create('text', node) : |
| + Path.create('any', child) |
| + ); |
| + } |
| + break; |
| + case TEXT_NODE: |
| + // the following ignore is actually covered by browsers |
| + // only basicHTML ends up on previous COMMENT_NODE case |
| + // instead of TEXT_NODE because it knows nothing about |
| + // special style or textarea behavior |
| + /* istanbul ignore if */ |
| + if ( |
| + SHOULD_USE_TEXT_CONTENT.test(node.nodeName) && |
| + trim.call(child.textContent) === UIDC |
| + ) { |
| + parts.shift(); |
| + paths.push(Path.create('text', node)); |
| + } |
| + break; |
| + } |
| + } |
| +}; |
| + |
| +// attributes are searched via unique hyperHTML id value. |
| +// Despite HTML being case insensitive, hyperHTML is able |
| +// to recognize attributes by name in a caseSensitive way. |
| +// This plays well with Custom Elements definitions |
| +// and also with XML-like environments, without trusting |
| +// the resulting DOM but the template literal as the source of truth. |
| +// IE/Edge has a funny bug with attributes and these might be duplicated. |
| +// This is why there is a cache in charge of being sure no duplicated |
| +// attributes are ever considered in future updates. |
| +const findAttributes = (node, paths, parts) => { |
| + const cache = new Cache; |
| + const attributes = node.attributes; |
| + const array = slice.call(attributes); |
| + const remove = []; |
| + const length = array.length; |
| + for (let i = 0; i < length; i++) { |
| + const attribute = array[i]; |
| + if (attribute.value === UID) { |
| + const name = attribute.name; |
| + // the following ignore is covered by IE |
| + // and the IE9 double viewBox test |
| + /* istanbul ignore else */ |
| + if (!(name in cache)) { |
| + const realName = parts.shift().replace(/^(?:|[\S\s]*?\s)(\S+?)=['"]?$/, '$1'); |
| + cache[name] = attributes[realName] || |
| + // the following ignore is covered by browsers |
| + // while basicHTML is already case-sensitive |
| + /* istanbul ignore next */ |
| + attributes[realName.toLowerCase()]; |
| + paths.push(Path.create('attr', cache[name], realName)); |
| + } |
| + remove.push(attribute); |
| + } |
| + } |
| + const len = remove.length; |
| + for (let i = 0; i < len; i++) { |
| + node.removeAttributeNode(remove[i]); |
| + } |
| + |
| + // This is a very specific Firefox/Safari issue |
| + // but since it should be a not so common pattern, |
| + // it's probably worth patching regardless. |
| + // Basically, scripts created through strings are death. |
| + // You need to create fresh new scripts instead. |
| + // TODO: is there any other node that needs such nonsense ? |
| + const nodeName = node.nodeName; |
| + if (/^script$/i.test(nodeName)) { |
| + const script = createElement(node, nodeName); |
| + for (let i = 0; i < attributes.length; i++) { |
| + script.setAttributeNode(attributes[i].cloneNode(true)); |
| + } |
| + script.textContent = node.textContent; |
| + node.parentNode.replaceChild(script, node); |
| + } |
| +}; |
| + |
| +// when a Promise is used as interpolation value |
| +// its result must be parsed once resolved. |
| +// This callback is in charge of understanding what to do |
| +// with a returned value once the promise is resolved. |
| +const invokeAtDistance = (value, callback) => { |
| + callback(value.placeholder); |
| + if ('text' in value) { |
| + Promise.resolve(value.text).then(String).then(callback); |
| + } else if ('any' in value) { |
| + Promise.resolve(value.any).then(callback); |
| + } else if ('html' in value) { |
| + Promise.resolve(value.html).then(asHTML).then(callback); |
| + } else { |
| + Promise.resolve(Intent.invoke(value, callback)).then(callback); |
| + } |
| +}; |
| + |
| +// quick and dirty way to check for Promise/ish values |
| +const isPromise_ish = value => value != null && 'then' in value; |
| + |
| +// in a hyper(node)`<div>${content}</div>` case |
| +// everything could happen: |
| +// * it's a JS primitive, stored as text |
| +// * it's null or undefined, the node should be cleaned |
| +// * it's a component, update the content by rendering it |
| +// * it's a promise, update the content once resolved |
| +// * it's an explicit intent, perform the desired operation |
| +// * it's an Array, resolve all values if Promises and/or |
| +// update the node with the resulting list of content |
| +const setAnyContent = (node, childNodes) => { |
| + let fastPath = false; |
| + let oldValue; |
| + const anyContent = value => { |
| + switch (typeof value) { |
| + case 'string': |
| + case 'number': |
| + case 'boolean': |
| + if (fastPath) { |
| + if (oldValue !== value) { |
| + oldValue = value; |
| + childNodes[0].textContent = value; |
| + } |
| + } else { |
| + fastPath = true; |
| + oldValue = value; |
| + childNodes = domdiff( |
| + node.parentNode, |
| + childNodes, |
| + [text(node, value)], |
| + asNode, |
| + node |
| + ); |
| + } |
| + break; |
| + case 'object': |
| + case 'undefined': |
| + if (value == null) { |
| + fastPath = false; |
| + childNodes = domdiff( |
| + node.parentNode, |
| + childNodes, |
| + [], |
| + asNode, |
| + node |
| + ); |
| + break; |
| + } |
| + default: |
| + fastPath = false; |
| + oldValue = value; |
| + if (isArray(value)) { |
| + if (value.length === 0) { |
| + if (childNodes.length) { |
| + childNodes = domdiff( |
| + node.parentNode, |
| + childNodes, |
| + [], |
| + asNode, |
| + node |
| + ); |
| + } |
| + } else { |
| + switch (typeof value[0]) { |
| + case 'string': |
| + case 'number': |
| + case 'boolean': |
| + anyContent({html: value}); |
| + break; |
| + case 'object': |
| + if (isArray(value[0])) { |
| + value = value.concat.apply([], value); |
| + } |
| + if (isPromise_ish(value[0])) { |
| + Promise.all(value).then(anyContent); |
| + break; |
| + } |
| + default: |
| + childNodes = domdiff( |
| + node.parentNode, |
| + childNodes, |
| + value, |
| + asNode, |
| + node |
| + ); |
| + break; |
| + } |
| + } |
| + } else if (canDiff(value)) { |
| + childNodes = domdiff( |
| + node.parentNode, |
| + childNodes, |
| + value.nodeType === DOCUMENT_FRAGMENT_NODE ? |
| + slice.call(value.childNodes) : |
| + [value], |
| + asNode, |
| + node |
| + ); |
| + } else if (isPromise_ish(value)) { |
| + value.then(anyContent); |
| + } else if ('placeholder' in value) { |
| + invokeAtDistance(value, anyContent); |
| + } else if ('text' in value) { |
| + anyContent(String(value.text)); |
| + } else if ('any' in value) { |
| + anyContent(value.any); |
| + } else if ('html' in value) { |
| + childNodes = domdiff( |
| + node.parentNode, |
| + childNodes, |
| + slice.call( |
| + createFragment( |
| + node, |
| + [].concat(value.html).join('') |
| + ).childNodes |
| + ), |
| + asNode, |
| + node |
| + ); |
| + } else if ('length' in value) { |
| + anyContent(slice.call(value)); |
| + } else { |
| + anyContent(Intent.invoke(value, anyContent)); |
| + } |
| + break; |
| + } |
| + }; |
| + return anyContent; |
| +}; |
| + |
| +// there are four kind of attributes, and related behavior: |
| +// * events, with a name starting with `on`, to add/remove event listeners |
| +// * special, with a name present in their inherited prototype, accessed directly |
| +// * regular, accessed through get/setAttribute standard DOM methods |
| +// * style, the only regular attribute that also accepts an object as value |
| +// so that you can style=${{width: 120}}. In this case, the behavior has been |
| +// fully inspired by Preact library and its simplicity. |
| +const setAttribute = (node, name, original) => { |
| + const isSVG = OWNER_SVG_ELEMENT in node; |
| + let oldValue; |
| + // if the attribute is the style one |
| + // handle it differently from others |
| + if (name === 'style') { |
| + return Style(node, original, isSVG); |
| + } |
| + // the name is an event one, |
| + // add/remove event listeners accordingly |
| + else if (/^on/.test(name)) { |
| + let type = name.slice(2); |
| + if (type === CONNECTED || type === DISCONNECTED) { |
| + if (notObserving) { |
| + notObserving = false; |
| + observe(); |
| + } |
| + components.add(node); |
| + } |
| + else if (name.toLowerCase() in node) { |
| + type = type.toLowerCase(); |
| + } |
| + return newValue => { |
| + if (oldValue !== newValue) { |
| + if (oldValue) node.removeEventListener(type, oldValue, false); |
| + oldValue = newValue; |
| + if (newValue) node.addEventListener(type, newValue, false); |
| + } |
| + }; |
| + } |
| + // the attribute is special ('value' in input) |
| + // and it's not SVG *or* the name is exactly data, |
| + // in this case assign the value directly |
| + else if (name === 'data' || (!isSVG && name in node)) { |
| + return newValue => { |
| + if (oldValue !== newValue) { |
| + oldValue = newValue; |
| + if (node[name] !== newValue) { |
| + node[name] = newValue; |
| + if (newValue == null) { |
| + node.removeAttribute(name); |
| + } |
| + } |
| + } |
| + }; |
| + } |
| + // in every other case, use the attribute node as it is |
| + // update only the value, set it as node only when/if needed |
| + else { |
| + let owner = false; |
| + const attribute = original.cloneNode(true); |
| + return newValue => { |
| + if (oldValue !== newValue) { |
| + oldValue = newValue; |
| + if (attribute.value !== newValue) { |
| + if (newValue == null) { |
| + if (owner) { |
| + owner = false; |
| + node.removeAttributeNode(attribute); |
| + } |
| + attribute.value = newValue; |
| + } else { |
| + attribute.value = newValue; |
| + if (!owner) { |
| + owner = true; |
| + node.setAttributeNode(attribute); |
| + } |
| + } |
| + } |
| + } |
| + }; |
| + } |
| +}; |
| + |
| +// style or textareas don't accept HTML as content |
| +// it's pointless to transform or analyze anything |
| +// different from text there but it's worth checking |
| +// for possible defined intents. |
| +const setTextContent = node => { |
| + // avoid hyper comments inside textarea/style when value is undefined |
| + let oldValue = ''; |
| + const textContent = value => { |
| + if (oldValue !== value) { |
| + oldValue = value; |
| + if (typeof value === 'object' && value) { |
| + if (isPromise_ish(value)) { |
| + value.then(textContent); |
| + } else if ('placeholder' in value) { |
| + invokeAtDistance(value, textContent); |
| + } else if ('text' in value) { |
| + textContent(String(value.text)); |
| + } else if ('any' in value) { |
| + textContent(value.any); |
| + } else if ('html' in value) { |
| + textContent([].concat(value.html).join('')); |
| + } else if ('length' in value) { |
| + textContent(slice.call(value).join('')); |
| + } else { |
| + textContent(Intent.invoke(value, textContent)); |
| + } |
| + } else { |
| + node.textContent = value == null ? '' : value; |
| + } |
| + } |
| + }; |
| + return textContent; |
| +}; |
| + |
| +Object.defineProperty(exports, '__esModule', {value: true}).default = {create, find}; |
| + |
| +// hyper.Components might need connected/disconnected notifications |
| +// used by components and their onconnect/ondisconnect callbacks. |
| +// When one of these callbacks is encountered, |
| +// the document starts being observed. |
| +let notObserving = true; |
| +function observe() { |
| + |
| + // when hyper.Component related DOM nodes |
| + // are appended or removed from the live tree |
| + // these might listen to connected/disconnected events |
| + // This utility is in charge of finding all components |
| + // involved in the DOM update/change and dispatch |
| + // related information to them |
| + const dispatchAll = (nodes, type) => { |
| + const event = new Event(type); |
| + const length = nodes.length; |
| + for (let i = 0; i < length; i++) { |
| + let node = nodes[i]; |
| + if (node.nodeType === ELEMENT_NODE) { |
| + dispatchTarget(node, event); |
| + } |
| + } |
| + }; |
| + |
| + // the way it's done is via the components weak set |
| + // and recursively looking for nested components too |
| + const dispatchTarget = (node, event) => { |
| + if (components.has(node)) { |
| + node.dispatchEvent(event); |
| + } |
| + |
| + const children = node.children; |
| + const length = children.length; |
| + for (let i = 0; i < length; i++) { |
| + dispatchTarget(children[i], event); |
| + } |
| + } |
| + |
| + // The MutationObserver is the best way to implement that |
| + // but there is a fallback to deprecated DOMNodeInserted/Removed |
| + // so that even older browsers/engines can help components life-cycle |
| + try { |
| + (new MutationObserver(records => { |
| + const length = records.length; |
| + for (let i = 0; i < length; i++) { |
| + let record = records[i]; |
| + dispatchAll(record.removedNodes, DISCONNECTED); |
| + dispatchAll(record.addedNodes, CONNECTED); |
| + } |
| + })).observe(document, {subtree: true, childList: true}); |
| + } catch(o_O) { |
| + document.addEventListener('DOMNodeRemoved', event => { |
| + dispatchAll([event.target], DISCONNECTED); |
| + }, false); |
| + document.addEventListener('DOMNodeInserted', event => { |
| + dispatchAll([event.target], CONNECTED); |
| + }, false); |
| + } |
| +} |
| + |
| +},{"../classes/Component.js":4,"../classes/Wire.js":5,"../shared/constants.js":13,"../shared/domdiff.js":14,"../shared/easy-dom.js":15,"../shared/poorlyfills.js":17,"../shared/utils.js":19,"./Intent.js":9,"./Path.js":10,"./Style.js":11}],13:[function(require,module,exports){ |
| +'use strict'; |
| +const G = document.defaultView; |
| +exports.G = G; |
| + |
| +// Node.CONSTANTS |
| +// 'cause some engine has no global Node defined |
| +// (i.e. Node, NativeScript, basicHTML ... ) |
| +const ELEMENT_NODE = 1; |
| +exports.ELEMENT_NODE = ELEMENT_NODE; |
| +const ATTRIBUTE_NODE = 2; |
| +exports.ATTRIBUTE_NODE = ATTRIBUTE_NODE; |
| +const TEXT_NODE = 3; |
| +exports.TEXT_NODE = TEXT_NODE; |
| +const COMMENT_NODE = 8; |
| +exports.COMMENT_NODE = COMMENT_NODE; |
| +const DOCUMENT_FRAGMENT_NODE = 11; |
| +exports.DOCUMENT_FRAGMENT_NODE = DOCUMENT_FRAGMENT_NODE; |
| + |
| +// HTML related constants |
| +const VOID_ELEMENTS = /^area|base|br|col|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr$/i; |
| +exports.VOID_ELEMENTS = VOID_ELEMENTS; |
| + |
| +// SVG related constants |
| +const OWNER_SVG_ELEMENT = 'ownerSVGElement'; |
| +exports.OWNER_SVG_ELEMENT = OWNER_SVG_ELEMENT; |
| +const SVG_NAMESPACE = 'http://www.w3.org/2000/svg'; |
| +exports.SVG_NAMESPACE = SVG_NAMESPACE; |
| + |
| +// Custom Elements / MutationObserver constants |
| +const CONNECTED = 'connected'; |
| +exports.CONNECTED = CONNECTED; |
| +const DISCONNECTED = 'dis' + CONNECTED; |
| +exports.DISCONNECTED = DISCONNECTED; |
| + |
| +// hyperHTML related constants |
| +const EXPANDO = '_hyper: '; |
| +exports.EXPANDO = EXPANDO; |
| +const SHOULD_USE_TEXT_CONTENT = /^style|textarea$/i; |
| +exports.SHOULD_USE_TEXT_CONTENT = SHOULD_USE_TEXT_CONTENT; |
| +const UID = EXPANDO + ((Math.random() * new Date) | 0) + ';'; |
| +exports.UID = UID; |
| +const UIDC = '<!--' + UID + '-->'; |
| +exports.UIDC = UIDC; |
| + |
| +},{}],14:[function(require,module,exports){ |
| +'use strict'; |
| +/* AUTOMATICALLY IMPORTED, DO NOT MODIFY */ |
| +/*! (c) 2017 Andrea Giammarchi (ISC) */ |
| + |
| +/** |
| + * This code is a revisited port of the snabbdom vDOM diffing logic, |
| + * the same that fuels as fork Vue.js or other libraries. |
| + * @credits https://github.com/snabbdom/snabbdom |
| + */ |
| + |
| +const identity = O => O; |
| + |
| +const domdiff = ( |
| + parentNode, // where changes happen |
| + currentNodes, // Array of current items/nodes |
| + futureNodes, // Array of future items/nodes |
| + getNode, // optional way to retrieve a node from an item |
| + beforeNode // optional item/node to use as insertBefore delimiter |
| +) => { |
| + const get = getNode || identity; |
| + const before = beforeNode == null ? null : get(beforeNode, 0); |
| + let currentStart = 0, futureStart = 0; |
| + let currentEnd = currentNodes.length - 1; |
| + let currentStartNode = currentNodes[0]; |
| + let currentEndNode = currentNodes[currentEnd]; |
| + let futureEnd = futureNodes.length - 1; |
| + let futureStartNode = futureNodes[0]; |
| + let futureEndNode = futureNodes[futureEnd]; |
| + while (currentStart <= currentEnd && futureStart <= futureEnd) { |
| + if (currentStartNode == null) { |
| + currentStartNode = currentNodes[++currentStart]; |
| + } |
| + else if (currentEndNode == null) { |
| + currentEndNode = currentNodes[--currentEnd]; |
| + } |
| + else if (futureStartNode == null) { |
| + futureStartNode = futureNodes[++futureStart]; |
| + } |
| + else if (futureEndNode == null) { |
| + futureEndNode = futureNodes[--futureEnd]; |
| + } |
| + else if (currentStartNode == futureStartNode) { |
| + currentStartNode = currentNodes[++currentStart]; |
| + futureStartNode = futureNodes[++futureStart]; |
| + } |
| + else if (currentEndNode == futureEndNode) { |
| + currentEndNode = currentNodes[--currentEnd]; |
| + futureEndNode = futureNodes[--futureEnd]; |
| + } |
| + else if (currentStartNode == futureEndNode) { |
| + parentNode.insertBefore( |
| + get(currentStartNode, 1), |
| + get(currentEndNode, -0).nextSibling |
| + ); |
| + currentStartNode = currentNodes[++currentStart]; |
| + futureEndNode = futureNodes[--futureEnd]; |
| + } |
| + else if (currentEndNode == futureStartNode) { |
| + parentNode.insertBefore( |
| + get(currentEndNode, 1), |
| + get(currentStartNode, 0) |
| + ); |
| + currentEndNode = currentNodes[--currentEnd]; |
| + futureStartNode = futureNodes[++futureStart]; |
| + } |
| + else { |
| + let index = currentNodes.indexOf(futureStartNode); |
| + if (index < 0) { |
| + parentNode.insertBefore( |
| + get(futureStartNode, 1), |
| + get(currentStartNode, 0) |
| + ); |
| + futureStartNode = futureNodes[++futureStart]; |
| + } |
| + else { |
| + let el = currentNodes[index]; |
| + currentNodes[index] = null; |
| + parentNode.insertBefore( |
| + get(el, 1), |
| + get(currentStartNode, 0) |
| + ); |
| + futureStartNode = futureNodes[++futureStart]; |
| + } |
| + } |
| + } |
| + if (currentStart <= currentEnd || futureStart <= futureEnd) { |
| + if (currentStart > currentEnd) { |
| + const pin = futureNodes[futureEnd + 1]; |
| + const place = pin == null ? before : get(pin, 0); |
| + if (futureStart === futureEnd) { |
| + parentNode.insertBefore(get(futureNodes[futureStart], 1), place); |
| + } |
| + else { |
| + const fragment = parentNode.ownerDocument.createDocumentFragment(); |
| + while (futureStart <= futureEnd) { |
| + fragment.appendChild(get(futureNodes[futureStart++], 1)); |
| + } |
| + parentNode.insertBefore(fragment, place); |
| + } |
| + } |
| + else { |
| + if (currentNodes[currentStart] == null) currentStart++; |
| + if (currentStart === currentEnd) { |
| + parentNode.removeChild(get(currentNodes[currentStart], -1)); |
| + } |
| + else { |
| + const range = parentNode.ownerDocument.createRange(); |
| + range.setStartBefore(get(currentNodes[currentStart], -1)); |
| + range.setEndAfter(get(currentNodes[currentEnd], -1)); |
| + range.deleteContents(); |
| + } |
| + } |
| + } |
| + return futureNodes; |
| +}; |
| + |
| +Object.defineProperty(exports, '__esModule', {value: true}).default = domdiff; |
| + |
| +},{}],15:[function(require,module,exports){ |
| +'use strict'; |
| +// these are tiny helpers to simplify most common operations needed here |
| +const create = (node, type) => doc(node).createElement(type); |
| +exports.create = create; |
| +const doc = node => node.ownerDocument || node; |
| +exports.doc = doc; |
| +const fragment = node => doc(node).createDocumentFragment(); |
| +exports.fragment = fragment; |
| +const text = (node, text) => doc(node).createTextNode(text); |
| +exports.text = text; |
| + |
| +},{}],16:[function(require,module,exports){ |
| +'use strict'; |
| +const {create, fragment, text} = require('./easy-dom.js'); |
| + |
| +const testFragment = fragment(document); |
| + |
| +// DOM4 node.append(...many) |
| +const hasAppend = 'append' in testFragment; |
| +exports.hasAppend = hasAppend; |
| + |
| +// detect old browsers without HTMLTemplateElement content support |
| +const hasContent = 'content' in create(document, 'template'); |
| +exports.hasContent = hasContent; |
| + |
| +// IE 11 has problems with cloning templates: it "forgets" empty childNodes |
| +testFragment.appendChild(text(testFragment, 'g')); |
| +testFragment.appendChild(text(testFragment, '')); |
| +const hasDoomedCloneNode = testFragment.cloneNode(true).childNodes.length === 1; |
| +exports.hasDoomedCloneNode = hasDoomedCloneNode; |
| + |
| +// old browsers need to fallback to cloneNode |
| +// Custom Elements V0 and V1 will work polyfilled |
| +// but native implementations need importNode instead |
| +// (specially Chromium and its old V0 implementation) |
| +const hasImportNode = 'importNode' in document; |
| +exports.hasImportNode = hasImportNode; |
| + |
| +},{"./easy-dom.js":15}],17:[function(require,module,exports){ |
| +'use strict'; |
| +const {G, UID} = require('./constants.js'); |
| + |
| +// you know that kind of basics you need to cover |
| +// your use case only but you don't want to bloat the library? |
| +// There's even a package in here: |
| +// https://www.npmjs.com/package/poorlyfills |
| + |
| +// used to dispatch simple events |
| +let Event = G.Event; |
| +try { |
| + new Event('Event'); |
| +} catch(o_O) { |
| + Event = function (type) { |
| + const e = document.createEvent('Event'); |
| + e.initEvent(type, false, false); |
| + return e; |
| + }; |
| +} |
| +exports.Event = Event; |
| + |
| +// used to store template literals |
| +const Map = G.Map || function Map() { |
| + const keys = [], values = []; |
| + return { |
| + get(obj) { |
| + return values[keys.indexOf(obj)]; |
| + }, |
| + set(obj, value) { |
| + values[keys.push(obj) - 1] = value; |
| + } |
| + }; |
| +}; |
| +exports.Map = Map; |
| + |
| +// used to store wired content |
| +const WeakMap = G.WeakMap || function WeakMap() { |
| + return { |
| + get(obj) { return obj[UID]; }, |
| + set(obj, value) { |
| + Object.defineProperty(obj, UID, { |
| + configurable: true, |
| + value |
| + }); |
| + } |
| + }; |
| +}; |
| +exports.WeakMap = WeakMap; |
| + |
| +// used to store hyper.Components |
| +const WeakSet = G.WeakSet || function WeakSet() { |
| + const wm = new WeakMap; |
| + return { |
| + add(obj) { wm.set(obj, true); }, |
| + has(obj) { return wm.get(obj) === true; } |
| + }; |
| +}; |
| +exports.WeakSet = WeakSet; |
| + |
| +// used to be sure IE9 or older Androids work as expected |
| +const isArray = Array.isArray || (toString => |
| + arr => toString.call(arr) === '[object Array]' |
| +)({}.toString); |
| +exports.isArray = isArray; |
| + |
| +const trim = UID.trim || function () { |
| + return this.replace(/^\s+|\s+$/g, ''); |
| +}; |
| +exports.trim = trim; |
| + |
| +},{"./constants.js":13}],18:[function(require,module,exports){ |
| +'use strict'; |
| +// TODO: I'd love to code-cover RegExp too here |
| +// these are fundamental for this library |
| + |
| +const spaces = ' \\f\\n\\r\\t'; |
| +const almostEverything = '[^ ' + spaces + '\\/>"\'=]+'; |
| +const attrName = '[ ' + spaces + ']+' + almostEverything; |
| +const tagName = '<([A-Za-z]+[A-Za-z0-9:_-]*)((?:'; |
| +const attrPartials = '(?:=(?:\'[^\']*?\'|"[^"]*?"|<[^>]*?>|' + almostEverything + '))?)'; |
| + |
| +const attrSeeker = new RegExp( |
| + tagName + attrName + attrPartials + '+)([ ' + spaces + ']*/?>)', |
| + 'g' |
| +); |
| + |
| +const selfClosing = new RegExp( |
| + tagName + attrName + attrPartials + '*)([ ' + spaces + ']*/>)', |
| + 'g' |
| +); |
| + |
| +exports.attrName = attrName; |
| +exports.attrSeeker = attrSeeker; |
| +exports.selfClosing = selfClosing; |
| + |
| +},{}],19:[function(require,module,exports){ |
| +'use strict'; |
| +const {attrName, attrSeeker} = require('./re.js'); |
| + |
| +const { |
| + G, |
| + OWNER_SVG_ELEMENT, |
| + SVG_NAMESPACE, |
| + UID, |
| + UIDC |
| +} = require('./constants.js'); |
| + |
| +const { |
| + hasAppend, |
| + hasContent, |
| + hasDoomedCloneNode, |
| + hasImportNode |
| +} = require('./features-detection.js'); |
| + |
| +const {create, doc, fragment} = require('./easy-dom.js'); |
| + |
| +// appends an array of nodes |
| +// to a generic node/fragment |
| +// When available, uses append passing all arguments at once |
| +// hoping that's somehow faster, even if append has more checks on type |
| +const append = hasAppend ? |
| + (node, childNodes) => { |
| + node.append.apply(node, childNodes); |
| + } : |
| + (node, childNodes) => { |
| + const length = childNodes.length; |
| + for (let i = 0; i < length; i++) { |
| + node.appendChild(childNodes[i]); |
| + } |
| + }; |
| +exports.append = append; |
| + |
| +const findAttributes = new RegExp('(' + attrName + '=)([\'"]?)' + UIDC + '\\2', 'gi'); |
| +const comments = ($0, $1, $2, $3) => |
| + '<' + $1 + $2.replace(findAttributes, replaceAttributes) + $3; |
| +const replaceAttributes = ($0, $1, $2) => $1 + ($2 || '"') + UID + ($2 || '"'); |
| + |
| +// given a node and a generic HTML content, |
| +// create either an SVG or an HTML fragment |
| +// where such content will be injected |
| +const createFragment = (node, html) => |
| + (OWNER_SVG_ELEMENT in node ? |
| + SVGFragment : |
| + HTMLFragment |
| + )(node, html.replace(attrSeeker, comments)); |
| +exports.createFragment = createFragment; |
| + |
| +// IE/Edge shenanigans proof cloneNode |
| +// it goes through all nodes manually |
| +// instead of relying the engine to suddenly |
| +// merge nodes together |
| +const cloneNode = hasDoomedCloneNode ? |
| + node => { |
| + const clone = node.cloneNode(); |
| + const childNodes = node.childNodes || |
| + // this is an excess of caution |
| + // but some node, in IE, might not |
| + // have childNodes property. |
| + // The following fallback ensure working code |
| + // in older IE without compromising performance |
| + // or any other browser/engine involved. |
| + /* istanbul ignore next */ |
| + []; |
| + const length = childNodes.length; |
| + for (let i = 0; i < length; i++) { |
| + clone.appendChild(cloneNode(childNodes[i])); |
| + } |
| + return clone; |
| + } : |
| + // the following ignore is due code-coverage |
| + // combination of not having document.importNode |
| + // but having a working node.cloneNode. |
| + // This shenario is common on older Android/WebKit browsers |
| + // but basicHTML here tests just two major cases: |
| + // with document.importNode or with broken cloneNode. |
| + /* istanbul ignore next */ |
| + node => node.cloneNode(true); |
| + |
| +// used to import html into fragments |
| +const importNode = hasImportNode ? |
| + (doc, node) => doc.importNode(node, true) : |
| + (doc, node) => cloneNode(node) |
| +exports.importNode = importNode |
| + |
| +// just recycling a one-off array to use slice |
| +// in every needed place |
| +const slice = [].slice; |
| +exports.slice = slice; |
| + |
| +// lazy evaluated, returns the unique identity |
| +// of a template literal, as tempalte literal itself. |
| +// By default, ES2015 template literals are unique |
| +// tag`a${1}z` === tag`a${2}z` |
| +// even if interpolated values are different |
| +// the template chunks are in a frozen Array |
| +// that is identical each time you use the same |
| +// literal to represent same static content |
| +// around its own interpolations. |
| +const unique = template => TL(template); |
| +exports.unique = unique; |
| + |
| +// TL returns a unique version of the template |
| +// it needs lazy feature detection |
| +// (cannot trust literals with transpiled code) |
| +let TL = template => { |
| + if ( |
| + // TypeScript template literals are not standard |
| + template.propertyIsEnumerable('raw') || |
| + ( |
| + // Firefox < 55 has not standard implementation neither |
| + /Firefox\/(\d+)/.test((G.navigator || {}).userAgent) && |
| + parseFloat(RegExp.$1) < 55 |
| + ) |
| + ) { |
| + // in these cases, address templates once |
| + const templateObjects = {}; |
| + // but always return the same template |
| + TL = template => { |
| + const key = '_' + template.join(UID); |
| + return templateObjects[key] || ( |
| + templateObjects[key] = template |
| + ); |
| + }; |
| + } |
| + else { |
| + // make TL an identity like function |
| + TL = template => template; |
| + } |
| + return TL(template); |
| +}; |
| + |
| +// create document fragments via native template |
| +// with a fallback for browsers that won't be able |
| +// to deal with some injected element such <td> or others |
| +const HTMLFragment = hasContent ? |
| + (node, html) => { |
| + const container = create(node, 'template'); |
| + container.innerHTML = html; |
| + return container.content; |
| + } : |
| + (node, html) => { |
| + const container = create(node, 'template'); |
| + const content = fragment(node); |
| + if (/^[^\S]*?<(col(?:group)?|t(?:head|body|foot|r|d|h))/i.test(html)) { |
| + const selector = RegExp.$1; |
| + container.innerHTML = '<table>' + html + '</table>'; |
| + append(content, slice.call(container.querySelectorAll(selector))); |
| + } else { |
| + container.innerHTML = html; |
| + append(content, slice.call(container.childNodes)); |
| + } |
| + return content; |
| + }; |
| + |
| +// creates SVG fragment with a fallback for IE that needs SVG |
| +// within the HTML content |
| +const SVGFragment = hasContent ? |
| + (node, html) => { |
| + const content = fragment(node); |
| + const container = doc(node).createElementNS(SVG_NAMESPACE, 'svg'); |
| + container.innerHTML = html; |
| + append(content, slice.call(container.childNodes)); |
| + return content; |
| + } : |
| + (node, html) => { |
| + const content = fragment(node); |
| + const container = create(node, 'div'); |
| + container.innerHTML = '<svg xmlns="' + SVG_NAMESPACE + '">' + html + '</svg>'; |
| + append(content, slice.call(container.firstChild.childNodes)); |
| + return content; |
| + }; |
| + |
| +},{"./constants.js":13,"./easy-dom.js":15,"./features-detection.js":16,"./re.js":18}],20:[function(require,module,exports){ |
| +/* globals module, require */ |
| + |
| +"use strict"; |
| + |
| +const IOElement = require("../js/io-element"); |
| + |
| +class IOClock extends IOElement |
| +{ |
| + connectedCallback() |
| + { |
| + this._timer = setInterval(() => this.render(), 1000); |
| + } |
| + |
| + disconnectedCallback() |
| + { |
| + clearInterval(this._timer); |
| + } |
| + |
| + render() |
| + { |
| + this.html` |
| + ${{i18n: "io_clock"}} |
| + @${(new Date()).toLocaleTimeString()} |
| + `; |
| + } |
| +} |
| + |
| +IOClock.define("io-clock"); |
| + |
| +},{"../js/io-element":1}]},{},[20]); |