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.6.1 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 (function(global) { 48 var registrationsTable = new WeakMap(); 49 var setImmediate; 50 if (/Trident|Edge/.test(navigator.userAgent)) { 51 setImmediate = setTimeout; 52 } else if (window.setImmediate) { 53 setImmediate = window.setImmediate; 54 } else { 55 var setImmediateQueue = []; 56 var sentinel = String(Math.random()); 57 window.addEventListener("message", function(e) { 58 if (e.data === sentinel) { 59 var queue = setImmediateQueue; 60 setImmediateQueue = []; 61 queue.forEach(function(func) { 62 func(); 63 }); 64 } 65 }); 66 setImmediate = function(func) { 67 setImmediateQueue.push(func); 68 window.postMessage(sentinel, "*"); 69 }; 70 } 71 var isScheduled = false; 72 var scheduledObservers = []; 73 function scheduleCallback(observer) { 74 scheduledObservers.push(observer); 75 if (!isScheduled) { 76 isScheduled = true; 77 setImmediate(dispatchCallbacks); 78 } 79 } 80 function wrapIfNeeded(node) { 81 return window.ShadowDOMPolyfill && window.ShadowDOMPolyfill.wrapIfNeeded(node) || node; 82 } 83 function dispatchCallbacks() { 84 isScheduled = false; 85 var observers = scheduledObservers; 86 scheduledObservers = []; 87 observers.sort(function(o1, o2) { 88 return o1.uid_ - o2.uid_; 89 }); 90 var anyNonEmpty = false; 91 observers.forEach(function(observer) { 92 var queue = observer.takeRecords(); 93 removeTransientObserversFor(observer); 94 if (queue.length) { 95 observer.callback_(queue, observer); 96 anyNonEmpty = true; 97 } 98 }); 99 if (anyNonEmpty) dispatchCallbacks(); 100 } 101 function removeTransientObserversFor(observer) { 102 observer.nodes_.forEach(function(node) { 103 var registrations = registrationsTable.get(node); 104 if (!registrations) return; 105 registrations.forEach(function(registration) { 106 if (registration.observer === observer) registration.removeTransientObservers(); 107 }); 108 }); 109 } 110 function forEachAncestorAndObserverEnqueueRecord(target, callback) { 111 for (var node = target; node; node = node.parentNode) { 112 var registrations = registrationsTable.get(node); 113 if (registrations) { 114 for (var j = 0; j < registrations.length; j++) { 115 var registration = registrations[j]; 116 var options = registration.options; 117 if (node !== target && !options.subtree) continue; 118 var record = callback(options); 119 if (record) registration.enqueue(record); 120 } 121 } 122 } 123 } 124 var uidCounter = 0; 125 function JsMutationObserver(callback) { 126 this.callback_ = callback; 127 this.nodes_ = []; 128 this.records_ = []; 129 this.uid_ = ++uidCounter; 130 } 131 JsMutationObserver.prototype = { 132 observe: function(target, options) { 133 target = wrapIfNeeded(target); 134 if (!options.childList && !options.attributes && !options.characterData || options.attributeOldValue && !options.attributes || options.attributeFilter && options.attributeFilter.length && !options.attributes || options.characterDataOldValue && !options.characterData) { 135 throw new SyntaxError(); 136 } 137 var registrations = registrationsTable.get(target); 138 if (!registrations) registrationsTable.set(target, registrations = []); 139 var registration; 140 for (var i = 0; i < registrations.length; i++) { 141 if (registrations[i].observer === this) { 142 registration = registrations[i]; 143 registration.removeListeners(); 144 registration.options = options; 145 break; 146 } 147 } 148 if (!registration) { 149 registration = new Registration(this, target, options); 150 registrations.push(registration); 151 this.nodes_.push(target); 152 } 153 registration.addListeners(); 154 }, 155 disconnect: function() { 156 this.nodes_.forEach(function(node) { 157 var registrations = registrationsTable.get(node); 158 for (var i = 0; i < registrations.length; i++) { 159 var registration = registrations[i]; 160 if (registration.observer === this) { 161 registration.removeListeners(); 162 registrations.splice(i, 1); 163 break; 164 } 165 } 166 }, this); 167 this.records_ = []; 168 }, 169 takeRecords: function() { 170 var copyOfRecords = this.records_; 171 this.records_ = []; 172 return copyOfRecords; 173 } 174 }; 175 function MutationRecord(type, target) { 176 this.type = type; 177 this.target = target; 178 this.addedNodes = []; 179 this.removedNodes = []; 180 this.previousSibling = null; 181 this.nextSibling = null; 182 this.attributeName = null; 183 this.attributeNamespace = null; 184 this.oldValue = null; 185 } 186 function copyMutationRecord(original) { 187 var record = new MutationRecord(original.type, original.target); 188 record.addedNodes = original.addedNodes.slice(); 189 record.removedNodes = original.removedNodes.slice(); 190 record.previousSibling = original.previousSibling; 191 record.nextSibling = original.nextSibling; 192 record.attributeName = original.attributeName; 193 record.attributeNamespace = original.attributeNamespace; 194 record.oldValue = original.oldValue; 195 return record; 196 } 197 var currentRecord, recordWithOldValue; 198 function getRecord(type, target) { 199 return currentRecord = new MutationRecord(type, target); 200 } 201 function getRecordWithOldValue(oldValue) { 202 if (recordWithOldValue) return recordWithOldValue; 203 recordWithOldValue = copyMutationRecord(currentRecord); 204 recordWithOldValue.oldValue = oldValue; 205 return recordWithOldValue; 206 } 207 function clearRecords() { 208 currentRecord = recordWithOldValue = undefined; 209 } 210 function recordRepresentsCurrentMutation(record) { 211 return record === recordWithOldValue || record === currentRecord; 212 } 213 function selectRecord(lastRecord, newRecord) { 214 if (lastRecord === newRecord) return lastRecord; 215 if (recordWithOldValue && recordRepresentsCurrentMutation(lastRecord)) return recordWithOldValue; 216 return null; 217 } 218 function Registration(observer, target, options) { 219 this.observer = observer; 220 this.target = target; 221 this.options = options; 222 this.transientObservedNodes = []; 223 } 224 Registration.prototype = { 225 enqueue: function(record) { 226 var records = this.observer.records_; 227 var length = records.length; 228 if (records.length > 0) { 229 var lastRecord = records[length - 1]; 230 var recordToReplaceLast = selectRecord(lastRecord, record); 231 if (recordToReplaceLast) { 232 records[length - 1] = recordToReplaceLast; 233 return; 234 } 235 } else { 236 scheduleCallback(this.observer); 237 } 238 records[length] = record; 239 }, 240 addListeners: function() { 241 this.addListeners_(this.target); 242 }, 243 addListeners_: function(node) { 244 var options = this.options; 245 if (options.attributes) node.addEventListener("DOMAttrModified", this, true); 246 if (options.characterData) node.addEventListener("DOMCharacterDataModified", this, true); 247 if (options.childList) node.addEventListener("DOMNodeInserted", this, true); 248 if (options.childList || options.subtree) node.addEventListener("DOMNodeRemoved", this, true); 249 }, 250 removeListeners: function() { 251 this.removeListeners_(this.target); 252 }, 253 removeListeners_: function(node) { 254 var options = this.options; 255 if (options.attributes) node.removeEventListener("DOMAttrModified", this, true); 256 if (options.characterData) node.removeEventListener("DOMCharacterDataModified", this, true); 257 if (options.childList) node.removeEventListener("DOMNodeInserted", this, true); 258 if (options.childList || options.subtree) node.removeEventListener("DOMNodeRemoved", this, true); 259 }, 260 addTransientObserver: function(node) { 261 if (node === this.target) return; 262 this.addListeners_(node); 263 this.transientObservedNodes.push(node); 264 var registrations = registrationsTable.get(node); 265 if (!registrations) registrationsTable.set(node, registrations = []); 266 registrations.push(this); 267 }, 268 removeTransientObservers: function() { 269 var transientObservedNodes = this.transientObservedNodes; 270 this.transientObservedNodes = []; 271 transientObservedNodes.forEach(function(node) { 272 this.removeListeners_(node); 273 var registrations = registrationsTable.get(node); 274 for (var i = 0; i < registrations.length; i++) { 275 if (registrations[i] === this) { 276 registrations.splice(i, 1); 277 break; 278 } 279 } 280 }, this); 281 }, 282 handleEvent: function(e) { 283 e.stopImmediatePropagation(); 284 switch (e.type) { 285 case "DOMAttrModified": 286 var name = e.attrName; 287 var namespace = e.relatedNode.namespaceURI; 288 var target = e.target; 289 var record = new getRecord("attributes", target); 290 record.attributeName = name; 291 record.attributeNamespace = namespace; 292 var oldValue = e.attrChange === MutationEvent.ADDITION ? null : e.prevValue; 293 forEachAncestorAndObserverEnqueueRecord(target, function(options) { 294 if (!options.attributes) return; 295 if (options.attributeFilter && options.attributeFilter.length && options.attributeFilter.indexOf(name) === -1 && options.attributeFilter.indexOf(namespace) === -1) { 296 return; 297 } 298 if (options.attributeOldValue) return getRecordWithOldValue(oldValue); 299 return record; 300 }); 301 break; 302 303 case "DOMCharacterDataModified": 304 var target = e.target; 305 var record = getRecord("characterData", target); 306 var oldValue = e.prevValue; 307 forEachAncestorAndObserverEnqueueRecord(target, function(options) { 308 if (!options.characterData) return; 309 if (options.characterDataOldValue) return getRecordWithOldValue(oldValue); 310 return record; 311 }); 312 break; 313 314 case "DOMNodeRemoved": 315 this.addTransientObserver(e.target); 316 317 case "DOMNodeInserted": 318 var changedNode = e.target; 319 var addedNodes, removedNodes; 320 if (e.type === "DOMNodeInserted") { 321 addedNodes = [ changedNode ]; 322 removedNodes = []; 323 } else { 324 addedNodes = []; 325 removedNodes = [ changedNode ]; 326 } 327 var previousSibling = changedNode.previousSibling; 328 var nextSibling = changedNode.nextSibling; 329 var record = getRecord("childList", e.target.parentNode); 330 record.addedNodes = addedNodes; 331 record.removedNodes = removedNodes; 332 record.previousSibling = previousSibling; 333 record.nextSibling = nextSibling; 334 forEachAncestorAndObserverEnqueueRecord(e.relatedNode, function(options) { 335 if (!options.childList) return; 336 return record; 337 }); 338 } 339 clearRecords(); 340 } 341 }; 342 global.JsMutationObserver = JsMutationObserver; 343 if (!global.MutationObserver) global.MutationObserver = JsMutationObserver; 344 })(this); 345 346 window.HTMLImports = window.HTMLImports || { 347 flags: {} 348 }; 349 350 (function(scope) { 351 var IMPORT_LINK_TYPE = "import"; 352 var useNative = Boolean(IMPORT_LINK_TYPE in document.createElement("link")); 353 var hasShadowDOMPolyfill = Boolean(window.ShadowDOMPolyfill); 354 var wrap = function(node) { 355 return hasShadowDOMPolyfill ? ShadowDOMPolyfill.wrapIfNeeded(node) : node; 356 }; 357 var rootDocument = wrap(document); 358 var currentScriptDescriptor = { 359 get: function() { 360 var script = HTMLImports.currentScript || document.currentScript || (document.readyState !== "complete" ? document.scripts[document.scripts.length - 1] : null); 361 return wrap(script); 362 }, 363 configurable: true 364 }; 365 Object.defineProperty(document, "_currentScript", currentScriptDescriptor); 366 Object.defineProperty(rootDocument, "_currentScript", currentScriptDescriptor); 367 var isIE = /Trident|Edge/.test(navigator.userAgent); 368 function whenReady(callback, doc) { 369 doc = doc || rootDocument; 370 whenDocumentReady(function() { 371 watchImportsLoad(callback, doc); 372 }, doc); 373 } 374 var requiredReadyState = isIE ? "complete" : "interactive"; 375 var READY_EVENT = "readystatechange"; 376 function isDocumentReady(doc) { 377 return doc.readyState === "complete" || doc.readyState === requiredReadyState; 378 } 379 function whenDocumentReady(callback, doc) { 380 if (!isDocumentReady(doc)) { 381 var checkReady = function() { 382 if (doc.readyState === "complete" || doc.readyState === requiredReadyState) { 383 doc.removeEventListener(READY_EVENT, checkReady); 384 whenDocumentReady(callback, doc); 385 } 386 }; 387 doc.addEventListener(READY_EVENT, checkReady); 388 } else if (callback) { 389 callback(); 390 } 391 } 392 function markTargetLoaded(event) { 393 event.target.__loaded = true; 394 } 395 function watchImportsLoad(callback, doc) { 396 var imports = doc.querySelectorAll("link[rel=import]"); 397 var parsedCount = 0, importCount = imports.length, newImports = [], errorImports = []; 398 function checkDone() { 399 if (parsedCount == importCount && callback) { 400 callback({ 401 allImports: imports, 402 loadedImports: newImports, 403 errorImports: errorImports 404 }); 405 } 406 } 407 function loadedImport(e) { 408 markTargetLoaded(e); 409 newImports.push(this); 410 parsedCount++; 411 checkDone(); 412 } 413 function errorLoadingImport(e) { 414 errorImports.push(this); 415 parsedCount++; 416 checkDone(); 417 } 418 if (importCount) { 419 for (var i = 0, imp; i < importCount && (imp = imports[i]); i++) { 420 if (isImportLoaded(imp)) { 421 parsedCount++; 422 checkDone(); 423 } else { 424 imp.addEventListener("load", loadedImport); 425 imp.addEventListener("error", errorLoadingImport); 426 } 427 } 428 } else { 429 checkDone(); 430 } 431 } 432 function isImportLoaded(link) { 433 return useNative ? link.__loaded || link.import && link.import.readyState !== "loading" : link.__importParsed; 434 } 435 if (useNative) { 436 new MutationObserver(function(mxns) { 437 for (var i = 0, l = mxns.length, m; i < l && (m = mxns[i]); i++) { 438 if (m.addedNodes) { 439 handleImports(m.addedNodes); 440 } 441 } 442 }).observe(document.head, { 443 childList: true 444 }); 445 function handleImports(nodes) { 446 for (var i = 0, l = nodes.length, n; i < l && (n = nodes[i]); i++) { 447 if (isImport(n)) { 448 handleImport(n); 449 } 450 } 451 } 452 function isImport(element) { 453 return element.localName === "link" && element.rel === "import"; 454 } 455 function handleImport(element) { 456 var loaded = element.import; 457 if (loaded) { 458 markTargetLoaded({ 459 target: element 460 }); 461 } else { 462 element.addEventListener("load", markTargetLoaded); 463 element.addEventListener("error", markTargetLoaded); 464 } 465 } 466 (function() { 467 if (document.readyState === "loading") { 468 var imports = document.querySelectorAll("link[rel=import]"); 469 for (var i = 0, l = imports.length, imp; i < l && (imp = imports[i]); i++) { 470 handleImport(imp); 471 } 472 } 473 })(); 474 } 475 whenReady(function(detail) { 476 HTMLImports.ready = true; 477 HTMLImports.readyTime = new Date().getTime(); 478 var evt = rootDocument.createEvent("CustomEvent"); 479 evt.initCustomEvent("HTMLImportsLoaded", true, true, detail); 480 rootDocument.dispatchEvent(evt); 481 }); 482 scope.IMPORT_LINK_TYPE = IMPORT_LINK_TYPE; 483 scope.useNative = useNative; 484 scope.rootDocument = rootDocument; 485 scope.whenReady = whenReady; 486 scope.isIE = isIE; 487 })(HTMLImports); 488 489 (function(scope) { 490 var modules = []; 491 var addModule = function(module) { 492 modules.push(module); 493 }; 494 var initializeModules = function() { 495 modules.forEach(function(module) { 496 module(scope); 497 }); 498 }; 499 scope.addModule = addModule; 500 scope.initializeModules = initializeModules; 501 })(HTMLImports); 502 503 HTMLImports.addModule(function(scope) { 504 var CSS_URL_REGEXP = /(url\()([^)]*)(\))/g; 505 var CSS_IMPORT_REGEXP = /(@import[\s]+(?!url\())([^;]*)(;)/g; 506 var path = { 507 resolveUrlsInStyle: function(style, linkUrl) { 508 var doc = style.ownerDocument; 509 var resolver = doc.createElement("a"); 510 style.textContent = this.resolveUrlsInCssText(style.textContent, linkUrl, resolver); 511 return style; 512 }, 513 resolveUrlsInCssText: function(cssText, linkUrl, urlObj) { 514 var r = this.replaceUrls(cssText, urlObj, linkUrl, CSS_URL_REGEXP); 515 r = this.replaceUrls(r, urlObj, linkUrl, CSS_IMPORT_REGEXP); 516 return r; 517 }, 518 replaceUrls: function(text, urlObj, linkUrl, regexp) { 519 return text.replace(regexp, function(m, pre, url, post) { 520 var urlPath = url.replace(/["']/g, ""); 521 if (linkUrl) { 522 urlPath = new URL(urlPath, linkUrl).href; 523 } 524 urlObj.href = urlPath; 525 urlPath = urlObj.href; 526 return pre + "'" + urlPath + "'" + post; 527 }); 528 } 529 }; 530 scope.path = path; 531 }); 532 533 HTMLImports.addModule(function(scope) { 534 var xhr = { 535 async: true, 536 ok: function(request) { 537 return request.status >= 200 && request.status < 300 || request.status === 304 || request.status === 0; 538 }, 539 load: function(url, next, nextContext) { 540 var request = new XMLHttpRequest(); 541 if (scope.flags.debug || scope.flags.bust) { 542 url += "?" + Math.random(); 543 } 544 request.open("GET", url, xhr.async); 545 request.addEventListener("readystatechange", function(e) { 546 if (request.readyState === 4) { 547 var locationHeader = request.getResponseHeader("Location"); 548 var redirectedUrl = null; 549 if (locationHeader) { 550 var redirectedUrl = locationHeader.substr(0, 1) === "/" ? location.origin + locationHeader : locationHeader; 551 } 552 next.call(nextContext, !xhr.ok(request) && request, request.response || request.responseText, redirectedUrl); 553 } 554 }); 555 request.send(); 556 return request; 557 }, 558 loadDocument: function(url, next, nextContext) { 559 this.load(url, next, nextContext).responseType = "document"; 560 } 561 }; 562 scope.xhr = xhr; 563 }); 564 565 HTMLImports.addModule(function(scope) { 566 var xhr = scope.xhr; 567 var flags = scope.flags; 568 var Loader = function(onLoad, onComplete) { 569 this.cache = {}; 570 this.onload = onLoad; 571 this.oncomplete = onComplete; 572 this.inflight = 0; 573 this.pending = {}; 574 }; 575 Loader.prototype = { 576 addNodes: function(nodes) { 577 this.inflight += nodes.length; 578 for (var i = 0, l = nodes.length, n; i < l && (n = nodes[i]); i++) { 579 this.require(n); 580 } 581 this.checkDone(); 582 }, 583 addNode: function(node) { 584 this.inflight++; 585 this.require(node); 586 this.checkDone(); 587 }, 588 require: function(elt) { 589 var url = elt.src || elt.href; 590 elt.__nodeUrl = url; 591 if (!this.dedupe(url, elt)) { 592 this.fetch(url, elt); 593 } 594 }, 595 dedupe: function(url, elt) { 596 if (this.pending[url]) { 597 this.pending[url].push(elt); 598 return true; 599 } 600 var resource; 601 if (this.cache[url]) { 602 this.onload(url, elt, this.cache[url]); 603 this.tail(); 604 return true; 605 } 606 this.pending[url] = [ elt ]; 607 return false; 608 }, 609 fetch: function(url, elt) { 610 flags.load && console.log("fetch", url, elt); 611 if (!url) { 612 setTimeout(function() { 613 this.receive(url, elt, { 614 error: "href must be specified" 615 }, null); 616 }.bind(this), 0); 617 } else if (url.match(/^data:/)) { 618 var pieces = url.split(","); 619 var header = pieces[0]; 620 var body = pieces[1]; 621 if (header.indexOf(";base64") > -1) { 622 body = atob(body); 623 } else { 624 body = decodeURIComponent(body); 625 } 626 setTimeout(function() { 627 this.receive(url, elt, null, body); 628 }.bind(this), 0); 629 } else { 630 var receiveXhr = function(err, resource, redirectedUrl) { 631 this.receive(url, elt, err, resource, redirectedUrl); 632 }.bind(this); 633 xhr.load(url, receiveXhr); 634 } 635 }, 636 receive: function(url, elt, err, resource, redirectedUrl) { 637 this.cache[url] = resource; 638 var $p = this.pending[url]; 639 for (var i = 0, l = $p.length, p; i < l && (p = $p[i]); i++) { 640 this.onload(url, p, resource, err, redirectedUrl); 641 this.tail(); 642 } 643 this.pending[url] = null; 644 }, 645 tail: function() { 646 --this.inflight; 647 this.checkDone(); 648 }, 649 checkDone: function() { 650 if (!this.inflight) { 651 this.oncomplete(); 652 } 653 } 654 }; 655 scope.Loader = Loader; 656 }); 657 658 HTMLImports.addModule(function(scope) { 659 var Observer = function(addCallback) { 660 this.addCallback = addCallback; 661 this.mo = new MutationObserver(this.handler.bind(this)); 662 }; 663 Observer.prototype = { 664 handler: function(mutations) { 665 for (var i = 0, l = mutations.length, m; i < l && (m = mutations[i]); i++) { 666 if (m.type === "childList" && m.addedNodes.length) { 667 this.addedNodes(m.addedNodes); 668 } 669 } 670 }, 671 addedNodes: function(nodes) { 672 if (this.addCallback) { 673 this.addCallback(nodes); 674 } 675 for (var i = 0, l = nodes.length, n, loading; i < l && (n = nodes[i]); i++) { 676 if (n.children && n.children.length) { 677 this.addedNodes(n.children); 678 } 679 } 680 }, 681 observe: function(root) { 682 this.mo.observe(root, { 683 childList: true, 684 subtree: true 685 }); 686 } 687 }; 688 scope.Observer = Observer; 689 }); 690 691 HTMLImports.addModule(function(scope) { 692 var path = scope.path; 693 var rootDocument = scope.rootDocument; 694 var flags = scope.flags; 695 var isIE = scope.isIE; 696 var IMPORT_LINK_TYPE = scope.IMPORT_LINK_TYPE; 697 var IMPORT_SELECTOR = "link[rel=" + IMPORT_LINK_TYPE + "]"; 698 var importParser = { 699 documentSelectors: IMPORT_SELECTOR, 700 importsSelectors: [ IMPORT_SELECTOR, "link[rel=stylesheet]", "style", "script:not([type])", 'script[type="text/javascript"]' ].join(","), 701 map: { 702 link: "parseLink", 703 script: "parseScript", 704 style: "parseStyle" 705 }, 706 dynamicElements: [], 707 parseNext: function() { 708 var next = this.nextToParse(); 709 if (next) { 710 this.parse(next); 711 } 712 }, 713 parse: function(elt) { 714 if (this.isParsed(elt)) { 715 flags.parse && console.log("[%s] is already parsed", elt.localName); 716 return; 717 } 718 var fn = this[this.map[elt.localName]]; 719 if (fn) { 720 this.markParsing(elt); 721 fn.call(this, elt); 722 } 723 }, 724 parseDynamic: function(elt, quiet) { 725 this.dynamicElements.push(elt); 726 if (!quiet) { 727 this.parseNext(); 728 } 729 }, 730 markParsing: function(elt) { 731 flags.parse && console.log("parsing", elt); 732 this.parsingElement = elt; 733 }, 734 markParsingComplete: function(elt) { 735 elt.__importParsed = true; 736 this.markDynamicParsingComplete(elt); 737 if (elt.__importElement) { 738 elt.__importElement.__importParsed = true; 739 this.markDynamicParsingComplete(elt.__importElement); 740 } 741 this.parsingElement = null; 742 flags.parse && console.log("completed", elt); 743 }, 744 markDynamicParsingComplete: function(elt) { 745 var i = this.dynamicElements.indexOf(elt); 746 if (i >= 0) { 747 this.dynamicElements.splice(i, 1); 748 } 749 }, 750 parseImport: function(elt) { 751 if (HTMLImports.__importsParsingHook) { 752 HTMLImports.__importsParsingHook(elt); 753 } 754 if (elt.import) { 755 elt.import.__importParsed = true; 756 } 757 this.markParsingComplete(elt); 758 if (elt.__resource && !elt.__error) { 759 elt.dispatchEvent(new CustomEvent("load", { 760 bubbles: false 761 })); 762 } else { 763 elt.dispatchEvent(new CustomEvent("error", { 764 bubbles: false 765 })); 766 } 767 if (elt.__pending) { 768 var fn; 769 while (elt.__pending.length) { 770 fn = elt.__pending.shift(); 771 if (fn) { 772 fn({ 773 target: elt 774 }); 775 } 776 } 777 } 778 this.parseNext(); 779 }, 780 parseLink: function(linkElt) { 781 if (nodeIsImport(linkElt)) { 782 this.parseImport(linkElt); 783 } else { 784 linkElt.href = linkElt.href; 785 this.parseGeneric(linkElt); 786 } 787 }, 788 parseStyle: function(elt) { 789 var src = elt; 790 elt = cloneStyle(elt); 791 src.__appliedElement = elt; 792 elt.__importElement = src; 793 this.parseGeneric(elt); 794 }, 795 parseGeneric: function(elt) { 796 this.trackElement(elt); 797 this.addElementToDocument(elt); 798 }, 799 rootImportForElement: function(elt) { 800 var n = elt; 801 while (n.ownerDocument.__importLink) { 802 n = n.ownerDocument.__importLink; 803 } 804 return n; 805 }, 806 addElementToDocument: function(elt) { 807 var port = this.rootImportForElement(elt.__importElement || elt); 808 port.parentNode.insertBefore(elt, port); 809 }, 810 trackElement: function(elt, callback) { 811 var self = this; 812 var done = function(e) { 813 if (callback) { 814 callback(e); 815 } 816 self.markParsingComplete(elt); 817 self.parseNext(); 818 }; 819 elt.addEventListener("load", done); 820 elt.addEventListener("error", done); 821 if (isIE && elt.localName === "style") { 822 var fakeLoad = false; 823 if (elt.textContent.indexOf("@import") == -1) { 824 fakeLoad = true; 825 } else if (elt.sheet) { 826 fakeLoad = true; 827 var csr = elt.sheet.cssRules; 828 var len = csr ? csr.length : 0; 829 for (var i = 0, r; i < len && (r = csr[i]); i++) { 830 if (r.type === CSSRule.IMPORT_RULE) { 831 fakeLoad = fakeLoad && Boolean(r.styleSheet); 832 } 833 } 834 } 835 if (fakeLoad) { 836 elt.dispatchEvent(new CustomEvent("load", { 837 bubbles: false 838 })); 839 } 840 } 841 }, 842 parseScript: function(scriptElt) { 843 var script = document.createElement("script"); 844 script.__importElement = scriptElt; 845 script.src = scriptElt.src ? scriptElt.src : generateScriptDataUrl(scriptElt); 846 scope.currentScript = scriptElt; 847 this.trackElement(script, function(e) { 848 script.parentNode.removeChild(script); 849 scope.currentScript = null; 850 }); 851 this.addElementToDocument(script); 852 }, 853 nextToParse: function() { 854 this._mayParse = []; 855 return !this.parsingElement && (this.nextToParseInDoc(rootDocument) || this.nextToParseDynamic()); 856 }, 857 nextToParseInDoc: function(doc, link) { 858 if (doc && this._mayParse.indexOf(doc) < 0) { 859 this._mayParse.push(doc); 860 var nodes = doc.querySelectorAll(this.parseSelectorsForNode(doc)); 861 for (var i = 0, l = nodes.length, p = 0, n; i < l && (n = nodes[i]); i++) { 862 if (!this.isParsed(n)) { 863 if (this.hasResource(n)) { 864 return nodeIsImport(n) ? this.nextToParseInDoc(n.import, n) : n; 865 } else { 866 return; 867 } 868 } 869 } 870 } 871 return link; 872 }, 873 nextToParseDynamic: function() { 874 return this.dynamicElements[0]; 875 }, 876 parseSelectorsForNode: function(node) { 877 var doc = node.ownerDocument || node; 878 return doc === rootDocument ? this.documentSelectors : this.importsSelectors; 879 }, 880 isParsed: function(node) { 881 return node.__importParsed; 882 }, 883 needsDynamicParsing: function(elt) { 884 return this.dynamicElements.indexOf(elt) >= 0; 885 }, 886 hasResource: function(node) { 887 if (nodeIsImport(node) && node.import === undefined) { 888 return false; 889 } 890 return true; 891 } 892 }; 893 function nodeIsImport(elt) { 894 return elt.localName === "link" && elt.rel === IMPORT_LINK_TYPE; 895 } 896 function generateScriptDataUrl(script) { 897 var scriptContent = generateScriptContent(script); 898 return "data:text/javascript;charset=utf-8," + encodeURIComponent(scriptContent); 899 } 900 function generateScriptContent(script) { 901 return script.textContent + generateSourceMapHint(script); 902 } 903 function generateSourceMapHint(script) { 904 var owner = script.ownerDocument; 905 owner.__importedScripts = owner.__importedScripts || 0; 906 var moniker = script.ownerDocument.baseURI; 907 var num = owner.__importedScripts ? "-" + owner.__importedScripts : ""; 908 owner.__importedScripts++; 909 return "\n//# sourceURL=" + moniker + num + ".js\n"; 910 } 911 function cloneStyle(style) { 912 var clone = style.ownerDocument.createElement("style"); 913 clone.textContent = style.textContent; 914 path.resolveUrlsInStyle(clone); 915 return clone; 916 } 917 scope.parser = importParser; 918 scope.IMPORT_SELECTOR = IMPORT_SELECTOR; 919 }); 920 921 HTMLImports.addModule(function(scope) { 922 var flags = scope.flags; 923 var IMPORT_LINK_TYPE = scope.IMPORT_LINK_TYPE; 924 var IMPORT_SELECTOR = scope.IMPORT_SELECTOR; 925 var rootDocument = scope.rootDocument; 926 var Loader = scope.Loader; 927 var Observer = scope.Observer; 928 var parser = scope.parser; 929 var importer = { 930 documents: {}, 931 documentPreloadSelectors: IMPORT_SELECTOR, 932 importsPreloadSelectors: [ IMPORT_SELECTOR ].join(","), 933 loadNode: function(node) { 934 importLoader.addNode(node); 935 }, 936 loadSubtree: function(parent) { 937 var nodes = this.marshalNodes(parent); 938 importLoader.addNodes(nodes); 939 }, 940 marshalNodes: function(parent) { 941 return parent.querySelectorAll(this.loadSelectorsForNode(parent)); 942 }, 943 loadSelectorsForNode: function(node) { 944 var doc = node.ownerDocument || node; 945 return doc === rootDocument ? this.documentPreloadSelectors : this.importsPreloadSelectors; 946 }, 947 loaded: function(url, elt, resource, err, redirectedUrl) { 948 flags.load && console.log("loaded", url, elt); 949 elt.__resource = resource; 950 elt.__error = err; 951 if (isImportLink(elt)) { 952 var doc = this.documents[url]; 953 if (doc === undefined) { 954 doc = err ? null : makeDocument(resource, redirectedUrl || url); 955 if (doc) { 956 doc.__importLink = elt; 957 this.bootDocument(doc); 958 } 959 this.documents[url] = doc; 960 } 961 elt.import = doc; 962 } 963 parser.parseNext(); 964 }, 965 bootDocument: function(doc) { 966 this.loadSubtree(doc); 967 this.observer.observe(doc); 968 parser.parseNext(); 969 }, 970 loadedAll: function() { 971 parser.parseNext(); 972 } 973 }; 974 var importLoader = new Loader(importer.loaded.bind(importer), importer.loadedAll.bind(importer)); 975 importer.observer = new Observer(); 976 function isImportLink(elt) { 977 return isLinkRel(elt, IMPORT_LINK_TYPE); 978 } 979 function isLinkRel(elt, rel) { 980 return elt.localName === "link" && elt.getAttribute("rel") === rel; 981 } 982 function hasBaseURIAccessor(doc) { 983 return !!Object.getOwnPropertyDescriptor(doc, "baseURI"); 984 } 985 function makeDocument(resource, url) { 986 var doc = document.implementation.createHTMLDocument(IMPORT_LINK_TYPE); 987 doc._URL = url; 988 var base = doc.createElement("base"); 989 base.setAttribute("href", url); 990 if (!doc.baseURI && !hasBaseURIAccessor(doc)) { 991 Object.defineProperty(doc, "baseURI", { 992 value: url 993 }); 994 } 995 var meta = doc.createElement("meta"); 996 meta.setAttribute("charset", "utf-8"); 997 doc.head.appendChild(meta); 998 doc.head.appendChild(base); 999 doc.body.innerHTML = resource; 1000 if (window.HTMLTemplateElement && HTMLTemplateElement.bootstrap) { 1001 HTMLTemplateElement.bootstrap(doc); 1002 } 1003 return doc; 1004 } 1005 if (!document.baseURI) { 1006 var baseURIDescriptor = { 1007 get: function() { 1008 var base = document.querySelector("base"); 1009 return base ? base.href : window.location.href; 1010 }, 1011 configurable: true 1012 }; 1013 Object.defineProperty(document, "baseURI", baseURIDescriptor); 1014 Object.defineProperty(rootDocument, "baseURI", baseURIDescriptor); 1015 } 1016 scope.importer = importer; 1017 scope.importLoader = importLoader; 1018 }); 1019 1020 HTMLImports.addModule(function(scope) { 1021 var parser = scope.parser; 1022 var importer = scope.importer; 1023 var dynamic = { 1024 added: function(nodes) { 1025 var owner, parsed, loading; 1026 for (var i = 0, l = nodes.length, n; i < l && (n = nodes[i]); i++) { 1027 if (!owner) { 1028 owner = n.ownerDocument; 1029 parsed = parser.isParsed(owner); 1030 } 1031 loading = this.shouldLoadNode(n); 1032 if (loading) { 1033 importer.loadNode(n); 1034 } 1035 if (this.shouldParseNode(n) && parsed) { 1036 parser.parseDynamic(n, loading); 1037 } 1038 } 1039 }, 1040 shouldLoadNode: function(node) { 1041 return node.nodeType === 1 && matches.call(node, importer.loadSelectorsForNode(node)); 1042 }, 1043 shouldParseNode: function(node) { 1044 return node.nodeType === 1 && matches.call(node, parser.parseSelectorsForNode(node)); 1045 } 1046 }; 1047 importer.observer.addCallback = dynamic.added.bind(dynamic); 1048 var matches = HTMLElement.prototype.matches || HTMLElement.prototype.matchesSelector || HTMLElement.prototype.webkitMatchesSelector || HTMLElement.prototype.mozMatchesSelector || HTMLElement.prototype.msMatchesSelector; 1049 }); 1050 1051 (function(scope) { 1052 var initializeModules = scope.initializeModules; 1053 var isIE = scope.isIE; 1054 if (scope.useNative) { 1055 return; 1056 } 1057 if (isIE && typeof window.CustomEvent !== "function") { 1058 window.CustomEvent = function(inType, params) { 1059 params = params || {}; 1060 var e = document.createEvent("CustomEvent"); 1061 e.initCustomEvent(inType, Boolean(params.bubbles), Boolean(params.cancelable), params.detail); 1062 return e; 1063 }; 1064 window.CustomEvent.prototype = window.Event.prototype; 1065 } 1066 initializeModules(); 1067 var rootDocument = scope.rootDocument; 1068 function bootstrap() { 1069 HTMLImports.importer.bootDocument(rootDocument); 1070 } 1071 if (document.readyState === "complete" || document.readyState === "interactive" && !window.attachEvent) { 1072 bootstrap(); 1073 } else { 1074 document.addEventListener("DOMContentLoaded", bootstrap); 1075 } 1076 })(HTMLImports);