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

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

Issue 140853005: update custom elements and shadow dom (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
OLDNEW
1 // Copyright (c) 2012 The Polymer Authors. All rights reserved. 1 // Copyright (c) 2012 The Polymer Authors. All rights reserved.
2 // 2 //
3 // Redistribution and use in source and binary forms, with or without 3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are 4 // modification, are permitted provided that the following conditions are
5 // met: 5 // met:
6 // 6 //
7 // * Redistributions of source code must retain the above copyright 7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer. 8 // notice, this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above 9 // * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer 10 // copyright notice, this list of conditions and the following disclaimer
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
49 }, 49 },
50 delete: function(key) { 50 delete: function(key) {
51 this.set(key, undefined); 51 this.set(key, undefined);
52 } 52 }
53 }; 53 };
54 54
55 window.WeakMap = WeakMap; 55 window.WeakMap = WeakMap;
56 })(); 56 })();
57 } 57 }
58 58
59 (function(global) {
blois 2014/01/27 20:20:26 Looks like the MutationObserver polyfill is extern
Jennifer Messerly 2014/01/29 20:52:37 good catch! will fix that in the tests
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 // Provide unprefixed MutationObserver with native or JS implementation
595 if (!global.MutationObserver && global.WebKitMutationObserver)
596 global.MutationObserver = global.WebKitMutationObserver;
597
598 if (!global.MutationObserver)
599 global.MutationObserver = JsMutationObserver;
600
601
602 })(this);
603
604 window.CustomElements = window.CustomElements || {flags:{}}; 59 window.CustomElements = window.CustomElements || {flags:{}};
605 (function(scope){ 60 (function(scope){
606 61
607 var logFlags = window.logFlags || {}; 62 var logFlags = window.logFlags || {};
63 var IMPORT_LINK_TYPE = window.HTMLImports ? HTMLImports.IMPORT_LINK_TYPE : 'none ';
608 64
609 // walk the subtree rooted at node, applying 'find(element, data)' function 65 // walk the subtree rooted at node, applying 'find(element, data)' function
610 // to each element 66 // to each element
611 // if 'find' returns true for 'element', do not search element's subtree 67 // if 'find' returns true for 'element', do not search element's subtree
612 function findAll(node, find, data) { 68 function findAll(node, find, data) {
613 var e = node.firstElementChild; 69 var e = node.firstElementChild;
614 if (!e) { 70 if (!e) {
615 e = node.firstChild; 71 e = node.firstChild;
616 while (e && e.nodeType !== Node.ELEMENT_NODE) { 72 while (e && e.nodeType !== Node.ELEMENT_NODE) {
617 e = e.nextSibling; 73 e = e.nextSibling;
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
689 function insertedNode(node) { 145 function insertedNode(node) {
690 inserted(node); 146 inserted(node);
691 if (inDocument(node)) { 147 if (inDocument(node)) {
692 forSubtree(node, function(e) { 148 forSubtree(node, function(e) {
693 inserted(e); 149 inserted(e);
694 }); 150 });
695 } 151 }
696 } 152 }
697 153
698 154
699 // TODO(sorvell): on platforms without MutationObserver, mutations may not be 155 // TODO(sorvell): on platforms without MutationObserver, mutations may not be
700 // reliable and therefore entered/leftView are not reliable. 156 // reliable and therefore attached/detached are not reliable.
701 // To make these callbacks less likely to fail, we defer all inserts and removes 157 // To make these callbacks less likely to fail, we defer all inserts and removes
702 // to give a chance for elements to be inserted into dom. 158 // to give a chance for elements to be inserted into dom.
703 // This ensures enteredViewCallback fires for elements that are created and 159 // This ensures attachedCallback fires for elements that are created and
704 // immediately added to dom. 160 // immediately added to dom.
705 var hasPolyfillMutations = (!window.MutationObserver || 161 var hasPolyfillMutations = (!window.MutationObserver ||
706 (window.MutationObserver === window.JsMutationObserver)); 162 (window.MutationObserver === window.JsMutationObserver));
707 scope.hasPolyfillMutations = hasPolyfillMutations; 163 scope.hasPolyfillMutations = hasPolyfillMutations;
708 164
709 var isPendingMutations = false; 165 var isPendingMutations = false;
710 var pendingMutations = []; 166 var pendingMutations = [];
711 function deferMutation(fn) { 167 function deferMutation(fn) {
712 pendingMutations.push(fn); 168 pendingMutations.push(fn);
713 if (!isPendingMutations) { 169 if (!isPendingMutations) {
(...skipping 28 matching lines...) Expand all
742 // TODO(sjmiles): it's possible we were inserted and removed in the space 198 // TODO(sjmiles): it's possible we were inserted and removed in the space
743 // of one microtask, in which case we won't be 'inDocument' here 199 // of one microtask, in which case we won't be 'inDocument' here
744 // But there are other cases where we are testing for inserted without 200 // But there are other cases where we are testing for inserted without
745 // specific knowledge of mutations, and must test 'inDocument' to determine 201 // specific knowledge of mutations, and must test 'inDocument' to determine
746 // whether to call inserted 202 // whether to call inserted
747 // If we can factor these cases into separate code paths we can have 203 // If we can factor these cases into separate code paths we can have
748 // better diagnostics. 204 // better diagnostics.
749 // TODO(sjmiles): when logging, do work on all custom elements so we can 205 // TODO(sjmiles): when logging, do work on all custom elements so we can
750 // track behavior even when callbacks not defined 206 // track behavior even when callbacks not defined
751 //console.log('inserted: ', element.localName); 207 //console.log('inserted: ', element.localName);
752 if (element.enteredViewCallback || (element.__upgraded__ && logFlags.dom)) { 208 if (element.attachedCallback || element.detachedCallback || (element.__upgrade d__ && logFlags.dom)) {
753 logFlags.dom && console.group('inserted:', element.localName); 209 logFlags.dom && console.group('inserted:', element.localName);
754 if (inDocument(element)) { 210 if (inDocument(element)) {
755 element.__inserted = (element.__inserted || 0) + 1; 211 element.__inserted = (element.__inserted || 0) + 1;
756 // if we are in a 'removed' state, bluntly adjust to an 'inserted' state 212 // if we are in a 'removed' state, bluntly adjust to an 'inserted' state
757 if (element.__inserted < 1) { 213 if (element.__inserted < 1) {
758 element.__inserted = 1; 214 element.__inserted = 1;
759 } 215 }
760 // if we are 'over inserted', squelch the callback 216 // if we are 'over inserted', squelch the callback
761 if (element.__inserted > 1) { 217 if (element.__inserted > 1) {
762 logFlags.dom && console.warn('inserted:', element.localName, 218 logFlags.dom && console.warn('inserted:', element.localName,
763 'insert/remove count:', element.__inserted) 219 'insert/remove count:', element.__inserted)
764 } else if (element.enteredViewCallback) { 220 } else if (element.attachedCallback) {
765 logFlags.dom && console.log('inserted:', element.localName); 221 logFlags.dom && console.log('inserted:', element.localName);
766 element.enteredViewCallback(); 222 element.attachedCallback();
767 } 223 }
768 } 224 }
769 logFlags.dom && console.groupEnd(); 225 logFlags.dom && console.groupEnd();
770 } 226 }
771 } 227 }
772 228
773 function removedNode(node) { 229 function removedNode(node) {
774 removed(node); 230 removed(node);
775 forSubtree(node, function(e) { 231 forSubtree(node, function(e) {
776 removed(e); 232 removed(e);
777 }); 233 });
778 } 234 }
779 235
780 function removed(element) { 236 function removed(element) {
781 if (hasPolyfillMutations) { 237 if (hasPolyfillMutations) {
782 deferMutation(function() { 238 deferMutation(function() {
783 _removed(element); 239 _removed(element);
784 }); 240 });
785 } else { 241 } else {
786 _removed(element); 242 _removed(element);
787 } 243 }
788 } 244 }
789 245
790 function _removed(element) { 246 function _removed(element) {
791 // TODO(sjmiles): temporary: do work on all custom elements so we can track 247 // TODO(sjmiles): temporary: do work on all custom elements so we can track
792 // behavior even when callbacks not defined 248 // behavior even when callbacks not defined
793 if (element.leftViewCallback || (element.__upgraded__ && logFlags.dom)) { 249 if (element.attachedCallback || element.detachedCallback || (element.__upgrade d__ && logFlags.dom)) {
794 logFlags.dom && console.log('removed:', element.localName); 250 logFlags.dom && console.group('removed:', element.localName);
795 if (!inDocument(element)) { 251 if (!inDocument(element)) {
796 element.__inserted = (element.__inserted || 0) - 1; 252 element.__inserted = (element.__inserted || 0) - 1;
797 // if we are in a 'inserted' state, bluntly adjust to an 'removed' state 253 // if we are in a 'inserted' state, bluntly adjust to an 'removed' state
798 if (element.__inserted > 0) { 254 if (element.__inserted > 0) {
799 element.__inserted = 0; 255 element.__inserted = 0;
800 } 256 }
801 // if we are 'over removed', squelch the callback 257 // if we are 'over removed', squelch the callback
802 if (element.__inserted < 0) { 258 if (element.__inserted < 0) {
803 logFlags.dom && console.warn('removed:', element.localName, 259 logFlags.dom && console.warn('removed:', element.localName,
804 'insert/remove count:', element.__inserted) 260 'insert/remove count:', element.__inserted)
805 } else if (element.leftViewCallback) { 261 } else if (element.detachedCallback) {
806 element.leftViewCallback(); 262 element.detachedCallback();
807 } 263 }
808 } 264 }
265 logFlags.dom && console.groupEnd();
809 } 266 }
810 } 267 }
811 268
269 // SD polyfill intrustion due mainly to the fact that 'document'
270 // is not entirely wrapped
271 function wrapIfNeeded(node) {
272 return window.ShadowDOMPolyfill ? ShadowDOMPolyfill.wrapIfNeeded(node)
273 : node;
274 }
275
812 function inDocument(element) { 276 function inDocument(element) {
813 var p = element; 277 var p = element;
814 var doc = window.ShadowDOMPolyfill && 278 var doc = wrapIfNeeded(document);
815 window.ShadowDOMPolyfill.wrapIfNeeded(document) || document;
816 while (p) { 279 while (p) {
817 if (p == doc) { 280 if (p == doc) {
818 return true; 281 return true;
819 } 282 }
820 p = p.parentNode || p.host; 283 p = p.parentNode || p.host;
821 } 284 }
822 } 285 }
823 286
824 function watchShadow(node) { 287 function watchShadow(node) {
825 if (node.shadowRoot && !node.shadowRoot.__watched) { 288 if (node.shadowRoot && !node.shadowRoot.__watched) {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
889 handler(observer.takeRecords()); 352 handler(observer.takeRecords());
890 takeMutations(); 353 takeMutations();
891 } 354 }
892 355
893 var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach); 356 var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
894 357
895 function observe(inRoot) { 358 function observe(inRoot) {
896 observer.observe(inRoot, {childList: true, subtree: true}); 359 observer.observe(inRoot, {childList: true, subtree: true});
897 } 360 }
898 361
899 function observeDocument(document) { 362 function observeDocument(doc) {
900 observe(document); 363 observe(doc);
901 } 364 }
902 365
903 function upgradeDocument(document) { 366 function upgradeDocument(doc) {
904 logFlags.dom && console.group('upgradeDocument: ', (document.URL || document._ URL || '').split('/').pop()); 367 logFlags.dom && console.group('upgradeDocument: ', (doc.baseURI).split('/').po p());
905 addedNode(document); 368 addedNode(doc);
906 logFlags.dom && console.groupEnd(); 369 logFlags.dom && console.groupEnd();
907 } 370 }
908 371
372 function upgradeDocumentTree(doc) {
373 doc = wrapIfNeeded(doc);
374 upgradeDocument(doc);
375 //console.log('upgradeDocumentTree: ', (doc.baseURI).split('/').pop());
376 // upgrade contained imported documents
377 var imports = doc.querySelectorAll('link[rel=' + IMPORT_LINK_TYPE + ']');
378 for (var i=0, l=imports.length, n; (i<l) && (n=imports[i]); i++) {
379 if (n.import && n.import.__parsed) {
380 upgradeDocumentTree(n.import);
381 }
382 }
383 }
384
909 // exports 385 // exports
910 386 scope.IMPORT_LINK_TYPE = IMPORT_LINK_TYPE;
911 scope.watchShadow = watchShadow; 387 scope.watchShadow = watchShadow;
388 scope.upgradeDocumentTree = upgradeDocumentTree;
912 scope.upgradeAll = addedNode; 389 scope.upgradeAll = addedNode;
913 scope.upgradeSubtree = addedSubtree; 390 scope.upgradeSubtree = addedSubtree;
914 391
915 scope.observeDocument = observeDocument; 392 scope.observeDocument = observeDocument;
916 scope.upgradeDocument = upgradeDocument; 393 scope.upgradeDocument = upgradeDocument;
917 394
918 scope.takeRecords = takeRecords; 395 scope.takeRecords = takeRecords;
919 396
920 })(window.CustomElements); 397 })(window.CustomElements);
921 398
922 /** 399 /**
923 * Implements `document.register` 400 * Implements `document.register`
924 * @module CustomElements 401 * @module CustomElements
925 */ 402 */
926 403
927 /** 404 /**
928 * Polyfilled extensions to the `document` object. 405 * Polyfilled extensions to the `document` object.
929 * @class Document 406 * @class Document
930 */ 407 */
931 408
932 (function(scope) { 409 (function(scope) {
933 410
934 // imports 411 // imports
935 412
936 if (!scope) { 413 if (!scope) {
937 scope = window.CustomElements = {flags:{}}; 414 scope = window.CustomElements = {flags:{}};
938 } 415 }
939 var flags = scope.flags; 416 var flags = scope.flags;
940 417
941 // native document.register? 418 // native document.registerElement?
942 419
943 var hasNative = Boolean(document.register); 420 var hasNative = Boolean(document.registerElement);
944 var useNative = !flags.register && hasNative; 421 // TODO(sorvell): See https://github.com/Polymer/polymer/issues/399
422 // we'll address this by defaulting to CE polyfill in the presence of the SD
423 // polyfill. This will avoid spamming excess attached/detached callbacks.
424 // If there is a compelling need to run CE native with SD polyfill,
425 // we'll need to fix this issue.
426 var useNative = !flags.register && hasNative && !window.ShadowDOMPolyfill;
945 427
946 if (useNative) { 428 if (useNative) {
947 429
948 // stub 430 // stub
949 var nop = function() {}; 431 var nop = function() {};
950 432
951 // exports 433 // exports
952 scope.registry = {}; 434 scope.registry = {};
953 scope.upgradeElement = nop; 435 scope.upgradeElement = nop;
954 436
(...skipping 26 matching lines...) Expand all
981 * Remember that the input prototype must chain to the extended element's 463 * Remember that the input prototype must chain to the extended element's
982 * prototype (or HTMLElement.prototype) regardless of the value of 464 * prototype (or HTMLElement.prototype) regardless of the value of
983 * `extends`. 465 * `extends`.
984 * @param {Object} options.prototype The prototype to use for the new 466 * @param {Object} options.prototype The prototype to use for the new
985 * element. The prototype must inherit from HTMLElement. 467 * element. The prototype must inherit from HTMLElement.
986 * @param {Object} [options.lifecycle] 468 * @param {Object} [options.lifecycle]
987 * Callbacks that fire at important phases in the life of the custom 469 * Callbacks that fire at important phases in the life of the custom
988 * element. 470 * element.
989 * 471 *
990 * @example 472 * @example
991 * FancyButton = document.register("fancy-button", { 473 * FancyButton = document.registerElement("fancy-button", {
992 * extends: 'button', 474 * extends: 'button',
993 * prototype: Object.create(HTMLButtonElement.prototype, { 475 * prototype: Object.create(HTMLButtonElement.prototype, {
994 * readyCallback: { 476 * readyCallback: {
995 * value: function() { 477 * value: function() {
996 * console.log("a fancy-button was created", 478 * console.log("a fancy-button was created",
997 * } 479 * }
998 * } 480 * }
999 * }) 481 * })
1000 * }); 482 * });
1001 * @return {Function} Constructor for the newly registered type. 483 * @return {Function} Constructor for the newly registered type.
1002 */ 484 */
1003 function register(name, options) { 485 function register(name, options) {
1004 //console.warn('document.register("' + name + '", ', options, ')'); 486 //console.warn('document.registerElement("' + name + '", ', options, ')');
1005 // construct a defintion out of options 487 // construct a defintion out of options
1006 // TODO(sjmiles): probably should clone options instead of mutating it 488 // TODO(sjmiles): probably should clone options instead of mutating it
1007 var definition = options || {}; 489 var definition = options || {};
1008 if (!name) { 490 if (!name) {
1009 // TODO(sjmiles): replace with more appropriate error (EricB can probably 491 // TODO(sjmiles): replace with more appropriate error (EricB can probably
1010 // offer guidance) 492 // offer guidance)
1011 throw new Error('document.register: first argument `name` must not be empt y'); 493 throw new Error('document.registerElement: first argument `name` must not be empty');
1012 } 494 }
1013 if (name.indexOf('-') < 0) { 495 if (name.indexOf('-') < 0) {
1014 // TODO(sjmiles): replace with more appropriate error (EricB can probably 496 // TODO(sjmiles): replace with more appropriate error (EricB can probably
1015 // offer guidance) 497 // offer guidance)
1016 throw new Error('document.register: first argument (\'name\') must contain a dash (\'-\'). Argument provided was \'' + String(name) + '\'.'); 498 throw new Error('document.registerElement: first argument (\'name\') must contain a dash (\'-\'). Argument provided was \'' + String(name) + '\'.');
1017 } 499 }
1018 // elements may only be registered once 500 // elements may only be registered once
1019 if (getRegisteredDefinition(name)) { 501 if (getRegisteredDefinition(name)) {
1020 throw new Error('DuplicateDefinitionError: a type with name \'' + String(n ame) + '\' is already registered'); 502 throw new Error('DuplicateDefinitionError: a type with name \'' + String(n ame) + '\' is already registered');
1021 } 503 }
1022 // must have a prototype, default to an extension of HTMLElement 504 // must have a prototype, default to an extension of HTMLElement
1023 // TODO(sjmiles): probably should throw if no prototype, check spec 505 // TODO(sjmiles): probably should throw if no prototype, check spec
1024 if (!definition.prototype) { 506 if (!definition.prototype) {
1025 // TODO(sjmiles): replace with more appropriate error (EricB can probably 507 // TODO(sjmiles): replace with more appropriate error (EricB can probably
1026 // offer guidance) 508 // offer guidance)
1027 throw new Error('Options missing required prototype property'); 509 throw new Error('Options missing required prototype property');
1028 } 510 }
1029 // record name 511 // record name
1030 definition.name = name.toLowerCase(); 512 definition.__name = name.toLowerCase();
1031 // ensure a lifecycle object so we don't have to null test it 513 // ensure a lifecycle object so we don't have to null test it
1032 definition.lifecycle = definition.lifecycle || {}; 514 definition.lifecycle = definition.lifecycle || {};
1033 // build a list of ancestral custom elements (for native base detection) 515 // build a list of ancestral custom elements (for native base detection)
1034 // TODO(sjmiles): we used to need to store this, but current code only 516 // TODO(sjmiles): we used to need to store this, but current code only
1035 // uses it in 'resolveTagName': it should probably be inlined 517 // uses it in 'resolveTagName': it should probably be inlined
1036 definition.ancestry = ancestry(definition.extends); 518 definition.ancestry = ancestry(definition.extends);
1037 // extensions of native specializations of HTMLElement require localName 519 // extensions of native specializations of HTMLElement require localName
1038 // to remain native, and use secondary 'is' specifier for extension type 520 // to remain native, and use secondary 'is' specifier for extension type
1039 resolveTagName(definition); 521 resolveTagName(definition);
1040 // some platforms require modifications to the user-supplied prototype 522 // some platforms require modifications to the user-supplied prototype
1041 // chain 523 // chain
1042 resolvePrototypeChain(definition); 524 resolvePrototypeChain(definition);
1043 // overrides to implement attributeChanged callback 525 // overrides to implement attributeChanged callback
1044 overrideAttributeApi(definition.prototype); 526 overrideAttributeApi(definition.prototype);
1045 // 7.1.5: Register the DEFINITION with DOCUMENT 527 // 7.1.5: Register the DEFINITION with DOCUMENT
1046 registerDefinition(definition.name, definition); 528 registerDefinition(definition.__name, definition);
1047 // 7.1.7. Run custom element constructor generation algorithm with PROTOTYPE 529 // 7.1.7. Run custom element constructor generation algorithm with PROTOTYPE
1048 // 7.1.8. Return the output of the previous step. 530 // 7.1.8. Return the output of the previous step.
1049 definition.ctor = generateConstructor(definition); 531 definition.ctor = generateConstructor(definition);
1050 definition.ctor.prototype = definition.prototype; 532 definition.ctor.prototype = definition.prototype;
1051 // force our .constructor to be our actual constructor 533 // force our .constructor to be our actual constructor
1052 definition.prototype.constructor = definition.ctor; 534 definition.prototype.constructor = definition.ctor;
1053 // if initial parsing is complete 535 // if initial parsing is complete
1054 if (scope.ready || scope.performedInitialDocumentUpgrade) { 536 if (scope.ready || scope.performedInitialDocumentUpgrade) {
1055 // upgrade any pre-existing nodes of this type 537 // upgrade any pre-existing nodes of this type
1056 scope.upgradeAll(document); 538 scope.upgradeDocumentTree(document);
1057 } 539 }
1058 return definition.ctor; 540 return definition.ctor;
1059 } 541 }
1060 542
1061 function ancestry(extnds) { 543 function ancestry(extnds) {
1062 var extendee = getRegisteredDefinition(extnds); 544 var extendee = getRegisteredDefinition(extnds);
1063 if (extendee) { 545 if (extendee) {
1064 return ancestry(extendee.extends).concat([extendee]); 546 return ancestry(extendee.extends).concat([extendee]);
1065 } 547 }
1066 return []; 548 return [];
1067 } 549 }
1068 550
1069 function resolveTagName(definition) { 551 function resolveTagName(definition) {
1070 // if we are explicitly extending something, that thing is our 552 // if we are explicitly extending something, that thing is our
1071 // baseTag, unless it represents a custom component 553 // baseTag, unless it represents a custom component
1072 var baseTag = definition.extends; 554 var baseTag = definition.extends;
1073 // if our ancestry includes custom components, we only have a 555 // if our ancestry includes custom components, we only have a
1074 // baseTag if one of them does 556 // baseTag if one of them does
1075 for (var i=0, a; (a=definition.ancestry[i]); i++) { 557 for (var i=0, a; (a=definition.ancestry[i]); i++) {
1076 baseTag = a.is && a.tag; 558 baseTag = a.is && a.tag;
1077 } 559 }
1078 // our tag is our baseTag, if it exists, and otherwise just our name 560 // our tag is our baseTag, if it exists, and otherwise just our name
1079 definition.tag = baseTag || definition.name; 561 definition.tag = baseTag || definition.__name;
1080 if (baseTag) { 562 if (baseTag) {
1081 // if there is a base tag, use secondary 'is' specifier 563 // if there is a base tag, use secondary 'is' specifier
1082 definition.is = definition.name; 564 definition.is = definition.__name;
1083 } 565 }
1084 } 566 }
1085 567
1086 function resolvePrototypeChain(definition) { 568 function resolvePrototypeChain(definition) {
1087 // if we don't support __proto__ we need to locate the native level 569 // if we don't support __proto__ we need to locate the native level
1088 // prototype for precise mixing in 570 // prototype for precise mixing in
1089 if (!Object.__proto__) { 571 if (!Object.__proto__) {
1090 // default prototype 572 // default prototype
1091 var nativePrototype = HTMLElement.prototype; 573 var nativePrototype = HTMLElement.prototype;
1092 // work out prototype when using type-extension 574 // work out prototype when using type-extension
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
1298 // capture native createElement before we override it 780 // capture native createElement before we override it
1299 781
1300 var domCreateElement = document.createElement.bind(document); 782 var domCreateElement = document.createElement.bind(document);
1301 783
1302 // capture native cloneNode before we override it 784 // capture native cloneNode before we override it
1303 785
1304 var domCloneNode = Node.prototype.cloneNode; 786 var domCloneNode = Node.prototype.cloneNode;
1305 787
1306 // exports 788 // exports
1307 789
1308 document.register = register; 790 document.registerElement = register;
1309 document.createElement = createElement; // override 791 document.createElement = createElement; // override
1310 Node.prototype.cloneNode = cloneNode; // override 792 Node.prototype.cloneNode = cloneNode; // override
1311 793
1312 scope.registry = registry; 794 scope.registry = registry;
1313 795
1314 /** 796 /**
1315 * Upgrade an element to a custom element. Upgrading an element 797 * Upgrade an element to a custom element. Upgrading an element
1316 * causes the custom prototype to be applied, an `is` attribute 798 * causes the custom prototype to be applied, an `is` attribute
1317 * to be attached (as needed), and invocation of the `readyCallback`. 799 * to be attached (as needed), and invocation of the `readyCallback`.
1318 * `upgrade` does nothing if the element is already upgraded, or 800 * `upgrade` does nothing if the element is already upgraded, or
1319 * if it matches no registered custom tag name. 801 * if it matches no registered custom tag name.
1320 * 802 *
1321 * @method ugprade 803 * @method ugprade
1322 * @param {Element} element The element to upgrade. 804 * @param {Element} element The element to upgrade.
1323 * @return {Element} The upgraded element. 805 * @return {Element} The upgraded element.
1324 */ 806 */
1325 scope.upgrade = upgradeElement; 807 scope.upgrade = upgradeElement;
1326 } 808 }
1327 809
810 // bc
811 document.register = document.registerElement;
812
1328 scope.hasNative = hasNative; 813 scope.hasNative = hasNative;
1329 scope.useNative = useNative; 814 scope.useNative = useNative;
1330 815
1331 })(window.CustomElements); 816 })(window.CustomElements);
1332 817
1333 (function() { 818 (function(scope) {
1334 819
1335 // import 820 // import
1336 821
1337 var IMPORT_LINK_TYPE = window.HTMLImports ? HTMLImports.IMPORT_LINK_TYPE : 'none '; 822 var IMPORT_LINK_TYPE = scope.IMPORT_LINK_TYPE;
1338 823
1339 // highlander object for parsing a document tree 824 // highlander object for parsing a document tree
1340 825
1341 var parser = { 826 var parser = {
1342 selectors: [ 827 selectors: [
1343 'link[rel=' + IMPORT_LINK_TYPE + ']' 828 'link[rel=' + IMPORT_LINK_TYPE + ']'
1344 ], 829 ],
1345 map: { 830 map: {
1346 link: 'parseLink' 831 link: 'parseLink'
1347 }, 832 },
(...skipping 14 matching lines...) Expand all
1362 CustomElements.observeDocument(inDocument); 847 CustomElements.observeDocument(inDocument);
1363 } 848 }
1364 }, 849 },
1365 parseLink: function(linkElt) { 850 parseLink: function(linkElt) {
1366 // imports 851 // imports
1367 if (isDocumentLink(linkElt)) { 852 if (isDocumentLink(linkElt)) {
1368 this.parseImport(linkElt); 853 this.parseImport(linkElt);
1369 } 854 }
1370 }, 855 },
1371 parseImport: function(linkElt) { 856 parseImport: function(linkElt) {
1372 if (linkElt.content) { 857 if (linkElt.import) {
1373 parser.parse(linkElt.content); 858 parser.parse(linkElt.import);
1374 } 859 }
1375 } 860 }
1376 }; 861 };
1377 862
1378 function isDocumentLink(inElt) { 863 function isDocumentLink(inElt) {
1379 return (inElt.localName === 'link' 864 return (inElt.localName === 'link'
1380 && inElt.getAttribute('rel') === IMPORT_LINK_TYPE); 865 && inElt.getAttribute('rel') === IMPORT_LINK_TYPE);
1381 } 866 }
1382 867
1383 var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach); 868 var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
1384 869
1385 // exports 870 // exports
1386 871
1387 CustomElements.parser = parser; 872 scope.parser = parser;
873 scope.IMPORT_LINK_TYPE = IMPORT_LINK_TYPE;
1388 874
1389 })(); 875 })(window.CustomElements);
1390 (function(scope){ 876 (function(scope){
1391 877
1392 // bootstrap parsing 878 // bootstrap parsing
1393 function bootstrap() { 879 function bootstrap() {
1394 // parse document 880 // parse document
1395 CustomElements.parser.parse(document); 881 CustomElements.parser.parse(document);
1396 // one more pass before register is 'live' 882 // one more pass before register is 'live'
1397 CustomElements.upgradeDocument(document); 883 CustomElements.upgradeDocument(document);
1398 CustomElements.performedInitialDocumentUpgrade = true; 884 CustomElements.performedInitialDocumentUpgrade = true;
1399 // choose async 885 // choose async
1400 var async = window.Platform && Platform.endOfMicrotask ? 886 var async = window.Platform && Platform.endOfMicrotask ?
1401 Platform.endOfMicrotask : 887 Platform.endOfMicrotask :
1402 setTimeout; 888 setTimeout;
1403 async(function() { 889 async(function() {
1404 // set internal 'ready' flag, now document.register will trigger 890 // set internal 'ready' flag, now document.registerElement will trigger
1405 // synchronous upgrades 891 // synchronous upgrades
1406 CustomElements.ready = true; 892 CustomElements.ready = true;
1407 // capture blunt profiling data 893 // capture blunt profiling data
1408 CustomElements.readyTime = Date.now(); 894 CustomElements.readyTime = Date.now();
1409 if (window.HTMLImports) { 895 if (window.HTMLImports) {
1410 CustomElements.elapsed = CustomElements.readyTime - HTMLImports.readyTime; 896 CustomElements.elapsed = CustomElements.readyTime - HTMLImports.readyTime;
1411 } 897 }
1412 // notify the system that we are bootstrapped 898 // notify the system that we are bootstrapped
1413 document.body.dispatchEvent( 899 document.dispatchEvent(
1414 new CustomEvent('WebComponentsReady', {bubbles: true}) 900 new CustomEvent('WebComponentsReady', {bubbles: true})
1415 ); 901 );
1416 }); 902 });
1417 } 903 }
1418 904
1419 // CustomEvent shim for IE 905 // CustomEvent shim for IE
1420 if (typeof window.CustomEvent !== 'function') { 906 if (typeof window.CustomEvent !== 'function') {
1421 window.CustomEvent = function(inType) { 907 window.CustomEvent = function(inType) {
1422 var e = document.createEvent('HTMLEvents'); 908 var e = document.createEvent('HTMLEvents');
1423 e.initEvent(inType, true, true); 909 e.initEvent(inType, true, true);
1424 return e; 910 return e;
1425 }; 911 };
1426 } 912 }
1427 913
1428 // When loading at readyState complete time (or via flag), boot custom elements 914 // When loading at readyState complete time (or via flag), boot custom elements
1429 // immediately. 915 // immediately.
1430 // If relevant, HTMLImports must already be loaded. 916 // If relevant, HTMLImports must already be loaded.
1431 if (document.readyState === 'complete' || scope.flags.eager) { 917 if (document.readyState === 'complete' || scope.flags.eager) {
1432 bootstrap(); 918 bootstrap();
1433 // When loading at readyState interactive time, bootstrap only if HTMLImports 919 // When loading at readyState interactive time, bootstrap only if HTMLImports
1434 // are not pending. Also avoid IE as the semantics of this state are unreliable. 920 // are not pending. Also avoid IE as the semantics of this state are unreliable.
1435 } else if (document.readyState === 'interactive' && !window.attachEvent && 921 } else if (document.readyState === 'interactive' && !window.attachEvent &&
1436 (!window.HTMLImports || window.HTMLImports.ready)) { 922 (!window.HTMLImports || window.HTMLImports.ready)) {
1437 bootstrap(); 923 bootstrap();
1438 // When loading at other readyStates, wait for the appropriate DOM event to 924 // When loading at other readyStates, wait for the appropriate DOM event to
1439 // bootstrap. 925 // bootstrap.
1440 } else { 926 } else {
1441 var loadEvent = window.HTMLImports ? 'HTMLImportsLoaded' : 927 var loadEvent = window.HTMLImports && !HTMLImports.ready
1442 document.readyState == 'loading' ? 'DOMContentLoaded' : 'load'; 928 ? 'HTMLImportsLoaded'
929 : document.readyState == 'loading' ? 'DOMContentLoaded' : 'load';
1443 window.addEventListener(loadEvent, bootstrap); 930 window.addEventListener(loadEvent, bootstrap);
1444 } 931 }
1445 932
1446 })(window.CustomElements); 933 })(window.CustomElements);
1447 934
1448 (function() { 935 (function() {
1449 // Patch to allow custom element and shadow dom to work together, from: 936 // Patch to allow custom element and shadow dom to work together, from:
1450 // https://github.com/Polymer/platform-dev/blob/60ece8c323c5d9325cbfdfd6e8cd180d 4f38a3bc/src/patches-shadowdom-polyfill.js 937 // https://github.com/Polymer/platform-dev/blob/60ece8c323c5d9325cbfdfd6e8cd180d 4f38a3bc/src/patches-shadowdom-polyfill.js
1451 // include .host reference 938 // include .host reference
1452 if (HTMLElement.prototype.createShadowRoot) { 939 if (HTMLElement.prototype.createShadowRoot) {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1488 if (window.CustomElements && !CustomElements.useNative) { 975 if (window.CustomElements && !CustomElements.useNative) {
1489 var originalImportNode = Document.prototype.importNode; 976 var originalImportNode = Document.prototype.importNode;
1490 Document.prototype.importNode = function(node, deep) { 977 Document.prototype.importNode = function(node, deep) {
1491 var imported = originalImportNode.call(this, node, deep); 978 var imported = originalImportNode.call(this, node, deep);
1492 CustomElements.upgradeAll(imported); 979 CustomElements.upgradeAll(imported);
1493 return imported; 980 return imported;
1494 } 981 }
1495 } 982 }
1496 983
1497 })(); 984 })();
OLDNEW
« no previous file with comments | « no previous file | pkg/custom_element/lib/custom-elements.min.js » ('j') | pkg/unittest/lib/html_config.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698