123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- /**
- * @license
- * Copyright (c) 2018 The Polymer Project Authors. All rights reserved.
- * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
- * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
- * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
- * Code distributed by Google as part of the polymer project is also
- * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
- */
- (function() {
- 'use strict';
- /**
- * Basic flow of the loader process
- *
- * There are 4 flows the loader can take when booting up
- *
- * - Synchronous script, no polyfills needed
- * - wait for `DOMContentLoaded`
- * - run callbacks passed to `waitFor`
- * - fire WCR event
- *
- * - Synchronous script, polyfills needed
- * - document.write the polyfill bundle
- * - wait on the `load` event of the bundle to batch Custom Element upgrades
- * - wait for `DOMContentLoaded`
- * - run callbacks passed to `waitFor`
- * - fire WCR event
- *
- * - Asynchronous script, no polyfills needed
- * - fire WCR event, as there could not be any callbacks passed to `waitFor`
- *
- * - Asynchronous script, polyfills needed
- * - Append the polyfill bundle script
- * - wait for `load` event of the bundle
- * - batch Custom Element Upgrades
- * - run callbacks pass to `waitFor`
- * - fire WCR event
- */
- var polyfillsLoaded = false;
- var whenLoadedFns = [];
- var allowUpgrades = false;
- var flushFn;
- function fireEvent() {
- window.WebComponents.ready = true;
- document.dispatchEvent(new CustomEvent('WebComponentsReady', { bubbles: true }));
- }
- function batchCustomElements() {
- if (window.customElements && customElements.polyfillWrapFlushCallback) {
- customElements.polyfillWrapFlushCallback(function (flushCallback) {
- flushFn = flushCallback;
- if (allowUpgrades) {
- flushFn();
- }
- });
- }
- }
- function asyncReady() {
- batchCustomElements();
- ready();
- }
- function ready() {
- // bootstrap <template> elements before custom elements
- if (window.HTMLTemplateElement && HTMLTemplateElement.bootstrap) {
- HTMLTemplateElement.bootstrap(window.document);
- }
- polyfillsLoaded = true;
- runWhenLoadedFns().then(fireEvent);
- }
- function runWhenLoadedFns() {
- allowUpgrades = false;
- var done = function() {
- allowUpgrades = true;
- whenLoadedFns.length = 0;
- flushFn && flushFn();
- };
- return Promise.all(whenLoadedFns.map(function(fn) {
- return fn instanceof Function ? fn() : fn;
- })).then(function() {
- done();
- }).catch(function(err) {
- console.error(err);
- });
- }
- window.WebComponents = window.WebComponents || {};
- window.WebComponents.ready = window.WebComponents.ready || false;
- window.WebComponents.waitFor = window.WebComponents.waitFor || function(waitFn) {
- if (!waitFn) {
- return;
- }
- whenLoadedFns.push(waitFn);
- if (polyfillsLoaded) {
- runWhenLoadedFns();
- }
- };
- window.WebComponents._batchCustomElements = batchCustomElements;
- var name = 'webcomponents-loader.js';
- // Feature detect which polyfill needs to be imported.
- var polyfills = [];
- if (!('attachShadow' in Element.prototype && 'getRootNode' in Element.prototype) ||
- (window.ShadyDOM && window.ShadyDOM.force)) {
- polyfills.push('sd');
- }
- if (!window.customElements || window.customElements.forcePolyfill) {
- polyfills.push('ce');
- }
- var needsTemplate = (function() {
- // no real <template> because no `content` property (IE and older browsers)
- var t = document.createElement('template');
- if (!('content' in t)) {
- return true;
- }
- // broken doc fragment (older Edge)
- if (!(t.content.cloneNode() instanceof DocumentFragment)) {
- return true;
- }
- // broken <template> cloning (Edge up to at least version 17)
- var t2 = document.createElement('template');
- t2.content.appendChild(document.createElement('div'));
- t.content.appendChild(t2);
- var clone = t.cloneNode(true);
- return (clone.content.childNodes.length === 0 ||
- clone.content.firstChild.content.childNodes.length === 0);
- })();
- // NOTE: any browser that does not have template or ES6 features
- // must load the full suite of polyfills.
- if (!window.Promise || !Array.from || !window.URL || !window.Symbol || needsTemplate) {
- polyfills = ['sd-ce-pf'];
- }
- if (polyfills.length) {
- var url;
- var polyfillFile = 'bundles/webcomponents-' + polyfills.join('-') + '.js';
- // Load it from the right place.
- if (window.WebComponents.root) {
- url = window.WebComponents.root + polyfillFile;
- } else {
- var script = document.querySelector('script[src*="' + name +'"]');
- // Load it from the right place.
- url = script.src.replace(name, polyfillFile);
- }
- var newScript = document.createElement('script');
- newScript.src = url;
- // if readyState is 'loading', this script is synchronous
- if (document.readyState === 'loading') {
- // make sure custom elements are batched whenever parser gets to the injected script
- newScript.setAttribute('onload', 'window.WebComponents._batchCustomElements()');
- document.write(newScript.outerHTML);
- document.addEventListener('DOMContentLoaded', ready);
- } else {
- newScript.addEventListener('load', function () {
- asyncReady();
- });
- newScript.addEventListener('error', function () {
- throw new Error('Could not load polyfill bundle' + url);
- });
- document.head.appendChild(newScript);
- }
- } else {
- polyfillsLoaded = true;
- if (document.readyState === 'complete') {
- fireEvent()
- } else {
- // this script may come between DCL and load, so listen for both, and cancel load listener if DCL fires
- window.addEventListener('load', ready);
- window.addEventListener('DOMContentLoaded', function() {
- window.removeEventListener('load', ready);
- ready();
- })
- }
- }
- })();
|