Home | History | Annotate | Download | only in webcomponentsjs
      1 /**
      2  * @license
      3  * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
      4  * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
      5  * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
      6  * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
      7  * Code distributed by Google as part of the polymer project is also
      8  * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
      9  */
     10 // @version 0.5.5
     11 if (typeof WeakMap === "undefined") {
     12   (function() {
     13     var defineProperty = Object.defineProperty;
     14     var counter = Date.now() % 1e9;
     15     var WeakMap = function() {
     16       this.name = "__st" + (Math.random() * 1e9 >>> 0) + (counter++ + "__");
     17     };
     18     WeakMap.prototype = {
     19       set: function(key, value) {
     20         var entry = key[this.name];
     21         if (entry && entry[0] === key) entry[1] = value; else defineProperty(key, this.name, {
     22           value: [ key, value ],
     23           writable: true
     24         });
     25         return this;
     26       },
     27       get: function(key) {
     28         var entry;
     29         return (entry = key[this.name]) && entry[0] === key ? entry[1] : undefined;
     30       },
     31       "delete": function(key) {
     32         var entry = key[this.name];
     33         if (!entry || entry[0] !== key) return false;
     34         entry[0] = entry[1] = undefined;
     35         return true;
     36       },
     37       has: function(key) {
     38         var entry = key[this.name];
     39         if (!entry) return false;
     40         return entry[0] === key;
     41       }
     42     };
     43     window.WeakMap = WeakMap;
     44   })();
     45 }
     46 
     47 window.CustomElements = window.CustomElements || {
     48   flags: {}
     49 };
     50 
     51 (function(scope) {
     52   var flags = scope.flags;
     53   var modules = [];
     54   var addModule = function(module) {
     55     modules.push(module);
     56   };
     57   var initializeModules = function() {
     58     modules.forEach(function(module) {
     59       module(scope);
     60     });
     61   };
     62   scope.addModule = addModule;
     63   scope.initializeModules = initializeModules;
     64   scope.hasNative = Boolean(document.registerElement);
     65   scope.useNative = !flags.register && scope.hasNative && !window.ShadowDOMPolyfill && (!window.HTMLImports || HTMLImports.useNative);
     66 })(CustomElements);
     67 
     68 CustomElements.addModule(function(scope) {
     69   var IMPORT_LINK_TYPE = window.HTMLImports ? HTMLImports.IMPORT_LINK_TYPE : "none";
     70   function forSubtree(node, cb) {
     71     findAllElements(node, function(e) {
     72       if (cb(e)) {
     73         return true;
     74       }
     75       forRoots(e, cb);
     76     });
     77     forRoots(node, cb);
     78   }
     79   function findAllElements(node, find, data) {
     80     var e = node.firstElementChild;
     81     if (!e) {
     82       e = node.firstChild;
     83       while (e && e.nodeType !== Node.ELEMENT_NODE) {
     84         e = e.nextSibling;
     85       }
     86     }
     87     while (e) {
     88       if (find(e, data) !== true) {
     89         findAllElements(e, find, data);
     90       }
     91       e = e.nextElementSibling;
     92     }
     93     return null;
     94   }
     95   function forRoots(node, cb) {
     96     var root = node.shadowRoot;
     97     while (root) {
     98       forSubtree(root, cb);
     99       root = root.olderShadowRoot;
    100     }
    101   }
    102   var processingDocuments;
    103   function forDocumentTree(doc, cb) {
    104     processingDocuments = [];
    105     _forDocumentTree(doc, cb);
    106     processingDocuments = null;
    107   }
    108   function _forDocumentTree(doc, cb) {
    109     doc = wrap(doc);
    110     if (processingDocuments.indexOf(doc) >= 0) {
    111       return;
    112     }
    113     processingDocuments.push(doc);
    114     var imports = doc.querySelectorAll("link[rel=" + IMPORT_LINK_TYPE + "]");
    115     for (var i = 0, l = imports.length, n; i < l && (n = imports[i]); i++) {
    116       if (n.import) {
    117         _forDocumentTree(n.import, cb);
    118       }
    119     }
    120     cb(doc);
    121   }
    122   scope.forDocumentTree = forDocumentTree;
    123   scope.forSubtree = forSubtree;
    124 });
    125 
    126 CustomElements.addModule(function(scope) {
    127   var flags = scope.flags;
    128   var forSubtree = scope.forSubtree;
    129   var forDocumentTree = scope.forDocumentTree;
    130   function addedNode(node) {
    131     return added(node) || addedSubtree(node);
    132   }
    133   function added(node) {
    134     if (scope.upgrade(node)) {
    135       return true;
    136     }
    137     attached(node);
    138   }
    139   function addedSubtree(node) {
    140     forSubtree(node, function(e) {
    141       if (added(e)) {
    142         return true;
    143       }
    144     });
    145   }
    146   function attachedNode(node) {
    147     attached(node);
    148     if (inDocument(node)) {
    149       forSubtree(node, function(e) {
    150         attached(e);
    151       });
    152     }
    153   }
    154   var hasPolyfillMutations = !window.MutationObserver || window.MutationObserver === window.JsMutationObserver;
    155   scope.hasPolyfillMutations = hasPolyfillMutations;
    156   var isPendingMutations = false;
    157   var pendingMutations = [];
    158   function deferMutation(fn) {
    159     pendingMutations.push(fn);
    160     if (!isPendingMutations) {
    161       isPendingMutations = true;
    162       setTimeout(takeMutations);
    163     }
    164   }
    165   function takeMutations() {
    166     isPendingMutations = false;
    167     var $p = pendingMutations;
    168     for (var i = 0, l = $p.length, p; i < l && (p = $p[i]); i++) {
    169       p();
    170     }
    171     pendingMutations = [];
    172   }
    173   function attached(element) {
    174     if (hasPolyfillMutations) {
    175       deferMutation(function() {
    176         _attached(element);
    177       });
    178     } else {
    179       _attached(element);
    180     }
    181   }
    182   function _attached(element) {
    183     if (element.__upgraded__ && (element.attachedCallback || element.detachedCallback)) {
    184       if (!element.__attached && inDocument(element)) {
    185         element.__attached = true;
    186         if (element.attachedCallback) {
    187           element.attachedCallback();
    188         }
    189       }
    190     }
    191   }
    192   function detachedNode(node) {
    193     detached(node);
    194     forSubtree(node, function(e) {
    195       detached(e);
    196     });
    197   }
    198   function detached(element) {
    199     if (hasPolyfillMutations) {
    200       deferMutation(function() {
    201         _detached(element);
    202       });
    203     } else {
    204       _detached(element);
    205     }
    206   }
    207   function _detached(element) {
    208     if (element.__upgraded__ && (element.attachedCallback || element.detachedCallback)) {
    209       if (element.__attached && !inDocument(element)) {
    210         element.__attached = false;
    211         if (element.detachedCallback) {
    212           element.detachedCallback();
    213         }
    214       }
    215     }
    216   }
    217   function inDocument(element) {
    218     var p = element;
    219     var doc = wrap(document);
    220     while (p) {
    221       if (p == doc) {
    222         return true;
    223       }
    224       p = p.parentNode || p.host;
    225     }
    226   }
    227   function watchShadow(node) {
    228     if (node.shadowRoot && !node.shadowRoot.__watched) {
    229       flags.dom && console.log("watching shadow-root for: ", node.localName);
    230       var root = node.shadowRoot;
    231       while (root) {
    232         observe(root);
    233         root = root.olderShadowRoot;
    234       }
    235     }
    236   }
    237   function handler(mutations) {
    238     if (flags.dom) {
    239       var mx = mutations[0];
    240       if (mx && mx.type === "childList" && mx.addedNodes) {
    241         if (mx.addedNodes) {
    242           var d = mx.addedNodes[0];
    243           while (d && d !== document && !d.host) {
    244             d = d.parentNode;
    245           }
    246           var u = d && (d.URL || d._URL || d.host && d.host.localName) || "";
    247           u = u.split("/?").shift().split("/").pop();
    248         }
    249       }
    250       console.group("mutations (%d) [%s]", mutations.length, u || "");
    251     }
    252     mutations.forEach(function(mx) {
    253       if (mx.type === "childList") {
    254         forEach(mx.addedNodes, function(n) {
    255           if (!n.localName) {
    256             return;
    257           }
    258           addedNode(n);
    259         });
    260         forEach(mx.removedNodes, function(n) {
    261           if (!n.localName) {
    262             return;
    263           }
    264           detachedNode(n);
    265         });
    266       }
    267     });
    268     flags.dom && console.groupEnd();
    269   }
    270   function takeRecords(node) {
    271     node = wrap(node);
    272     if (!node) {
    273       node = wrap(document);
    274     }
    275     while (node.parentNode) {
    276       node = node.parentNode;
    277     }
    278     var observer = node.__observer;
    279     if (observer) {
    280       handler(observer.takeRecords());
    281       takeMutations();
    282     }
    283   }
    284   var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
    285   function observe(inRoot) {
    286     if (inRoot.__observer) {
    287       return;
    288     }
    289     var observer = new MutationObserver(handler);
    290     observer.observe(inRoot, {
    291       childList: true,
    292       subtree: true
    293     });
    294     inRoot.__observer = observer;
    295   }
    296   function upgradeDocument(doc) {
    297     doc = wrap(doc);
    298     flags.dom && console.group("upgradeDocument: ", doc.baseURI.split("/").pop());
    299     addedNode(doc);
    300     observe(doc);
    301     flags.dom && console.groupEnd();
    302   }
    303   function upgradeDocumentTree(doc) {
    304     forDocumentTree(doc, upgradeDocument);
    305   }
    306   var originalCreateShadowRoot = Element.prototype.createShadowRoot;
    307   if (originalCreateShadowRoot) {
    308     Element.prototype.createShadowRoot = function() {
    309       var root = originalCreateShadowRoot.call(this);
    310       CustomElements.watchShadow(this);
    311       return root;
    312     };
    313   }
    314   scope.watchShadow = watchShadow;
    315   scope.upgradeDocumentTree = upgradeDocumentTree;
    316   scope.upgradeSubtree = addedSubtree;
    317   scope.upgradeAll = addedNode;
    318   scope.attachedNode = attachedNode;
    319   scope.takeRecords = takeRecords;
    320 });
    321 
    322 CustomElements.addModule(function(scope) {
    323   var flags = scope.flags;
    324   function upgrade(node) {
    325     if (!node.__upgraded__ && node.nodeType === Node.ELEMENT_NODE) {
    326       var is = node.getAttribute("is");
    327       var definition = scope.getRegisteredDefinition(is || node.localName);
    328       if (definition) {
    329         if (is && definition.tag == node.localName) {
    330           return upgradeWithDefinition(node, definition);
    331         } else if (!is && !definition.extends) {
    332           return upgradeWithDefinition(node, definition);
    333         }
    334       }
    335     }
    336   }
    337   function upgradeWithDefinition(element, definition) {
    338     flags.upgrade && console.group("upgrade:", element.localName);
    339     if (definition.is) {
    340       element.setAttribute("is", definition.is);
    341     }
    342     implementPrototype(element, definition);
    343     element.__upgraded__ = true;
    344     created(element);
    345     scope.attachedNode(element);
    346     scope.upgradeSubtree(element);
    347     flags.upgrade && console.groupEnd();
    348     return element;
    349   }
    350   function implementPrototype(element, definition) {
    351     if (Object.__proto__) {
    352       element.__proto__ = definition.prototype;
    353     } else {
    354       customMixin(element, definition.prototype, definition.native);
    355       element.__proto__ = definition.prototype;
    356     }
    357   }
    358   function customMixin(inTarget, inSrc, inNative) {
    359     var used = {};
    360     var p = inSrc;
    361     while (p !== inNative && p !== HTMLElement.prototype) {
    362       var keys = Object.getOwnPropertyNames(p);
    363       for (var i = 0, k; k = keys[i]; i++) {
    364         if (!used[k]) {
    365           Object.defineProperty(inTarget, k, Object.getOwnPropertyDescriptor(p, k));
    366           used[k] = 1;
    367         }
    368       }
    369       p = Object.getPrototypeOf(p);
    370     }
    371   }
    372   function created(element) {
    373     if (element.createdCallback) {
    374       element.createdCallback();
    375     }
    376   }
    377   scope.upgrade = upgrade;
    378   scope.upgradeWithDefinition = upgradeWithDefinition;
    379   scope.implementPrototype = implementPrototype;
    380 });
    381 
    382 CustomElements.addModule(function(scope) {
    383   var upgradeDocumentTree = scope.upgradeDocumentTree;
    384   var upgrade = scope.upgrade;
    385   var upgradeWithDefinition = scope.upgradeWithDefinition;
    386   var implementPrototype = scope.implementPrototype;
    387   var useNative = scope.useNative;
    388   function register(name, options) {
    389     var definition = options || {};
    390     if (!name) {
    391       throw new Error("document.registerElement: first argument `name` must not be empty");
    392     }
    393     if (name.indexOf("-") < 0) {
    394       throw new Error("document.registerElement: first argument ('name') must contain a dash ('-'). Argument provided was '" + String(name) + "'.");
    395     }
    396     if (isReservedTag(name)) {
    397       throw new Error("Failed to execute 'registerElement' on 'Document': Registration failed for type '" + String(name) + "'. The type name is invalid.");
    398     }
    399     if (getRegisteredDefinition(name)) {
    400       throw new Error("DuplicateDefinitionError: a type with name '" + String(name) + "' is already registered");
    401     }
    402     if (!definition.prototype) {
    403       definition.prototype = Object.create(HTMLElement.prototype);
    404     }
    405     definition.__name = name.toLowerCase();
    406     definition.lifecycle = definition.lifecycle || {};
    407     definition.ancestry = ancestry(definition.extends);
    408     resolveTagName(definition);
    409     resolvePrototypeChain(definition);
    410     overrideAttributeApi(definition.prototype);
    411     registerDefinition(definition.__name, definition);
    412     definition.ctor = generateConstructor(definition);
    413     definition.ctor.prototype = definition.prototype;
    414     definition.prototype.constructor = definition.ctor;
    415     if (scope.ready) {
    416       upgradeDocumentTree(document);
    417     }
    418     return definition.ctor;
    419   }
    420   function overrideAttributeApi(prototype) {
    421     if (prototype.setAttribute._polyfilled) {
    422       return;
    423     }
    424     var setAttribute = prototype.setAttribute;
    425     prototype.setAttribute = function(name, value) {
    426       changeAttribute.call(this, name, value, setAttribute);
    427     };
    428     var removeAttribute = prototype.removeAttribute;
    429     prototype.removeAttribute = function(name) {
    430       changeAttribute.call(this, name, null, removeAttribute);
    431     };
    432     prototype.setAttribute._polyfilled = true;
    433   }
    434   function changeAttribute(name, value, operation) {
    435     name = name.toLowerCase();
    436     var oldValue = this.getAttribute(name);
    437     operation.apply(this, arguments);
    438     var newValue = this.getAttribute(name);
    439     if (this.attributeChangedCallback && newValue !== oldValue) {
    440       this.attributeChangedCallback(name, oldValue, newValue);
    441     }
    442   }
    443   function isReservedTag(name) {
    444     for (var i = 0; i < reservedTagList.length; i++) {
    445       if (name === reservedTagList[i]) {
    446         return true;
    447       }
    448     }
    449   }
    450   var reservedTagList = [ "annotation-xml", "color-profile", "font-face", "font-face-src", "font-face-uri", "font-face-format", "font-face-name", "missing-glyph" ];
    451   function ancestry(extnds) {
    452     var extendee = getRegisteredDefinition(extnds);
    453     if (extendee) {
    454       return ancestry(extendee.extends).concat([ extendee ]);
    455     }
    456     return [];
    457   }
    458   function resolveTagName(definition) {
    459     var baseTag = definition.extends;
    460     for (var i = 0, a; a = definition.ancestry[i]; i++) {
    461       baseTag = a.is && a.tag;
    462     }
    463     definition.tag = baseTag || definition.__name;
    464     if (baseTag) {
    465       definition.is = definition.__name;
    466     }
    467   }
    468   function resolvePrototypeChain(definition) {
    469     if (!Object.__proto__) {
    470       var nativePrototype = HTMLElement.prototype;
    471       if (definition.is) {
    472         var inst = document.createElement(definition.tag);
    473         var expectedPrototype = Object.getPrototypeOf(inst);
    474         if (expectedPrototype === definition.prototype) {
    475           nativePrototype = expectedPrototype;
    476         }
    477       }
    478       var proto = definition.prototype, ancestor;
    479       while (proto && proto !== nativePrototype) {
    480         ancestor = Object.getPrototypeOf(proto);
    481         proto.__proto__ = ancestor;
    482         proto = ancestor;
    483       }
    484       definition.native = nativePrototype;
    485     }
    486   }
    487   function instantiate(definition) {
    488     return upgradeWithDefinition(domCreateElement(definition.tag), definition);
    489   }
    490   var registry = {};
    491   function getRegisteredDefinition(name) {
    492     if (name) {
    493       return registry[name.toLowerCase()];
    494     }
    495   }
    496   function registerDefinition(name, definition) {
    497     registry[name] = definition;
    498   }
    499   function generateConstructor(definition) {
    500     return function() {
    501       return instantiate(definition);
    502     };
    503   }
    504   var HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
    505   function createElementNS(namespace, tag, typeExtension) {
    506     if (namespace === HTML_NAMESPACE) {
    507       return createElement(tag, typeExtension);
    508     } else {
    509       return domCreateElementNS(namespace, tag);
    510     }
    511   }
    512   function createElement(tag, typeExtension) {
    513     var definition = getRegisteredDefinition(typeExtension || tag);
    514     if (definition) {
    515       if (tag == definition.tag && typeExtension == definition.is) {
    516         return new definition.ctor();
    517       }
    518       if (!typeExtension && !definition.is) {
    519         return new definition.ctor();
    520       }
    521     }
    522     var element;
    523     if (typeExtension) {
    524       element = createElement(tag);
    525       element.setAttribute("is", typeExtension);
    526       return element;
    527     }
    528     element = domCreateElement(tag);
    529     if (tag.indexOf("-") >= 0) {
    530       implementPrototype(element, HTMLElement);
    531     }
    532     return element;
    533   }
    534   function cloneNode(deep) {
    535     var n = domCloneNode.call(this, deep);
    536     upgrade(n);
    537     return n;
    538   }
    539   var domCreateElement = document.createElement.bind(document);
    540   var domCreateElementNS = document.createElementNS.bind(document);
    541   var domCloneNode = Node.prototype.cloneNode;
    542   var isInstance;
    543   if (!Object.__proto__ && !useNative) {
    544     isInstance = function(obj, ctor) {
    545       var p = obj;
    546       while (p) {
    547         if (p === ctor.prototype) {
    548           return true;
    549         }
    550         p = p.__proto__;
    551       }
    552       return false;
    553     };
    554   } else {
    555     isInstance = function(obj, base) {
    556       return obj instanceof base;
    557     };
    558   }
    559   document.registerElement = register;
    560   document.createElement = createElement;
    561   document.createElementNS = createElementNS;
    562   Node.prototype.cloneNode = cloneNode;
    563   scope.registry = registry;
    564   scope.instanceof = isInstance;
    565   scope.reservedTagList = reservedTagList;
    566   scope.getRegisteredDefinition = getRegisteredDefinition;
    567   document.register = document.registerElement;
    568 });
    569 
    570 (function(scope) {
    571   var useNative = scope.useNative;
    572   var initializeModules = scope.initializeModules;
    573   var isIE11OrOlder = /Trident/.test(navigator.userAgent);
    574   if (useNative) {
    575     var nop = function() {};
    576     scope.watchShadow = nop;
    577     scope.upgrade = nop;
    578     scope.upgradeAll = nop;
    579     scope.upgradeDocumentTree = nop;
    580     scope.upgradeSubtree = nop;
    581     scope.takeRecords = nop;
    582     scope.instanceof = function(obj, base) {
    583       return obj instanceof base;
    584     };
    585   } else {
    586     initializeModules();
    587   }
    588   var upgradeDocumentTree = scope.upgradeDocumentTree;
    589   if (!window.wrap) {
    590     if (window.ShadowDOMPolyfill) {
    591       window.wrap = ShadowDOMPolyfill.wrapIfNeeded;
    592       window.unwrap = ShadowDOMPolyfill.unwrapIfNeeded;
    593     } else {
    594       window.wrap = window.unwrap = function(node) {
    595         return node;
    596       };
    597     }
    598   }
    599   function bootstrap() {
    600     upgradeDocumentTree(wrap(document));
    601     if (window.HTMLImports) {
    602       HTMLImports.__importsParsingHook = function(elt) {
    603         upgradeDocumentTree(wrap(elt.import));
    604       };
    605     }
    606     CustomElements.ready = true;
    607     setTimeout(function() {
    608       CustomElements.readyTime = Date.now();
    609       if (window.HTMLImports) {
    610         CustomElements.elapsed = CustomElements.readyTime - HTMLImports.readyTime;
    611       }
    612       document.dispatchEvent(new CustomEvent("WebComponentsReady", {
    613         bubbles: true
    614       }));
    615     });
    616   }
    617   if (isIE11OrOlder && typeof window.CustomEvent !== "function") {
    618     window.CustomEvent = function(inType, params) {
    619       params = params || {};
    620       var e = document.createEvent("CustomEvent");
    621       e.initCustomEvent(inType, Boolean(params.bubbles), Boolean(params.cancelable), params.detail);
    622       return e;
    623     };
    624     window.CustomEvent.prototype = window.Event.prototype;
    625   }
    626   if (document.readyState === "complete" || scope.flags.eager) {
    627     bootstrap();
    628   } else if (document.readyState === "interactive" && !window.attachEvent && (!window.HTMLImports || window.HTMLImports.ready)) {
    629     bootstrap();
    630   } else {
    631     var loadEvent = window.HTMLImports && !HTMLImports.ready ? "HTMLImportsLoaded" : "DOMContentLoaded";
    632     window.addEventListener(loadEvent, bootstrap);
    633   }
    634 })(window.CustomElements);