Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(133)

Side by Side Diff: pkg/custom_element/lib/custom-elements.debug.js

Issue 158083002: introduce web_components pkg for consolidated polyfills (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/custom_element/REVISION ('k') | pkg/custom_element/lib/custom-elements.min.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Polymer Authors. All rights reserved.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 // * Neither the name of Google Inc. nor the names of its
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 if (typeof WeakMap === 'undefined') {
29 (function() {
30 var defineProperty = Object.defineProperty;
31 var counter = Date.now() % 1e9;
32
33 var WeakMap = function() {
34 this.name = '__st' + (Math.random() * 1e9 >>> 0) + (counter++ + '__');
35 };
36
37 WeakMap.prototype = {
38 set: function(key, value) {
39 var entry = key[this.name];
40 if (entry && entry[0] === key)
41 entry[1] = value;
42 else
43 defineProperty(key, this.name, {value: [key, value], writable: true});
44 },
45 get: function(key) {
46 var entry;
47 return (entry = key[this.name]) && entry[0] === key ?
48 entry[1] : undefined;
49 },
50 delete: function(key) {
51 this.set(key, undefined);
52 }
53 };
54
55 window.WeakMap = WeakMap;
56 })();
57 }
58
59 (function(global) {
60
61 var registrationsTable = new WeakMap();
62
63 // We use setImmediate or postMessage for our future callback.
64 var setImmediate = window.msSetImmediate;
65
66 // Use post message to emulate setImmediate.
67 if (!setImmediate) {
68 var setImmediateQueue = [];
69 var sentinel = String(Math.random());
70 window.addEventListener('message', function(e) {
71 if (e.data === sentinel) {
72 var queue = setImmediateQueue;
73 setImmediateQueue = [];
74 queue.forEach(function(func) {
75 func();
76 });
77 }
78 });
79 setImmediate = function(func) {
80 setImmediateQueue.push(func);
81 window.postMessage(sentinel, '*');
82 };
83 }
84
85 // This is used to ensure that we never schedule 2 callas to setImmediate
86 var isScheduled = false;
87
88 // Keep track of observers that needs to be notified next time.
89 var scheduledObservers = [];
90
91 /**
92 * Schedules |dispatchCallback| to be called in the future.
93 * @param {MutationObserver} observer
94 */
95 function scheduleCallback(observer) {
96 scheduledObservers.push(observer);
97 if (!isScheduled) {
98 isScheduled = true;
99 setImmediate(dispatchCallbacks);
100 }
101 }
102
103 function wrapIfNeeded(node) {
104 return window.ShadowDOMPolyfill &&
105 window.ShadowDOMPolyfill.wrapIfNeeded(node) ||
106 node;
107 }
108
109 function dispatchCallbacks() {
110 // http://dom.spec.whatwg.org/#mutation-observers
111
112 isScheduled = false; // Used to allow a new setImmediate call above.
113
114 var observers = scheduledObservers;
115 scheduledObservers = [];
116 // Sort observers based on their creation UID (incremental).
117 observers.sort(function(o1, o2) {
118 return o1.uid_ - o2.uid_;
119 });
120
121 var anyNonEmpty = false;
122 observers.forEach(function(observer) {
123
124 // 2.1, 2.2
125 var queue = observer.takeRecords();
126 // 2.3. Remove all transient registered observers whose observer is mo.
127 removeTransientObserversFor(observer);
128
129 // 2.4
130 if (queue.length) {
131 observer.callback_(queue, observer);
132 anyNonEmpty = true;
133 }
134 });
135
136 // 3.
137 if (anyNonEmpty)
138 dispatchCallbacks();
139 }
140
141 function removeTransientObserversFor(observer) {
142 observer.nodes_.forEach(function(node) {
143 var registrations = registrationsTable.get(node);
144 if (!registrations)
145 return;
146 registrations.forEach(function(registration) {
147 if (registration.observer === observer)
148 registration.removeTransientObservers();
149 });
150 });
151 }
152
153 /**
154 * This function is used for the "For each registered observer observer (with
155 * observer's options as options) in target's list of registered observers,
156 * run these substeps:" and the "For each ancestor ancestor of target, and for
157 * each registered observer observer (with options options) in ancestor's list
158 * of registered observers, run these substeps:" part of the algorithms. The
159 * |options.subtree| is checked to ensure that the callback is called
160 * correctly.
161 *
162 * @param {Node} target
163 * @param {function(MutationObserverInit):MutationRecord} callback
164 */
165 function forEachAncestorAndObserverEnqueueRecord(target, callback) {
166 for (var node = target; node; node = node.parentNode) {
167 var registrations = registrationsTable.get(node);
168
169 if (registrations) {
170 for (var j = 0; j < registrations.length; j++) {
171 var registration = registrations[j];
172 var options = registration.options;
173
174 // Only target ignores subtree.
175 if (node !== target && !options.subtree)
176 continue;
177
178 var record = callback(options);
179 if (record)
180 registration.enqueue(record);
181 }
182 }
183 }
184 }
185
186 var uidCounter = 0;
187
188 /**
189 * The class that maps to the DOM MutationObserver interface.
190 * @param {Function} callback.
191 * @constructor
192 */
193 function JsMutationObserver(callback) {
194 this.callback_ = callback;
195 this.nodes_ = [];
196 this.records_ = [];
197 this.uid_ = ++uidCounter;
198 }
199
200 JsMutationObserver.prototype = {
201 observe: function(target, options) {
202 target = wrapIfNeeded(target);
203
204 // 1.1
205 if (!options.childList && !options.attributes && !options.characterData ||
206
207 // 1.2
208 options.attributeOldValue && !options.attributes ||
209
210 // 1.3
211 options.attributeFilter && options.attributeFilter.length &&
212 !options.attributes ||
213
214 // 1.4
215 options.characterDataOldValue && !options.characterData) {
216
217 throw new SyntaxError();
218 }
219
220 var registrations = registrationsTable.get(target);
221 if (!registrations)
222 registrationsTable.set(target, registrations = []);
223
224 // 2
225 // If target's list of registered observers already includes a registered
226 // observer associated with the context object, replace that registered
227 // observer's options with options.
228 var registration;
229 for (var i = 0; i < registrations.length; i++) {
230 if (registrations[i].observer === this) {
231 registration = registrations[i];
232 registration.removeListeners();
233 registration.options = options;
234 break;
235 }
236 }
237
238 // 3.
239 // Otherwise, add a new registered observer to target's list of registered
240 // observers with the context object as the observer and options as the
241 // options, and add target to context object's list of nodes on which it
242 // is registered.
243 if (!registration) {
244 registration = new Registration(this, target, options);
245 registrations.push(registration);
246 this.nodes_.push(target);
247 }
248
249 registration.addListeners();
250 },
251
252 disconnect: function() {
253 this.nodes_.forEach(function(node) {
254 var registrations = registrationsTable.get(node);
255 for (var i = 0; i < registrations.length; i++) {
256 var registration = registrations[i];
257 if (registration.observer === this) {
258 registration.removeListeners();
259 registrations.splice(i, 1);
260 // Each node can only have one registered observer associated with
261 // this observer.
262 break;
263 }
264 }
265 }, this);
266 this.records_ = [];
267 },
268
269 takeRecords: function() {
270 var copyOfRecords = this.records_;
271 this.records_ = [];
272 return copyOfRecords;
273 }
274 };
275
276 /**
277 * @param {string} type
278 * @param {Node} target
279 * @constructor
280 */
281 function MutationRecord(type, target) {
282 this.type = type;
283 this.target = target;
284 this.addedNodes = [];
285 this.removedNodes = [];
286 this.previousSibling = null;
287 this.nextSibling = null;
288 this.attributeName = null;
289 this.attributeNamespace = null;
290 this.oldValue = null;
291 }
292
293 function copyMutationRecord(original) {
294 var record = new MutationRecord(original.type, original.target);
295 record.addedNodes = original.addedNodes.slice();
296 record.removedNodes = original.removedNodes.slice();
297 record.previousSibling = original.previousSibling;
298 record.nextSibling = original.nextSibling;
299 record.attributeName = original.attributeName;
300 record.attributeNamespace = original.attributeNamespace;
301 record.oldValue = original.oldValue;
302 return record;
303 };
304
305 // We keep track of the two (possibly one) records used in a single mutation.
306 var currentRecord, recordWithOldValue;
307
308 /**
309 * Creates a record without |oldValue| and caches it as |currentRecord| for
310 * later use.
311 * @param {string} oldValue
312 * @return {MutationRecord}
313 */
314 function getRecord(type, target) {
315 return currentRecord = new MutationRecord(type, target);
316 }
317
318 /**
319 * Gets or creates a record with |oldValue| based in the |currentRecord|
320 * @param {string} oldValue
321 * @return {MutationRecord}
322 */
323 function getRecordWithOldValue(oldValue) {
324 if (recordWithOldValue)
325 return recordWithOldValue;
326 recordWithOldValue = copyMutationRecord(currentRecord);
327 recordWithOldValue.oldValue = oldValue;
328 return recordWithOldValue;
329 }
330
331 function clearRecords() {
332 currentRecord = recordWithOldValue = undefined;
333 }
334
335 /**
336 * @param {MutationRecord} record
337 * @return {boolean} Whether the record represents a record from the current
338 * mutation event.
339 */
340 function recordRepresentsCurrentMutation(record) {
341 return record === recordWithOldValue || record === currentRecord;
342 }
343
344 /**
345 * Selects which record, if any, to replace the last record in the queue.
346 * This returns |null| if no record should be replaced.
347 *
348 * @param {MutationRecord} lastRecord
349 * @param {MutationRecord} newRecord
350 * @param {MutationRecord}
351 */
352 function selectRecord(lastRecord, newRecord) {
353 if (lastRecord === newRecord)
354 return lastRecord;
355
356 // Check if the the record we are adding represents the same record. If
357 // so, we keep the one with the oldValue in it.
358 if (recordWithOldValue && recordRepresentsCurrentMutation(lastRecord))
359 return recordWithOldValue;
360
361 return null;
362 }
363
364 /**
365 * Class used to represent a registered observer.
366 * @param {MutationObserver} observer
367 * @param {Node} target
368 * @param {MutationObserverInit} options
369 * @constructor
370 */
371 function Registration(observer, target, options) {
372 this.observer = observer;
373 this.target = target;
374 this.options = options;
375 this.transientObservedNodes = [];
376 }
377
378 Registration.prototype = {
379 enqueue: function(record) {
380 var records = this.observer.records_;
381 var length = records.length;
382
383 // There are cases where we replace the last record with the new record.
384 // For example if the record represents the same mutation we need to use
385 // the one with the oldValue. If we get same record (this can happen as we
386 // walk up the tree) we ignore the new record.
387 if (records.length > 0) {
388 var lastRecord = records[length - 1];
389 var recordToReplaceLast = selectRecord(lastRecord, record);
390 if (recordToReplaceLast) {
391 records[length - 1] = recordToReplaceLast;
392 return;
393 }
394 } else {
395 scheduleCallback(this.observer);
396 }
397
398 records[length] = record;
399 },
400
401 addListeners: function() {
402 this.addListeners_(this.target);
403 },
404
405 addListeners_: function(node) {
406 var options = this.options;
407 if (options.attributes)
408 node.addEventListener('DOMAttrModified', this, true);
409
410 if (options.characterData)
411 node.addEventListener('DOMCharacterDataModified', this, true);
412
413 if (options.childList)
414 node.addEventListener('DOMNodeInserted', this, true);
415
416 if (options.childList || options.subtree)
417 node.addEventListener('DOMNodeRemoved', this, true);
418 },
419
420 removeListeners: function() {
421 this.removeListeners_(this.target);
422 },
423
424 removeListeners_: function(node) {
425 var options = this.options;
426 if (options.attributes)
427 node.removeEventListener('DOMAttrModified', this, true);
428
429 if (options.characterData)
430 node.removeEventListener('DOMCharacterDataModified', this, true);
431
432 if (options.childList)
433 node.removeEventListener('DOMNodeInserted', this, true);
434
435 if (options.childList || options.subtree)
436 node.removeEventListener('DOMNodeRemoved', this, true);
437 },
438
439 /**
440 * Adds a transient observer on node. The transient observer gets removed
441 * next time we deliver the change records.
442 * @param {Node} node
443 */
444 addTransientObserver: function(node) {
445 // Don't add transient observers on the target itself. We already have all
446 // the required listeners set up on the target.
447 if (node === this.target)
448 return;
449
450 this.addListeners_(node);
451 this.transientObservedNodes.push(node);
452 var registrations = registrationsTable.get(node);
453 if (!registrations)
454 registrationsTable.set(node, registrations = []);
455
456 // We know that registrations does not contain this because we already
457 // checked if node === this.target.
458 registrations.push(this);
459 },
460
461 removeTransientObservers: function() {
462 var transientObservedNodes = this.transientObservedNodes;
463 this.transientObservedNodes = [];
464
465 transientObservedNodes.forEach(function(node) {
466 // Transient observers are never added to the target.
467 this.removeListeners_(node);
468
469 var registrations = registrationsTable.get(node);
470 for (var i = 0; i < registrations.length; i++) {
471 if (registrations[i] === this) {
472 registrations.splice(i, 1);
473 // Each node can only have one registered observer associated with
474 // this observer.
475 break;
476 }
477 }
478 }, this);
479 },
480
481 handleEvent: function(e) {
482 // Stop propagation since we are managing the propagation manually.
483 // This means that other mutation events on the page will not work
484 // correctly but that is by design.
485 e.stopImmediatePropagation();
486
487 switch (e.type) {
488 case 'DOMAttrModified':
489 // http://dom.spec.whatwg.org/#concept-mo-queue-attributes
490
491 var name = e.attrName;
492 var namespace = e.relatedNode.namespaceURI;
493 var target = e.target;
494
495 // 1.
496 var record = new getRecord('attributes', target);
497 record.attributeName = name;
498 record.attributeNamespace = namespace;
499
500 // 2.
501 var oldValue =
502 e.attrChange === MutationEvent.ADDITION ? null : e.prevValue;
503
504 forEachAncestorAndObserverEnqueueRecord(target, function(options) {
505 // 3.1, 4.2
506 if (!options.attributes)
507 return;
508
509 // 3.2, 4.3
510 if (options.attributeFilter && options.attributeFilter.length &&
511 options.attributeFilter.indexOf(name) === -1 &&
512 options.attributeFilter.indexOf(namespace) === -1) {
513 return;
514 }
515 // 3.3, 4.4
516 if (options.attributeOldValue)
517 return getRecordWithOldValue(oldValue);
518
519 // 3.4, 4.5
520 return record;
521 });
522
523 break;
524
525 case 'DOMCharacterDataModified':
526 // http://dom.spec.whatwg.org/#concept-mo-queue-characterdata
527 var target = e.target;
528
529 // 1.
530 var record = getRecord('characterData', target);
531
532 // 2.
533 var oldValue = e.prevValue;
534
535
536 forEachAncestorAndObserverEnqueueRecord(target, function(options) {
537 // 3.1, 4.2
538 if (!options.characterData)
539 return;
540
541 // 3.2, 4.3
542 if (options.characterDataOldValue)
543 return getRecordWithOldValue(oldValue);
544
545 // 3.3, 4.4
546 return record;
547 });
548
549 break;
550
551 case 'DOMNodeRemoved':
552 this.addTransientObserver(e.target);
553 // Fall through.
554 case 'DOMNodeInserted':
555 // http://dom.spec.whatwg.org/#concept-mo-queue-childlist
556 var target = e.relatedNode;
557 var changedNode = e.target;
558 var addedNodes, removedNodes;
559 if (e.type === 'DOMNodeInserted') {
560 addedNodes = [changedNode];
561 removedNodes = [];
562 } else {
563
564 addedNodes = [];
565 removedNodes = [changedNode];
566 }
567 var previousSibling = changedNode.previousSibling;
568 var nextSibling = changedNode.nextSibling;
569
570 // 1.
571 var record = getRecord('childList', target);
572 record.addedNodes = addedNodes;
573 record.removedNodes = removedNodes;
574 record.previousSibling = previousSibling;
575 record.nextSibling = nextSibling;
576
577 forEachAncestorAndObserverEnqueueRecord(target, function(options) {
578 // 2.1, 3.2
579 if (!options.childList)
580 return;
581
582 // 2.2, 3.3
583 return record;
584 });
585
586 }
587
588 clearRecords();
589 }
590 };
591
592 global.JsMutationObserver = JsMutationObserver;
593
594 if (!global.MutationObserver)
595 global.MutationObserver = JsMutationObserver;
596
597
598 })(this);
599
600 window.CustomElements = window.CustomElements || {flags:{}};
601 (function(scope){
602
603 var logFlags = window.logFlags || {};
604 var IMPORT_LINK_TYPE = window.HTMLImports ? HTMLImports.IMPORT_LINK_TYPE : 'none ';
605
606 // walk the subtree rooted at node, applying 'find(element, data)' function
607 // to each element
608 // if 'find' returns true for 'element', do not search element's subtree
609 function findAll(node, find, data) {
610 var e = node.firstElementChild;
611 if (!e) {
612 e = node.firstChild;
613 while (e && e.nodeType !== Node.ELEMENT_NODE) {
614 e = e.nextSibling;
615 }
616 }
617 while (e) {
618 if (find(e, data) !== true) {
619 findAll(e, find, data);
620 }
621 e = e.nextElementSibling;
622 }
623 return null;
624 }
625
626 // walk all shadowRoots on a given node.
627 function forRoots(node, cb) {
628 var root = node.shadowRoot;
629 while(root) {
630 forSubtree(root, cb);
631 root = root.olderShadowRoot;
632 }
633 }
634
635 // walk the subtree rooted at node, including descent into shadow-roots,
636 // applying 'cb' to each element
637 function forSubtree(node, cb) {
638 //logFlags.dom && node.childNodes && node.childNodes.length && console.group(' subTree: ', node);
639 findAll(node, function(e) {
640 if (cb(e)) {
641 return true;
642 }
643 forRoots(e, cb);
644 });
645 forRoots(node, cb);
646 //logFlags.dom && node.childNodes && node.childNodes.length && console.groupEn d();
647 }
648
649 // manage lifecycle on added node
650 function added(node) {
651 if (upgrade(node)) {
652 insertedNode(node);
653 return true;
654 }
655 inserted(node);
656 }
657
658 // manage lifecycle on added node's subtree only
659 function addedSubtree(node) {
660 forSubtree(node, function(e) {
661 if (added(e)) {
662 return true;
663 }
664 });
665 }
666
667 // manage lifecycle on added node and it's subtree
668 function addedNode(node) {
669 return added(node) || addedSubtree(node);
670 }
671
672 // upgrade custom elements at node, if applicable
673 function upgrade(node) {
674 if (!node.__upgraded__ && node.nodeType === Node.ELEMENT_NODE) {
675 var type = node.getAttribute('is') || node.localName;
676 var definition = scope.registry[type];
677 if (definition) {
678 logFlags.dom && console.group('upgrade:', node.localName);
679 scope.upgrade(node);
680 logFlags.dom && console.groupEnd();
681 return true;
682 }
683 }
684 }
685
686 function insertedNode(node) {
687 inserted(node);
688 if (inDocument(node)) {
689 forSubtree(node, function(e) {
690 inserted(e);
691 });
692 }
693 }
694
695
696 // TODO(sorvell): on platforms without MutationObserver, mutations may not be
697 // reliable and therefore attached/detached are not reliable.
698 // To make these callbacks less likely to fail, we defer all inserts and removes
699 // to give a chance for elements to be inserted into dom.
700 // This ensures attachedCallback fires for elements that are created and
701 // immediately added to dom.
702 var hasPolyfillMutations = (!window.MutationObserver ||
703 (window.MutationObserver === window.JsMutationObserver));
704 scope.hasPolyfillMutations = hasPolyfillMutations;
705
706 var isPendingMutations = false;
707 var pendingMutations = [];
708 function deferMutation(fn) {
709 pendingMutations.push(fn);
710 if (!isPendingMutations) {
711 isPendingMutations = true;
712 var async = (window.Platform && window.Platform.endOfMicrotask) ||
713 setTimeout;
714 async(takeMutations);
715 }
716 }
717
718 function takeMutations() {
719 isPendingMutations = false;
720 var $p = pendingMutations;
721 for (var i=0, l=$p.length, p; (i<l) && (p=$p[i]); i++) {
722 p();
723 }
724 pendingMutations = [];
725 }
726
727 function inserted(element) {
728 if (hasPolyfillMutations) {
729 deferMutation(function() {
730 _inserted(element);
731 });
732 } else {
733 _inserted(element);
734 }
735 }
736
737 // TODO(sjmiles): if there are descents into trees that can never have inDocumen t(*) true, fix this
738 function _inserted(element) {
739 // TODO(sjmiles): it's possible we were inserted and removed in the space
740 // of one microtask, in which case we won't be 'inDocument' here
741 // But there are other cases where we are testing for inserted without
742 // specific knowledge of mutations, and must test 'inDocument' to determine
743 // whether to call inserted
744 // If we can factor these cases into separate code paths we can have
745 // better diagnostics.
746 // TODO(sjmiles): when logging, do work on all custom elements so we can
747 // track behavior even when callbacks not defined
748 //console.log('inserted: ', element.localName);
749 if (element.attachedCallback || element.detachedCallback || (element.__upgrade d__ && logFlags.dom)) {
750 logFlags.dom && console.group('inserted:', element.localName);
751 if (inDocument(element)) {
752 element.__inserted = (element.__inserted || 0) + 1;
753 // if we are in a 'removed' state, bluntly adjust to an 'inserted' state
754 if (element.__inserted < 1) {
755 element.__inserted = 1;
756 }
757 // if we are 'over inserted', squelch the callback
758 if (element.__inserted > 1) {
759 logFlags.dom && console.warn('inserted:', element.localName,
760 'insert/remove count:', element.__inserted)
761 } else if (element.attachedCallback) {
762 logFlags.dom && console.log('inserted:', element.localName);
763 element.attachedCallback();
764 }
765 }
766 logFlags.dom && console.groupEnd();
767 }
768 }
769
770 function removedNode(node) {
771 removed(node);
772 forSubtree(node, function(e) {
773 removed(e);
774 });
775 }
776
777 function removed(element) {
778 if (hasPolyfillMutations) {
779 deferMutation(function() {
780 _removed(element);
781 });
782 } else {
783 _removed(element);
784 }
785 }
786
787 function _removed(element) {
788 // TODO(sjmiles): temporary: do work on all custom elements so we can track
789 // behavior even when callbacks not defined
790 if (element.attachedCallback || element.detachedCallback || (element.__upgrade d__ && logFlags.dom)) {
791 logFlags.dom && console.group('removed:', element.localName);
792 if (!inDocument(element)) {
793 element.__inserted = (element.__inserted || 0) - 1;
794 // if we are in a 'inserted' state, bluntly adjust to an 'removed' state
795 if (element.__inserted > 0) {
796 element.__inserted = 0;
797 }
798 // if we are 'over removed', squelch the callback
799 if (element.__inserted < 0) {
800 logFlags.dom && console.warn('removed:', element.localName,
801 'insert/remove count:', element.__inserted)
802 } else if (element.detachedCallback) {
803 element.detachedCallback();
804 }
805 }
806 logFlags.dom && console.groupEnd();
807 }
808 }
809
810 // SD polyfill intrustion due mainly to the fact that 'document'
811 // is not entirely wrapped
812 function wrapIfNeeded(node) {
813 return window.ShadowDOMPolyfill ? ShadowDOMPolyfill.wrapIfNeeded(node)
814 : node;
815 }
816
817 function inDocument(element) {
818 var p = element;
819 var doc = wrapIfNeeded(document);
820 while (p) {
821 if (p == doc) {
822 return true;
823 }
824 p = p.parentNode || p.host;
825 }
826 }
827
828 function watchShadow(node) {
829 if (node.shadowRoot && !node.shadowRoot.__watched) {
830 logFlags.dom && console.log('watching shadow-root for: ', node.localName);
831 // watch all unwatched roots...
832 var root = node.shadowRoot;
833 while (root) {
834 watchRoot(root);
835 root = root.olderShadowRoot;
836 }
837 }
838 }
839
840 function watchRoot(root) {
841 if (!root.__watched) {
842 observe(root);
843 root.__watched = true;
844 }
845 }
846
847 function handler(mutations) {
848 //
849 if (logFlags.dom) {
850 var mx = mutations[0];
851 if (mx && mx.type === 'childList' && mx.addedNodes) {
852 if (mx.addedNodes) {
853 var d = mx.addedNodes[0];
854 while (d && d !== document && !d.host) {
855 d = d.parentNode;
856 }
857 var u = d && (d.URL || d._URL || (d.host && d.host.localName)) || '';
858 u = u.split('/?').shift().split('/').pop();
859 }
860 }
861 console.group('mutations (%d) [%s]', mutations.length, u || '');
862 }
863 //
864 mutations.forEach(function(mx) {
865 //logFlags.dom && console.group('mutation');
866 if (mx.type === 'childList') {
867 forEach(mx.addedNodes, function(n) {
868 //logFlags.dom && console.log(n.localName);
869 if (!n.localName) {
870 return;
871 }
872 // nodes added may need lifecycle management
873 addedNode(n);
874 });
875 // removed nodes may need lifecycle management
876 forEach(mx.removedNodes, function(n) {
877 //logFlags.dom && console.log(n.localName);
878 if (!n.localName) {
879 return;
880 }
881 removedNode(n);
882 });
883 }
884 //logFlags.dom && console.groupEnd();
885 });
886 logFlags.dom && console.groupEnd();
887 };
888
889 var observer = new MutationObserver(handler);
890
891 function takeRecords() {
892 // TODO(sjmiles): ask Raf why we have to call handler ourselves
893 handler(observer.takeRecords());
894 takeMutations();
895 }
896
897 var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
898
899 function observe(inRoot) {
900 observer.observe(inRoot, {childList: true, subtree: true});
901 }
902
903 function observeDocument(doc) {
904 observe(doc);
905 }
906
907 function upgradeDocument(doc) {
908 logFlags.dom && console.group('upgradeDocument: ', (doc.baseURI).split('/').po p());
909 addedNode(doc);
910 logFlags.dom && console.groupEnd();
911 }
912
913 function upgradeDocumentTree(doc) {
914 doc = wrapIfNeeded(doc);
915 upgradeDocument(doc);
916 //console.log('upgradeDocumentTree: ', (doc.baseURI).split('/').pop());
917 // upgrade contained imported documents
918 var imports = doc.querySelectorAll('link[rel=' + IMPORT_LINK_TYPE + ']');
919 for (var i=0, l=imports.length, n; (i<l) && (n=imports[i]); i++) {
920 if (n.import && n.import.__parsed) {
921 upgradeDocumentTree(n.import);
922 }
923 }
924 }
925
926 // exports
927 scope.IMPORT_LINK_TYPE = IMPORT_LINK_TYPE;
928 scope.watchShadow = watchShadow;
929 scope.upgradeDocumentTree = upgradeDocumentTree;
930 scope.upgradeAll = addedNode;
931 scope.upgradeSubtree = addedSubtree;
932
933 scope.observeDocument = observeDocument;
934 scope.upgradeDocument = upgradeDocument;
935
936 scope.takeRecords = takeRecords;
937
938 })(window.CustomElements);
939
940 /**
941 * Implements `document.register`
942 * @module CustomElements
943 */
944
945 /**
946 * Polyfilled extensions to the `document` object.
947 * @class Document
948 */
949
950 (function(scope) {
951
952 // imports
953
954 if (!scope) {
955 scope = window.CustomElements = {flags:{}};
956 }
957 var flags = scope.flags;
958
959 // native document.registerElement?
960
961 var hasNative = Boolean(document.registerElement);
962 // TODO(sorvell): See https://github.com/Polymer/polymer/issues/399
963 // we'll address this by defaulting to CE polyfill in the presence of the SD
964 // polyfill. This will avoid spamming excess attached/detached callbacks.
965 // If there is a compelling need to run CE native with SD polyfill,
966 // we'll need to fix this issue.
967 var useNative = !flags.register && hasNative && !window.ShadowDOMPolyfill;
968
969 if (useNative) {
970
971 // stub
972 var nop = function() {};
973
974 // exports
975 scope.registry = {};
976 scope.upgradeElement = nop;
977
978 scope.watchShadow = nop;
979 scope.upgrade = nop;
980 scope.upgradeAll = nop;
981 scope.upgradeSubtree = nop;
982 scope.observeDocument = nop;
983 scope.upgradeDocument = nop;
984 scope.upgradeDocumentTree = nop;
985 scope.takeRecords = nop;
986
987 } else {
988
989 /**
990 * Registers a custom tag name with the document.
991 *
992 * When a registered element is created, a `readyCallback` method is called
993 * in the scope of the element. The `readyCallback` method can be specified on
994 * either `options.prototype` or `options.lifecycle` with the latter taking
995 * precedence.
996 *
997 * @method register
998 * @param {String} name The tag name to register. Must include a dash ('-'),
999 * for example 'x-component'.
1000 * @param {Object} options
1001 * @param {String} [options.extends]
1002 * (_off spec_) Tag name of an element to extend (or blank for a new
1003 * element). This parameter is not part of the specification, but instead
1004 * is a hint for the polyfill because the extendee is difficult to infer.
1005 * Remember that the input prototype must chain to the extended element's
1006 * prototype (or HTMLElement.prototype) regardless of the value of
1007 * `extends`.
1008 * @param {Object} options.prototype The prototype to use for the new
1009 * element. The prototype must inherit from HTMLElement.
1010 * @param {Object} [options.lifecycle]
1011 * Callbacks that fire at important phases in the life of the custom
1012 * element.
1013 *
1014 * @example
1015 * FancyButton = document.registerElement("fancy-button", {
1016 * extends: 'button',
1017 * prototype: Object.create(HTMLButtonElement.prototype, {
1018 * readyCallback: {
1019 * value: function() {
1020 * console.log("a fancy-button was created",
1021 * }
1022 * }
1023 * })
1024 * });
1025 * @return {Function} Constructor for the newly registered type.
1026 */
1027 function register(name, options) {
1028 //console.warn('document.registerElement("' + name + '", ', options, ')');
1029 // construct a defintion out of options
1030 // TODO(sjmiles): probably should clone options instead of mutating it
1031 var definition = options || {};
1032 if (!name) {
1033 // TODO(sjmiles): replace with more appropriate error (EricB can probably
1034 // offer guidance)
1035 throw new Error('document.registerElement: first argument `name` must not be empty');
1036 }
1037 if (name.indexOf('-') < 0) {
1038 // TODO(sjmiles): replace with more appropriate error (EricB can probably
1039 // offer guidance)
1040 throw new Error('document.registerElement: first argument (\'name\') must contain a dash (\'-\'). Argument provided was \'' + String(name) + '\'.');
1041 }
1042 // elements may only be registered once
1043 if (getRegisteredDefinition(name)) {
1044 throw new Error('DuplicateDefinitionError: a type with name \'' + String(n ame) + '\' is already registered');
1045 }
1046 // must have a prototype, default to an extension of HTMLElement
1047 // TODO(sjmiles): probably should throw if no prototype, check spec
1048 if (!definition.prototype) {
1049 // TODO(sjmiles): replace with more appropriate error (EricB can probably
1050 // offer guidance)
1051 throw new Error('Options missing required prototype property');
1052 }
1053 // record name
1054 definition.__name = name.toLowerCase();
1055 // ensure a lifecycle object so we don't have to null test it
1056 definition.lifecycle = definition.lifecycle || {};
1057 // build a list of ancestral custom elements (for native base detection)
1058 // TODO(sjmiles): we used to need to store this, but current code only
1059 // uses it in 'resolveTagName': it should probably be inlined
1060 definition.ancestry = ancestry(definition.extends);
1061 // extensions of native specializations of HTMLElement require localName
1062 // to remain native, and use secondary 'is' specifier for extension type
1063 resolveTagName(definition);
1064 // some platforms require modifications to the user-supplied prototype
1065 // chain
1066 resolvePrototypeChain(definition);
1067 // overrides to implement attributeChanged callback
1068 overrideAttributeApi(definition.prototype);
1069 // 7.1.5: Register the DEFINITION with DOCUMENT
1070 registerDefinition(definition.__name, definition);
1071 // 7.1.7. Run custom element constructor generation algorithm with PROTOTYPE
1072 // 7.1.8. Return the output of the previous step.
1073 definition.ctor = generateConstructor(definition);
1074 definition.ctor.prototype = definition.prototype;
1075 // force our .constructor to be our actual constructor
1076 definition.prototype.constructor = definition.ctor;
1077 // if initial parsing is complete
1078 if (scope.ready || scope.performedInitialDocumentUpgrade) {
1079 // upgrade any pre-existing nodes of this type
1080 scope.upgradeDocumentTree(document);
1081 }
1082 return definition.ctor;
1083 }
1084
1085 function ancestry(extnds) {
1086 var extendee = getRegisteredDefinition(extnds);
1087 if (extendee) {
1088 return ancestry(extendee.extends).concat([extendee]);
1089 }
1090 return [];
1091 }
1092
1093 function resolveTagName(definition) {
1094 // if we are explicitly extending something, that thing is our
1095 // baseTag, unless it represents a custom component
1096 var baseTag = definition.extends;
1097 // if our ancestry includes custom components, we only have a
1098 // baseTag if one of them does
1099 for (var i=0, a; (a=definition.ancestry[i]); i++) {
1100 baseTag = a.is && a.tag;
1101 }
1102 // our tag is our baseTag, if it exists, and otherwise just our name
1103 definition.tag = baseTag || definition.__name;
1104 if (baseTag) {
1105 // if there is a base tag, use secondary 'is' specifier
1106 definition.is = definition.__name;
1107 }
1108 }
1109
1110 function resolvePrototypeChain(definition) {
1111 // if we don't support __proto__ we need to locate the native level
1112 // prototype for precise mixing in
1113 if (!Object.__proto__) {
1114 // default prototype
1115 var nativePrototype = HTMLElement.prototype;
1116 // work out prototype when using type-extension
1117 if (definition.is) {
1118 var inst = document.createElement(definition.tag);
1119 nativePrototype = Object.getPrototypeOf(inst);
1120 }
1121 // ensure __proto__ reference is installed at each point on the prototype
1122 // chain.
1123 // NOTE: On platforms without __proto__, a mixin strategy is used instead
1124 // of prototype swizzling. In this case, this generated __proto__ provides
1125 // limited support for prototype traversal.
1126 var proto = definition.prototype, ancestor;
1127 while (proto && (proto !== nativePrototype)) {
1128 var ancestor = Object.getPrototypeOf(proto);
1129 proto.__proto__ = ancestor;
1130 proto = ancestor;
1131 }
1132 }
1133 // cache this in case of mixin
1134 definition.native = nativePrototype;
1135 }
1136
1137 // SECTION 4
1138
1139 function instantiate(definition) {
1140 // 4.a.1. Create a new object that implements PROTOTYPE
1141 // 4.a.2. Let ELEMENT by this new object
1142 //
1143 // the custom element instantiation algorithm must also ensure that the
1144 // output is a valid DOM element with the proper wrapper in place.
1145 //
1146 return upgrade(domCreateElement(definition.tag), definition);
1147 }
1148
1149 function upgrade(element, definition) {
1150 // some definitions specify an 'is' attribute
1151 if (definition.is) {
1152 element.setAttribute('is', definition.is);
1153 }
1154 // remove 'unresolved' attr, which is a standin for :unresolved.
1155 element.removeAttribute('unresolved');
1156 // make 'element' implement definition.prototype
1157 implement(element, definition);
1158 // flag as upgraded
1159 element.__upgraded__ = true;
1160 // lifecycle management
1161 created(element);
1162 // there should never be a shadow root on element at this point
1163 // we require child nodes be upgraded before `created`
1164 scope.upgradeSubtree(element);
1165 // OUTPUT
1166 return element;
1167 }
1168
1169 function implement(element, definition) {
1170 // prototype swizzling is best
1171 if (Object.__proto__) {
1172 element.__proto__ = definition.prototype;
1173 } else {
1174 // where above we can re-acquire inPrototype via
1175 // getPrototypeOf(Element), we cannot do so when
1176 // we use mixin, so we install a magic reference
1177 customMixin(element, definition.prototype, definition.native);
1178 element.__proto__ = definition.prototype;
1179 }
1180 }
1181
1182 function customMixin(inTarget, inSrc, inNative) {
1183 // TODO(sjmiles): 'used' allows us to only copy the 'youngest' version of
1184 // any property. This set should be precalculated. We also need to
1185 // consider this for supporting 'super'.
1186 var used = {};
1187 // start with inSrc
1188 var p = inSrc;
1189 // sometimes the default is HTMLUnknownElement.prototype instead of
1190 // HTMLElement.prototype, so we add a test
1191 // the idea is to avoid mixing in native prototypes, so adding
1192 // the second test is WLOG
1193 while (p !== inNative && p !== HTMLUnknownElement.prototype) {
1194 var keys = Object.getOwnPropertyNames(p);
1195 for (var i=0, k; k=keys[i]; i++) {
1196 if (!used[k]) {
1197 Object.defineProperty(inTarget, k,
1198 Object.getOwnPropertyDescriptor(p, k));
1199 used[k] = 1;
1200 }
1201 }
1202 p = Object.getPrototypeOf(p);
1203 }
1204 }
1205
1206 function created(element) {
1207 // invoke createdCallback
1208 if (element.createdCallback) {
1209 element.createdCallback();
1210 }
1211 }
1212
1213 // attribute watching
1214
1215 function overrideAttributeApi(prototype) {
1216 // overrides to implement callbacks
1217 // TODO(sjmiles): should support access via .attributes NamedNodeMap
1218 // TODO(sjmiles): preserves user defined overrides, if any
1219 if (prototype.setAttribute._polyfilled) {
1220 return;
1221 }
1222 var setAttribute = prototype.setAttribute;
1223 prototype.setAttribute = function(name, value) {
1224 changeAttribute.call(this, name, value, setAttribute);
1225 }
1226 var removeAttribute = prototype.removeAttribute;
1227 prototype.removeAttribute = function(name) {
1228 changeAttribute.call(this, name, null, removeAttribute);
1229 }
1230 prototype.setAttribute._polyfilled = true;
1231 }
1232
1233 // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/
1234 // index.html#dfn-attribute-changed-callback
1235 function changeAttribute(name, value, operation) {
1236 var oldValue = this.getAttribute(name);
1237 operation.apply(this, arguments);
1238 var newValue = this.getAttribute(name);
1239 if (this.attributeChangedCallback
1240 && (newValue !== oldValue)) {
1241 this.attributeChangedCallback(name, oldValue, newValue);
1242 }
1243 }
1244
1245 // element registry (maps tag names to definitions)
1246
1247 var registry = {};
1248
1249 function getRegisteredDefinition(name) {
1250 if (name) {
1251 return registry[name.toLowerCase()];
1252 }
1253 }
1254
1255 function registerDefinition(name, definition) {
1256 if (registry[name]) {
1257 throw new Error('a type with that name is already registered.');
1258 }
1259 registry[name] = definition;
1260 }
1261
1262 function generateConstructor(definition) {
1263 return function() {
1264 return instantiate(definition);
1265 };
1266 }
1267
1268 function createElement(tag, typeExtension) {
1269 // TODO(sjmiles): ignore 'tag' when using 'typeExtension', we could
1270 // error check it, or perhaps there should only ever be one argument
1271 var definition = getRegisteredDefinition(typeExtension || tag);
1272 if (definition) {
1273 if (tag == definition.tag && typeExtension == definition.is) {
1274 return new definition.ctor();
1275 }
1276 // Handle empty string for type extension.
1277 if (!typeExtension && !definition.is) {
1278 return new definition.ctor();
1279 }
1280 }
1281
1282 if (typeExtension) {
1283 var element = createElement(tag);
1284 element.setAttribute('is', typeExtension);
1285 return element;
1286 }
1287 var element = domCreateElement(tag);
1288 // Custom tags should be HTMLElements even if not upgraded.
1289 if (tag.indexOf('-') >= 0) {
1290 implement(element, HTMLElement);
1291 }
1292 return element;
1293 }
1294
1295 function upgradeElement(element) {
1296 if (!element.__upgraded__ && (element.nodeType === Node.ELEMENT_NODE)) {
1297 var is = element.getAttribute('is');
1298 var definition = registry[is || element.localName];
1299 if (definition) {
1300 if (is && definition.tag == element.localName) {
1301 return upgrade(element, definition);
1302 } else if (!is && !definition.extends) {
1303 return upgrade(element, definition);
1304 }
1305 }
1306 }
1307 }
1308
1309 function cloneNode(deep) {
1310 // call original clone
1311 var n = domCloneNode.call(this, deep);
1312 // upgrade the element and subtree
1313 scope.upgradeAll(n);
1314 // return the clone
1315 return n;
1316 }
1317 // capture native createElement before we override it
1318
1319 var domCreateElement = document.createElement.bind(document);
1320
1321 // capture native cloneNode before we override it
1322
1323 var domCloneNode = Node.prototype.cloneNode;
1324
1325 // exports
1326
1327 document.registerElement = register;
1328 document.createElement = createElement; // override
1329 Node.prototype.cloneNode = cloneNode; // override
1330
1331 scope.registry = registry;
1332
1333 /**
1334 * Upgrade an element to a custom element. Upgrading an element
1335 * causes the custom prototype to be applied, an `is` attribute
1336 * to be attached (as needed), and invocation of the `readyCallback`.
1337 * `upgrade` does nothing if the element is already upgraded, or
1338 * if it matches no registered custom tag name.
1339 *
1340 * @method ugprade
1341 * @param {Element} element The element to upgrade.
1342 * @return {Element} The upgraded element.
1343 */
1344 scope.upgrade = upgradeElement;
1345 }
1346
1347 // bc
1348 document.register = document.registerElement;
1349
1350 scope.hasNative = hasNative;
1351 scope.useNative = useNative;
1352
1353 })(window.CustomElements);
1354
1355 (function(scope) {
1356
1357 // import
1358
1359 var IMPORT_LINK_TYPE = scope.IMPORT_LINK_TYPE;
1360
1361 // highlander object for parsing a document tree
1362
1363 var parser = {
1364 selectors: [
1365 'link[rel=' + IMPORT_LINK_TYPE + ']'
1366 ],
1367 map: {
1368 link: 'parseLink'
1369 },
1370 parse: function(inDocument) {
1371 if (!inDocument.__parsed) {
1372 // only parse once
1373 inDocument.__parsed = true;
1374 // all parsable elements in inDocument (depth-first pre-order traversal)
1375 var elts = inDocument.querySelectorAll(parser.selectors);
1376 // for each parsable node type, call the mapped parsing method
1377 forEach(elts, function(e) {
1378 parser[parser.map[e.localName]](e);
1379 });
1380 // upgrade all upgradeable static elements, anything dynamically
1381 // created should be caught by observer
1382 CustomElements.upgradeDocument(inDocument);
1383 // observe document for dom changes
1384 CustomElements.observeDocument(inDocument);
1385 }
1386 },
1387 parseLink: function(linkElt) {
1388 // imports
1389 if (isDocumentLink(linkElt)) {
1390 this.parseImport(linkElt);
1391 }
1392 },
1393 parseImport: function(linkElt) {
1394 if (linkElt.import) {
1395 parser.parse(linkElt.import);
1396 }
1397 }
1398 };
1399
1400 function isDocumentLink(inElt) {
1401 return (inElt.localName === 'link'
1402 && inElt.getAttribute('rel') === IMPORT_LINK_TYPE);
1403 }
1404
1405 var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
1406
1407 // exports
1408
1409 scope.parser = parser;
1410 scope.IMPORT_LINK_TYPE = IMPORT_LINK_TYPE;
1411
1412 })(window.CustomElements);
1413 (function(scope){
1414
1415 // bootstrap parsing
1416 function bootstrap() {
1417 // parse document
1418 CustomElements.parser.parse(document);
1419 // one more pass before register is 'live'
1420 CustomElements.upgradeDocument(document);
1421 CustomElements.performedInitialDocumentUpgrade = true;
1422 // choose async
1423 var async = window.Platform && Platform.endOfMicrotask ?
1424 Platform.endOfMicrotask :
1425 setTimeout;
1426 async(function() {
1427 // set internal 'ready' flag, now document.registerElement will trigger
1428 // synchronous upgrades
1429 CustomElements.ready = true;
1430 // capture blunt profiling data
1431 CustomElements.readyTime = Date.now();
1432 if (window.HTMLImports) {
1433 CustomElements.elapsed = CustomElements.readyTime - HTMLImports.readyTime;
1434 }
1435 // notify the system that we are bootstrapped
1436 document.dispatchEvent(
1437 new CustomEvent('WebComponentsReady', {bubbles: true})
1438 );
1439 });
1440 }
1441
1442 // CustomEvent shim for IE
1443 if (typeof window.CustomEvent !== 'function') {
1444 window.CustomEvent = function(inType) {
1445 var e = document.createEvent('HTMLEvents');
1446 e.initEvent(inType, true, true);
1447 return e;
1448 };
1449 }
1450
1451 // When loading at readyState complete time (or via flag), boot custom elements
1452 // immediately.
1453 // If relevant, HTMLImports must already be loaded.
1454 if (document.readyState === 'complete' || scope.flags.eager) {
1455 bootstrap();
1456 // When loading at readyState interactive time, bootstrap only if HTMLImports
1457 // are not pending. Also avoid IE as the semantics of this state are unreliable.
1458 } else if (document.readyState === 'interactive' && !window.attachEvent &&
1459 (!window.HTMLImports || window.HTMLImports.ready)) {
1460 bootstrap();
1461 // When loading at other readyStates, wait for the appropriate DOM event to
1462 // bootstrap.
1463 } else {
1464 var loadEvent = window.HTMLImports && !HTMLImports.ready ?
1465 'HTMLImportsLoaded' : document.readyState == 'loading' ?
1466 'DOMContentLoaded' : 'load';
1467 window.addEventListener(loadEvent, bootstrap);
1468 }
1469
1470 })(window.CustomElements);
1471
1472 (function() {
1473 // Patch to allow custom element and shadow dom to work together, from:
1474 // https://github.com/Polymer/platform-dev/blob/60ece8c323c5d9325cbfdfd6e8cd180d 4f38a3bc/src/patches-shadowdom-polyfill.js
1475 // include .host reference
1476 if (HTMLElement.prototype.createShadowRoot) {
1477 var originalCreateShadowRoot = HTMLElement.prototype.createShadowRoot;
1478 HTMLElement.prototype.createShadowRoot = function() {
1479 var root = originalCreateShadowRoot.call(this);
1480 root.host = this;
1481 CustomElements.watchShadow(this);
1482 return root;
1483 }
1484 }
1485
1486
1487 // Patch to allow custom elements and shadow dom to work together, from:
1488 // https://github.com/Polymer/platform-dev/blob/2bb9c56d90f9ac19c2e65cdad368668a ff514f14/src/patches-custom-elements.js
1489 if (window.ShadowDOMPolyfill) {
1490
1491 // ensure wrapped inputs for these functions
1492 var fns = ['upgradeAll', 'upgradeSubtree', 'observeDocument',
1493 'upgradeDocument'];
1494
1495 // cache originals
1496 var original = {};
1497 fns.forEach(function(fn) {
1498 original[fn] = CustomElements[fn];
1499 });
1500
1501 // override
1502 fns.forEach(function(fn) {
1503 CustomElements[fn] = function(inNode) {
1504 return original[fn](window.ShadowDOMPolyfill.wrapIfNeeded(inNode));
1505 };
1506 });
1507
1508 }
1509
1510 // Patch to make importNode work.
1511 // https://github.com/Polymer/platform-dev/blob/64a92f273462f04a84abbe2f054294f2 b62dbcd6/src/patches-mdv.js
1512 if (window.CustomElements && !CustomElements.useNative) {
1513 var originalImportNode = Document.prototype.importNode;
1514 Document.prototype.importNode = function(node, deep) {
1515 var imported = originalImportNode.call(this, node, deep);
1516 CustomElements.upgradeAll(imported);
1517 return imported;
1518 }
1519 }
1520
1521 })();
OLDNEW
« no previous file with comments | « pkg/custom_element/REVISION ('k') | pkg/custom_element/lib/custom-elements.min.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698