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

Side by Side Diff: pkg/shadow_dom/lib/shadow_dom.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/shadow_dom/REVISIONS ('k') | pkg/shadow_dom/lib/shadow_dom.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 if (!HTMLElement.prototype.createShadowRoot
2 || window.__forceShadowDomPolyfill) {
3
4 /*
5 * Copyright 2013 The Polymer Authors. All rights reserved.
6 * Use of this source code is governed by a BSD-style
7 * license that can be found in the LICENSE file.
8 */
9 (function() {
10 // TODO(jmesserly): fix dart:html to use unprefixed name
11 if (Element.prototype.webkitCreateShadowRoot) {
12 Element.prototype.webkitCreateShadowRoot = function() {
13 return window.ShadowDOMPolyfill.wrapIfNeeded(this).createShadowRoot();
14 };
15 }
16 })();
17
18 // Copyright 2012 Google Inc.
19 //
20 // Licensed under the Apache License, Version 2.0 (the "License");
21 // you may not use this file except in compliance with the License.
22 // You may obtain a copy of the License at
23 //
24 // http://www.apache.org/licenses/LICENSE-2.0
25 //
26 // Unless required by applicable law or agreed to in writing, software
27 // distributed under the License is distributed on an "AS IS" BASIS,
28 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29 // See the License for the specific language governing permissions and
30 // limitations under the License.
31
32 (function(global) {
33 'use strict';
34
35 var PROP_ADD_TYPE = 'add';
36 var PROP_UPDATE_TYPE = 'update';
37 var PROP_RECONFIGURE_TYPE = 'reconfigure';
38 var PROP_DELETE_TYPE = 'delete';
39 var ARRAY_SPLICE_TYPE = 'splice';
40
41 // Detect and do basic sanity checking on Object/Array.observe.
42 function detectObjectObserve() {
43 if (typeof Object.observe !== 'function' ||
44 typeof Array.observe !== 'function') {
45 return false;
46 }
47
48 var records = [];
49
50 function callback(recs) {
51 records = recs;
52 }
53
54 var test = {};
55 Object.observe(test, callback);
56 test.id = 1;
57 test.id = 2;
58 delete test.id;
59 Object.deliverChangeRecords(callback);
60 if (records.length !== 3)
61 return false;
62
63 // TODO(rafaelw): Remove this when new change record type names make it to
64 // chrome release.
65 if (records[0].type == 'new' &&
66 records[1].type == 'updated' &&
67 records[2].type == 'deleted') {
68 PROP_ADD_TYPE = 'new';
69 PROP_UPDATE_TYPE = 'updated';
70 PROP_RECONFIGURE_TYPE = 'reconfigured';
71 PROP_DELETE_TYPE = 'deleted';
72 } else if (records[0].type != 'add' ||
73 records[1].type != 'update' ||
74 records[2].type != 'delete') {
75 console.error('Unexpected change record names for Object.observe. ' +
76 'Using dirty-checking instead');
77 return false;
78 }
79 Object.unobserve(test, callback);
80
81 test = [0];
82 Array.observe(test, callback);
83 test[1] = 1;
84 test.length = 0;
85 Object.deliverChangeRecords(callback);
86 if (records.length != 2)
87 return false;
88 if (records[0].type != ARRAY_SPLICE_TYPE ||
89 records[1].type != ARRAY_SPLICE_TYPE) {
90 return false;
91 }
92 Array.unobserve(test, callback);
93
94 return true;
95 }
96
97 var hasObserve = detectObjectObserve();
98
99 function detectEval() {
100 // don't test for eval if document has CSP securityPolicy object and we can see that
101 // eval is not supported. This avoids an error message in console even when the exception
102 // is caught
103 if (global.document &&
104 'securityPolicy' in global.document &&
105 !global.document.securityPolicy.allowsEval) {
106 return false;
107 }
108
109 try {
110 var f = new Function('', 'return true;');
111 return f();
112 } catch (ex) {
113 return false;
114 }
115 }
116
117 var hasEval = detectEval();
118
119 function isIndex(s) {
120 return +s === s >>> 0;
121 }
122
123 function toNumber(s) {
124 return +s;
125 }
126
127 function isObject(obj) {
128 return obj === Object(obj);
129 }
130
131 var numberIsNaN = global.Number.isNaN || function isNaN(value) {
132 return typeof value === 'number' && global.isNaN(value);
133 }
134
135 function areSameValue(left, right) {
136 if (left === right)
137 return left !== 0 || 1 / left === 1 / right;
138 if (numberIsNaN(left) && numberIsNaN(right))
139 return true;
140
141 return left !== left && right !== right;
142 }
143
144 var createObject = ('__proto__' in {}) ?
145 function(obj) { return obj; } :
146 function(obj) {
147 var proto = obj.__proto__;
148 if (!proto)
149 return obj;
150 var newObject = Object.create(proto);
151 Object.getOwnPropertyNames(obj).forEach(function(name) {
152 Object.defineProperty(newObject, name,
153 Object.getOwnPropertyDescriptor(obj, name));
154 });
155 return newObject;
156 };
157
158 var identStart = '[\$_a-zA-Z]';
159 var identPart = '[\$_a-zA-Z0-9]';
160 var ident = identStart + '+' + identPart + '*';
161 var elementIndex = '(?:[0-9]|[1-9]+[0-9]+)';
162 var identOrElementIndex = '(?:' + ident + '|' + elementIndex + ')';
163 var path = '(?:' + identOrElementIndex + ')(?:\\s*\\.\\s*' + identOrElementInd ex + ')*';
164 var pathRegExp = new RegExp('^' + path + '$');
165
166 function isPathValid(s) {
167 if (typeof s != 'string')
168 return false;
169 s = s.trim();
170
171 if (s == '')
172 return true;
173
174 if (s[0] == '.')
175 return false;
176
177 return pathRegExp.test(s);
178 }
179
180 var constructorIsPrivate = {};
181
182 function Path(s, privateToken) {
183 if (privateToken !== constructorIsPrivate)
184 throw Error('Use Path.get to retrieve path objects');
185
186 if (s.trim() == '')
187 return this;
188
189 if (isIndex(s)) {
190 this.push(s);
191 return this;
192 }
193
194 s.split(/\s*\.\s*/).filter(function(part) {
195 return part;
196 }).forEach(function(part) {
197 this.push(part);
198 }, this);
199
200 if (hasEval && this.length) {
201 this.getValueFrom = this.compiledGetValueFromFn();
202 }
203 }
204
205 // TODO(rafaelw): Make simple LRU cache
206 var pathCache = {};
207
208 function getPath(pathString) {
209 if (pathString instanceof Path)
210 return pathString;
211
212 if (pathString == null)
213 pathString = '';
214
215 if (typeof pathString !== 'string')
216 pathString = String(pathString);
217
218 var path = pathCache[pathString];
219 if (path)
220 return path;
221 if (!isPathValid(pathString))
222 return invalidPath;
223 var path = new Path(pathString, constructorIsPrivate);
224 pathCache[pathString] = path;
225 return path;
226 }
227
228 Path.get = getPath;
229
230 Path.prototype = createObject({
231 __proto__: [],
232 valid: true,
233
234 toString: function() {
235 return this.join('.');
236 },
237
238 getValueFrom: function(obj, directObserver) {
239 for (var i = 0; i < this.length; i++) {
240 if (obj == null)
241 return;
242 obj = obj[this[i]];
243 }
244 return obj;
245 },
246
247 iterateObjects: function(obj, observe) {
248 for (var i = 0; i < this.length; i++) {
249 if (i)
250 obj = obj[this[i - 1]];
251 if (!obj)
252 return;
253 observe(obj);
254 }
255 },
256
257 compiledGetValueFromFn: function() {
258 var accessors = this.map(function(ident) {
259 return isIndex(ident) ? '["' + ident + '"]' : '.' + ident;
260 });
261
262 var str = '';
263 var pathString = 'obj';
264 str += 'if (obj != null';
265 var i = 0;
266 for (; i < (this.length - 1); i++) {
267 var ident = this[i];
268 pathString += accessors[i];
269 str += ' &&\n ' + pathString + ' != null';
270 }
271 str += ')\n';
272
273 pathString += accessors[i];
274
275 str += ' return ' + pathString + ';\nelse\n return undefined;';
276 return new Function('obj', str);
277 },
278
279 setValueFrom: function(obj, value) {
280 if (!this.length)
281 return false;
282
283 for (var i = 0; i < this.length - 1; i++) {
284 if (!isObject(obj))
285 return false;
286 obj = obj[this[i]];
287 }
288
289 if (!isObject(obj))
290 return false;
291
292 obj[this[i]] = value;
293 return true;
294 }
295 });
296
297 var invalidPath = new Path('', constructorIsPrivate);
298 invalidPath.valid = false;
299 invalidPath.getValueFrom = invalidPath.setValueFrom = function() {};
300
301 var MAX_DIRTY_CHECK_CYCLES = 1000;
302
303 function dirtyCheck(observer) {
304 var cycles = 0;
305 while (cycles < MAX_DIRTY_CHECK_CYCLES && observer.check_()) {
306 cycles++;
307 }
308 if (global.testingExposeCycleCount)
309 global.dirtyCheckCycleCount = cycles;
310
311 return cycles > 0;
312 }
313
314 function objectIsEmpty(object) {
315 for (var prop in object)
316 return false;
317 return true;
318 }
319
320 function diffIsEmpty(diff) {
321 return objectIsEmpty(diff.added) &&
322 objectIsEmpty(diff.removed) &&
323 objectIsEmpty(diff.changed);
324 }
325
326 function diffObjectFromOldObject(object, oldObject) {
327 var added = {};
328 var removed = {};
329 var changed = {};
330 var oldObjectHas = {};
331
332 for (var prop in oldObject) {
333 var newValue = object[prop];
334
335 if (newValue !== undefined && newValue === oldObject[prop])
336 continue;
337
338 if (!(prop in object)) {
339 removed[prop] = undefined;
340 continue;
341 }
342
343 if (newValue !== oldObject[prop])
344 changed[prop] = newValue;
345 }
346
347 for (var prop in object) {
348 if (prop in oldObject)
349 continue;
350
351 added[prop] = object[prop];
352 }
353
354 if (Array.isArray(object) && object.length !== oldObject.length)
355 changed.length = object.length;
356
357 return {
358 added: added,
359 removed: removed,
360 changed: changed
361 };
362 }
363
364 var eomTasks = [];
365 function runEOMTasks() {
366 if (!eomTasks.length)
367 return false;
368
369 for (var i = 0; i < eomTasks.length; i++) {
370 eomTasks[i]();
371 }
372 eomTasks.length = 0;
373 return true;
374 }
375
376 var runEOM = hasObserve ? (function(){
377 var eomObj = { pingPong: true };
378 var eomRunScheduled = false;
379
380 Object.observe(eomObj, function() {
381 runEOMTasks();
382 eomRunScheduled = false;
383 });
384
385 return function(fn) {
386 eomTasks.push(fn);
387 if (!eomRunScheduled) {
388 eomRunScheduled = true;
389 eomObj.pingPong = !eomObj.pingPong;
390 }
391 };
392 })() :
393 (function() {
394 return function(fn) {
395 eomTasks.push(fn);
396 };
397 })();
398
399 var observedObjectCache = [];
400
401 function newObservedObject() {
402 var observer;
403 var object;
404 var discardRecords = false;
405 var first = true;
406
407 function callback(records) {
408 if (observer && observer.state_ === OPENED && !discardRecords)
409 observer.check_(records);
410 }
411
412 return {
413 open: function(obs) {
414 if (observer)
415 throw Error('ObservedObject in use');
416
417 if (!first)
418 Object.deliverChangeRecords(callback);
419
420 observer = obs;
421 first = false;
422 },
423 observe: function(obj, arrayObserve) {
424 object = obj;
425 if (arrayObserve)
426 Array.observe(object, callback);
427 else
428 Object.observe(object, callback);
429 },
430 deliver: function(discard) {
431 discardRecords = discard;
432 Object.deliverChangeRecords(callback);
433 discardRecords = false;
434 },
435 close: function() {
436 observer = undefined;
437 Object.unobserve(object, callback);
438 observedObjectCache.push(this);
439 }
440 };
441 }
442
443 function getObservedObject(observer, object, arrayObserve) {
444 var dir = observedObjectCache.pop() || newObservedObject();
445 dir.open(observer);
446 dir.observe(object, arrayObserve);
447 return dir;
448 }
449
450 var emptyArray = [];
451 var observedSetCache = [];
452
453 function newObservedSet() {
454 var observers = [];
455 var observerCount = 0;
456 var objects = [];
457 var toRemove = emptyArray;
458 var resetNeeded = false;
459 var resetScheduled = false;
460
461 function observe(obj) {
462 if (!isObject(obj))
463 return;
464
465 var index = toRemove.indexOf(obj);
466 if (index >= 0) {
467 toRemove[index] = undefined;
468 objects.push(obj);
469 } else if (objects.indexOf(obj) < 0) {
470 objects.push(obj);
471 Object.observe(obj, callback);
472 }
473
474 observe(Object.getPrototypeOf(obj));
475 }
476
477 function reset() {
478 resetScheduled = false;
479 if (!resetNeeded)
480 return;
481
482 var objs = toRemove === emptyArray ? [] : toRemove;
483 toRemove = objects;
484 objects = objs;
485
486 var observer;
487 for (var id in observers) {
488 observer = observers[id];
489 if (!observer || observer.state_ != OPENED)
490 continue;
491
492 observer.iterateObjects_(observe);
493 }
494
495 for (var i = 0; i < toRemove.length; i++) {
496 var obj = toRemove[i];
497 if (obj)
498 Object.unobserve(obj, callback);
499 }
500
501 toRemove.length = 0;
502 }
503
504 function scheduleReset() {
505 if (resetScheduled)
506 return;
507
508 resetNeeded = true;
509 resetScheduled = true;
510 runEOM(reset);
511 }
512
513 function callback() {
514 var observer;
515
516 for (var id in observers) {
517 observer = observers[id];
518 if (!observer || observer.state_ != OPENED)
519 continue;
520
521 observer.check_();
522 }
523
524 scheduleReset();
525 }
526
527 var record = {
528 object: undefined,
529 objects: objects,
530 open: function(obs) {
531 observers[obs.id_] = obs;
532 observerCount++;
533 obs.iterateObjects_(observe);
534 },
535 close: function(obs) {
536 var anyLeft = false;
537
538 observers[obs.id_] = undefined;
539 observerCount--;
540
541 if (observerCount) {
542 scheduleReset();
543 return;
544 }
545 resetNeeded = false;
546
547 for (var i = 0; i < objects.length; i++) {
548 Object.unobserve(objects[i], callback);
549 Observer.unobservedCount++;
550 }
551
552 observers.length = 0;
553 objects.length = 0;
554 observedSetCache.push(this);
555 },
556 reset: scheduleReset
557 };
558
559 return record;
560 }
561
562 var lastObservedSet;
563
564 function getObservedSet(observer, obj) {
565 if (!lastObservedSet || lastObservedSet.object !== obj) {
566 lastObservedSet = observedSetCache.pop() || newObservedSet();
567 lastObservedSet.object = obj;
568 }
569 lastObservedSet.open(observer);
570 return lastObservedSet;
571 }
572
573 var UNOPENED = 0;
574 var OPENED = 1;
575 var CLOSED = 2;
576 var RESETTING = 3;
577
578 var nextObserverId = 1;
579
580 function Observer() {
581 this.state_ = UNOPENED;
582 this.callback_ = undefined;
583 this.target_ = undefined; // TODO(rafaelw): Should be WeakRef
584 this.directObserver_ = undefined;
585 this.value_ = undefined;
586 this.id_ = nextObserverId++;
587 }
588
589 Observer.prototype = {
590 open: function(callback, target) {
591 if (this.state_ != UNOPENED)
592 throw Error('Observer has already been opened.');
593
594 addToAll(this);
595 this.callback_ = callback;
596 this.target_ = target;
597 this.state_ = OPENED;
598 this.connect_();
599 return this.value_;
600 },
601
602 close: function() {
603 if (this.state_ != OPENED)
604 return;
605
606 removeFromAll(this);
607 this.state_ = CLOSED;
608 this.disconnect_();
609 this.value_ = undefined;
610 this.callback_ = undefined;
611 this.target_ = undefined;
612 },
613
614 deliver: function() {
615 if (this.state_ != OPENED)
616 return;
617
618 dirtyCheck(this);
619 },
620
621 report_: function(changes) {
622 try {
623 this.callback_.apply(this.target_, changes);
624 } catch (ex) {
625 Observer._errorThrownDuringCallback = true;
626 console.error('Exception caught during observer callback: ' +
627 (ex.stack || ex));
628 }
629 },
630
631 discardChanges: function() {
632 this.check_(undefined, true);
633 return this.value_;
634 }
635 }
636
637 var collectObservers = !hasObserve;
638 var allObservers;
639 Observer._allObserversCount = 0;
640
641 if (collectObservers) {
642 allObservers = [];
643 }
644
645 function addToAll(observer) {
646 Observer._allObserversCount++;
647 if (!collectObservers)
648 return;
649
650 allObservers.push(observer);
651 }
652
653 function removeFromAll(observer) {
654 Observer._allObserversCount--;
655 }
656
657 var runningMicrotaskCheckpoint = false;
658
659 var hasDebugForceFullDelivery = typeof Object.deliverAllChangeRecords == 'func tion';
660
661 global.Platform = global.Platform || {};
662
663 global.Platform.performMicrotaskCheckpoint = function() {
664 if (runningMicrotaskCheckpoint)
665 return;
666
667 if (hasDebugForceFullDelivery) {
668 Object.deliverAllChangeRecords();
669 return;
670 }
671
672 if (!collectObservers)
673 return;
674
675 runningMicrotaskCheckpoint = true;
676
677 var cycles = 0;
678 var anyChanged, toCheck;
679
680 do {
681 cycles++;
682 toCheck = allObservers;
683 allObservers = [];
684 anyChanged = false;
685
686 for (var i = 0; i < toCheck.length; i++) {
687 var observer = toCheck[i];
688 if (observer.state_ != OPENED)
689 continue;
690
691 if (observer.check_())
692 anyChanged = true;
693
694 allObservers.push(observer);
695 }
696 if (runEOMTasks())
697 anyChanged = true;
698 } while (cycles < MAX_DIRTY_CHECK_CYCLES && anyChanged);
699
700 if (global.testingExposeCycleCount)
701 global.dirtyCheckCycleCount = cycles;
702
703 runningMicrotaskCheckpoint = false;
704 };
705
706 if (collectObservers) {
707 global.Platform.clearObservers = function() {
708 allObservers = [];
709 };
710 }
711
712 function ObjectObserver(object) {
713 Observer.call(this);
714 this.value_ = object;
715 this.oldObject_ = undefined;
716 }
717
718 ObjectObserver.prototype = createObject({
719 __proto__: Observer.prototype,
720
721 arrayObserve: false,
722
723 connect_: function(callback, target) {
724 if (hasObserve) {
725 this.directObserver_ = getObservedObject(this, this.value_,
726 this.arrayObserve);
727 } else {
728 this.oldObject_ = this.copyObject(this.value_);
729 }
730
731 },
732
733 copyObject: function(object) {
734 var copy = Array.isArray(object) ? [] : {};
735 for (var prop in object) {
736 copy[prop] = object[prop];
737 };
738 if (Array.isArray(object))
739 copy.length = object.length;
740 return copy;
741 },
742
743 check_: function(changeRecords, skipChanges) {
744 var diff;
745 var oldValues;
746 if (hasObserve) {
747 if (!changeRecords)
748 return false;
749
750 oldValues = {};
751 diff = diffObjectFromChangeRecords(this.value_, changeRecords,
752 oldValues);
753 } else {
754 oldValues = this.oldObject_;
755 diff = diffObjectFromOldObject(this.value_, this.oldObject_);
756 }
757
758 if (diffIsEmpty(diff))
759 return false;
760
761 if (!hasObserve)
762 this.oldObject_ = this.copyObject(this.value_);
763
764 this.report_([
765 diff.added || {},
766 diff.removed || {},
767 diff.changed || {},
768 function(property) {
769 return oldValues[property];
770 }
771 ]);
772
773 return true;
774 },
775
776 disconnect_: function() {
777 if (hasObserve) {
778 this.directObserver_.close();
779 this.directObserver_ = undefined;
780 } else {
781 this.oldObject_ = undefined;
782 }
783 },
784
785 deliver: function() {
786 if (this.state_ != OPENED)
787 return;
788
789 if (hasObserve)
790 this.directObserver_.deliver(false);
791 else
792 dirtyCheck(this);
793 },
794
795 discardChanges: function() {
796 if (this.directObserver_)
797 this.directObserver_.deliver(true);
798 else
799 this.oldObject_ = this.copyObject(this.value_);
800
801 return this.value_;
802 }
803 });
804
805 function ArrayObserver(array) {
806 if (!Array.isArray(array))
807 throw Error('Provided object is not an Array');
808 ObjectObserver.call(this, array);
809 }
810
811 ArrayObserver.prototype = createObject({
812
813 __proto__: ObjectObserver.prototype,
814
815 arrayObserve: true,
816
817 copyObject: function(arr) {
818 return arr.slice();
819 },
820
821 check_: function(changeRecords) {
822 var splices;
823 if (hasObserve) {
824 if (!changeRecords)
825 return false;
826 splices = projectArraySplices(this.value_, changeRecords);
827 } else {
828 splices = calcSplices(this.value_, 0, this.value_.length,
829 this.oldObject_, 0, this.oldObject_.length);
830 }
831
832 if (!splices || !splices.length)
833 return false;
834
835 if (!hasObserve)
836 this.oldObject_ = this.copyObject(this.value_);
837
838 this.report_([splices]);
839 return true;
840 }
841 });
842
843 ArrayObserver.applySplices = function(previous, current, splices) {
844 splices.forEach(function(splice) {
845 var spliceArgs = [splice.index, splice.removed.length];
846 var addIndex = splice.index;
847 while (addIndex < splice.index + splice.addedCount) {
848 spliceArgs.push(current[addIndex]);
849 addIndex++;
850 }
851
852 Array.prototype.splice.apply(previous, spliceArgs);
853 });
854 };
855
856 function PathObserver(object, path) {
857 Observer.call(this);
858
859 this.object_ = object;
860 this.path_ = path instanceof Path ? path : getPath(path);
861 this.directObserver_ = undefined;
862 }
863
864 PathObserver.prototype = createObject({
865 __proto__: Observer.prototype,
866
867 connect_: function() {
868 if (hasObserve)
869 this.directObserver_ = getObservedSet(this, this.object_);
870
871 this.check_(undefined, true);
872 },
873
874 disconnect_: function() {
875 this.value_ = undefined;
876
877 if (this.directObserver_) {
878 this.directObserver_.close(this);
879 this.directObserver_ = undefined;
880 }
881 },
882
883 iterateObjects_: function(observe) {
884 this.path_.iterateObjects(this.object_, observe);
885 },
886
887 check_: function(changeRecords, skipChanges) {
888 var oldValue = this.value_;
889 this.value_ = this.path_.getValueFrom(this.object_);
890 if (skipChanges || areSameValue(this.value_, oldValue))
891 return false;
892
893 this.report_([this.value_, oldValue]);
894 return true;
895 },
896
897 setValue: function(newValue) {
898 if (this.path_)
899 this.path_.setValueFrom(this.object_, newValue);
900 }
901 });
902
903 function CompoundObserver() {
904 Observer.call(this);
905
906 this.value_ = [];
907 this.directObserver_ = undefined;
908 this.observed_ = [];
909 }
910
911 var observerSentinel = {};
912
913 CompoundObserver.prototype = createObject({
914 __proto__: Observer.prototype,
915
916 connect_: function() {
917 this.check_(undefined, true);
918
919 if (!hasObserve)
920 return;
921
922 var object;
923 var needsDirectObserver = false;
924 for (var i = 0; i < this.observed_.length; i += 2) {
925 object = this.observed_[i]
926 if (object !== observerSentinel) {
927 needsDirectObserver = true;
928 break;
929 }
930 }
931
932 if (this.directObserver_) {
933 if (needsDirectObserver) {
934 this.directObserver_.reset();
935 return;
936 }
937 this.directObserver_.close();
938 this.directObserver_ = undefined;
939 return;
940 }
941
942 if (needsDirectObserver)
943 this.directObserver_ = getObservedSet(this, object);
944 },
945
946 closeObservers_: function() {
947 for (var i = 0; i < this.observed_.length; i += 2) {
948 if (this.observed_[i] === observerSentinel)
949 this.observed_[i + 1].close();
950 }
951 this.observed_.length = 0;
952 },
953
954 disconnect_: function() {
955 this.value_ = undefined;
956
957 if (this.directObserver_) {
958 this.directObserver_.close(this);
959 this.directObserver_ = undefined;
960 }
961
962 this.closeObservers_();
963 },
964
965 addPath: function(object, path) {
966 if (this.state_ != UNOPENED && this.state_ != RESETTING)
967 throw Error('Cannot add paths once started.');
968
969 this.observed_.push(object, path instanceof Path ? path : getPath(path));
970 },
971
972 addObserver: function(observer) {
973 if (this.state_ != UNOPENED && this.state_ != RESETTING)
974 throw Error('Cannot add observers once started.');
975
976 observer.open(this.deliver, this);
977 this.observed_.push(observerSentinel, observer);
978 },
979
980 startReset: function() {
981 if (this.state_ != OPENED)
982 throw Error('Can only reset while open');
983
984 this.state_ = RESETTING;
985 this.closeObservers_();
986 },
987
988 finishReset: function() {
989 if (this.state_ != RESETTING)
990 throw Error('Can only finishReset after startReset');
991 this.state_ = OPENED;
992 this.connect_();
993
994 return this.value_;
995 },
996
997 iterateObjects_: function(observe) {
998 var object;
999 for (var i = 0; i < this.observed_.length; i += 2) {
1000 object = this.observed_[i]
1001 if (object !== observerSentinel)
1002 this.observed_[i + 1].iterateObjects(object, observe)
1003 }
1004 },
1005
1006 check_: function(changeRecords, skipChanges) {
1007 var oldValues;
1008 for (var i = 0; i < this.observed_.length; i += 2) {
1009 var pathOrObserver = this.observed_[i+1];
1010 var object = this.observed_[i];
1011 var value = object === observerSentinel ?
1012 pathOrObserver.discardChanges() :
1013 pathOrObserver.getValueFrom(object)
1014
1015 if (skipChanges) {
1016 this.value_[i / 2] = value;
1017 continue;
1018 }
1019
1020 if (areSameValue(value, this.value_[i / 2]))
1021 continue;
1022
1023 oldValues = oldValues || [];
1024 oldValues[i / 2] = this.value_[i / 2];
1025 this.value_[i / 2] = value;
1026 }
1027
1028 if (!oldValues)
1029 return false;
1030
1031 // TODO(rafaelw): Having observed_ as the third callback arg here is
1032 // pretty lame API. Fix.
1033 this.report_([this.value_, oldValues, this.observed_]);
1034 return true;
1035 }
1036 });
1037
1038 function identFn(value) { return value; }
1039
1040 function ObserverTransform(observable, getValueFn, setValueFn,
1041 dontPassThroughSet) {
1042 this.callback_ = undefined;
1043 this.target_ = undefined;
1044 this.value_ = undefined;
1045 this.observable_ = observable;
1046 this.getValueFn_ = getValueFn || identFn;
1047 this.setValueFn_ = setValueFn || identFn;
1048 // TODO(rafaelw): This is a temporary hack. PolymerExpressions needs this
1049 // at the moment because of a bug in it's dependency tracking.
1050 this.dontPassThroughSet_ = dontPassThroughSet;
1051 }
1052
1053 ObserverTransform.prototype = {
1054 open: function(callback, target) {
1055 this.callback_ = callback;
1056 this.target_ = target;
1057 this.value_ =
1058 this.getValueFn_(this.observable_.open(this.observedCallback_, this));
1059 return this.value_;
1060 },
1061
1062 observedCallback_: function(value) {
1063 value = this.getValueFn_(value);
1064 if (areSameValue(value, this.value_))
1065 return;
1066 var oldValue = this.value_;
1067 this.value_ = value;
1068 this.callback_.call(this.target_, this.value_, oldValue);
1069 },
1070
1071 discardChanges: function() {
1072 this.value_ = this.getValueFn_(this.observable_.discardChanges());
1073 return this.value_;
1074 },
1075
1076 deliver: function() {
1077 return this.observable_.deliver();
1078 },
1079
1080 setValue: function(value) {
1081 value = this.setValueFn_(value);
1082 if (!this.dontPassThroughSet_ && this.observable_.setValue)
1083 return this.observable_.setValue(value);
1084 },
1085
1086 close: function() {
1087 if (this.observable_)
1088 this.observable_.close();
1089 this.callback_ = undefined;
1090 this.target_ = undefined;
1091 this.observable_ = undefined;
1092 this.value_ = undefined;
1093 this.getValueFn_ = undefined;
1094 this.setValueFn_ = undefined;
1095 }
1096 }
1097
1098 var expectedRecordTypes = {};
1099 expectedRecordTypes[PROP_ADD_TYPE] = true;
1100 expectedRecordTypes[PROP_UPDATE_TYPE] = true;
1101 expectedRecordTypes[PROP_DELETE_TYPE] = true;
1102
1103 function notifyFunction(object, name) {
1104 if (typeof Object.observe !== 'function')
1105 return;
1106
1107 var notifier = Object.getNotifier(object);
1108 return function(type, oldValue) {
1109 var changeRecord = {
1110 object: object,
1111 type: type,
1112 name: name
1113 };
1114 if (arguments.length === 2)
1115 changeRecord.oldValue = oldValue;
1116 notifier.notify(changeRecord);
1117 }
1118 }
1119
1120 Observer.defineComputedProperty = function(target, name, observable) {
1121 var notify = notifyFunction(target, name);
1122 var value = observable.open(function(newValue, oldValue) {
1123 value = newValue;
1124 if (notify)
1125 notify(PROP_UPDATE_TYPE, oldValue);
1126 });
1127
1128 Object.defineProperty(target, name, {
1129 get: function() {
1130 observable.deliver();
1131 return value;
1132 },
1133 set: function(newValue) {
1134 observable.setValue(newValue);
1135 return newValue;
1136 },
1137 configurable: true
1138 });
1139
1140 return {
1141 close: function() {
1142 observable.close();
1143 Object.defineProperty(target, name, {
1144 value: value,
1145 writable: true,
1146 configurable: true
1147 });
1148 }
1149 };
1150 }
1151
1152 function diffObjectFromChangeRecords(object, changeRecords, oldValues) {
1153 var added = {};
1154 var removed = {};
1155
1156 for (var i = 0; i < changeRecords.length; i++) {
1157 var record = changeRecords[i];
1158 if (!expectedRecordTypes[record.type]) {
1159 console.error('Unknown changeRecord type: ' + record.type);
1160 console.error(record);
1161 continue;
1162 }
1163
1164 if (!(record.name in oldValues))
1165 oldValues[record.name] = record.oldValue;
1166
1167 if (record.type == PROP_UPDATE_TYPE)
1168 continue;
1169
1170 if (record.type == PROP_ADD_TYPE) {
1171 if (record.name in removed)
1172 delete removed[record.name];
1173 else
1174 added[record.name] = true;
1175
1176 continue;
1177 }
1178
1179 // type = 'delete'
1180 if (record.name in added) {
1181 delete added[record.name];
1182 delete oldValues[record.name];
1183 } else {
1184 removed[record.name] = true;
1185 }
1186 }
1187
1188 for (var prop in added)
1189 added[prop] = object[prop];
1190
1191 for (var prop in removed)
1192 removed[prop] = undefined;
1193
1194 var changed = {};
1195 for (var prop in oldValues) {
1196 if (prop in added || prop in removed)
1197 continue;
1198
1199 var newValue = object[prop];
1200 if (oldValues[prop] !== newValue)
1201 changed[prop] = newValue;
1202 }
1203
1204 return {
1205 added: added,
1206 removed: removed,
1207 changed: changed
1208 };
1209 }
1210
1211 function newSplice(index, removed, addedCount) {
1212 return {
1213 index: index,
1214 removed: removed,
1215 addedCount: addedCount
1216 };
1217 }
1218
1219 var EDIT_LEAVE = 0;
1220 var EDIT_UPDATE = 1;
1221 var EDIT_ADD = 2;
1222 var EDIT_DELETE = 3;
1223
1224 function ArraySplice() {}
1225
1226 ArraySplice.prototype = {
1227
1228 // Note: This function is *based* on the computation of the Levenshtein
1229 // "edit" distance. The one change is that "updates" are treated as two
1230 // edits - not one. With Array splices, an update is really a delete
1231 // followed by an add. By retaining this, we optimize for "keeping" the
1232 // maximum array items in the original array. For example:
1233 //
1234 // 'xxxx123' -> '123yyyy'
1235 //
1236 // With 1-edit updates, the shortest path would be just to update all seven
1237 // characters. With 2-edit updates, we delete 4, leave 3, and add 4. This
1238 // leaves the substring '123' intact.
1239 calcEditDistances: function(current, currentStart, currentEnd,
1240 old, oldStart, oldEnd) {
1241 // "Deletion" columns
1242 var rowCount = oldEnd - oldStart + 1;
1243 var columnCount = currentEnd - currentStart + 1;
1244 var distances = new Array(rowCount);
1245
1246 // "Addition" rows. Initialize null column.
1247 for (var i = 0; i < rowCount; i++) {
1248 distances[i] = new Array(columnCount);
1249 distances[i][0] = i;
1250 }
1251
1252 // Initialize null row
1253 for (var j = 0; j < columnCount; j++)
1254 distances[0][j] = j;
1255
1256 for (var i = 1; i < rowCount; i++) {
1257 for (var j = 1; j < columnCount; j++) {
1258 if (this.equals(current[currentStart + j - 1], old[oldStart + i - 1]))
1259 distances[i][j] = distances[i - 1][j - 1];
1260 else {
1261 var north = distances[i - 1][j] + 1;
1262 var west = distances[i][j - 1] + 1;
1263 distances[i][j] = north < west ? north : west;
1264 }
1265 }
1266 }
1267
1268 return distances;
1269 },
1270
1271 // This starts at the final weight, and walks "backward" by finding
1272 // the minimum previous weight recursively until the origin of the weight
1273 // matrix.
1274 spliceOperationsFromEditDistances: function(distances) {
1275 var i = distances.length - 1;
1276 var j = distances[0].length - 1;
1277 var current = distances[i][j];
1278 var edits = [];
1279 while (i > 0 || j > 0) {
1280 if (i == 0) {
1281 edits.push(EDIT_ADD);
1282 j--;
1283 continue;
1284 }
1285 if (j == 0) {
1286 edits.push(EDIT_DELETE);
1287 i--;
1288 continue;
1289 }
1290 var northWest = distances[i - 1][j - 1];
1291 var west = distances[i - 1][j];
1292 var north = distances[i][j - 1];
1293
1294 var min;
1295 if (west < north)
1296 min = west < northWest ? west : northWest;
1297 else
1298 min = north < northWest ? north : northWest;
1299
1300 if (min == northWest) {
1301 if (northWest == current) {
1302 edits.push(EDIT_LEAVE);
1303 } else {
1304 edits.push(EDIT_UPDATE);
1305 current = northWest;
1306 }
1307 i--;
1308 j--;
1309 } else if (min == west) {
1310 edits.push(EDIT_DELETE);
1311 i--;
1312 current = west;
1313 } else {
1314 edits.push(EDIT_ADD);
1315 j--;
1316 current = north;
1317 }
1318 }
1319
1320 edits.reverse();
1321 return edits;
1322 },
1323
1324 /**
1325 * Splice Projection functions:
1326 *
1327 * A splice map is a representation of how a previous array of items
1328 * was transformed into a new array of items. Conceptually it is a list of
1329 * tuples of
1330 *
1331 * <index, removed, addedCount>
1332 *
1333 * which are kept in ascending index order of. The tuple represents that at
1334 * the |index|, |removed| sequence of items were removed, and counting forwa rd
1335 * from |index|, |addedCount| items were added.
1336 */
1337
1338 /**
1339 * Lacking individual splice mutation information, the minimal set of
1340 * splices can be synthesized given the previous state and final state of an
1341 * array. The basic approach is to calculate the edit distance matrix and
1342 * choose the shortest path through it.
1343 *
1344 * Complexity: O(l * p)
1345 * l: The length of the current array
1346 * p: The length of the old array
1347 */
1348 calcSplices: function(current, currentStart, currentEnd,
1349 old, oldStart, oldEnd) {
1350 var prefixCount = 0;
1351 var suffixCount = 0;
1352
1353 var minLength = Math.min(currentEnd - currentStart, oldEnd - oldStart);
1354 if (currentStart == 0 && oldStart == 0)
1355 prefixCount = this.sharedPrefix(current, old, minLength);
1356
1357 if (currentEnd == current.length && oldEnd == old.length)
1358 suffixCount = this.sharedSuffix(current, old, minLength - prefixCount);
1359
1360 currentStart += prefixCount;
1361 oldStart += prefixCount;
1362 currentEnd -= suffixCount;
1363 oldEnd -= suffixCount;
1364
1365 if (currentEnd - currentStart == 0 && oldEnd - oldStart == 0)
1366 return [];
1367
1368 if (currentStart == currentEnd) {
1369 var splice = newSplice(currentStart, [], 0);
1370 while (oldStart < oldEnd)
1371 splice.removed.push(old[oldStart++]);
1372
1373 return [ splice ];
1374 } else if (oldStart == oldEnd)
1375 return [ newSplice(currentStart, [], currentEnd - currentStart) ];
1376
1377 var ops = this.spliceOperationsFromEditDistances(
1378 this.calcEditDistances(current, currentStart, currentEnd,
1379 old, oldStart, oldEnd));
1380
1381 var splice = undefined;
1382 var splices = [];
1383 var index = currentStart;
1384 var oldIndex = oldStart;
1385 for (var i = 0; i < ops.length; i++) {
1386 switch(ops[i]) {
1387 case EDIT_LEAVE:
1388 if (splice) {
1389 splices.push(splice);
1390 splice = undefined;
1391 }
1392
1393 index++;
1394 oldIndex++;
1395 break;
1396 case EDIT_UPDATE:
1397 if (!splice)
1398 splice = newSplice(index, [], 0);
1399
1400 splice.addedCount++;
1401 index++;
1402
1403 splice.removed.push(old[oldIndex]);
1404 oldIndex++;
1405 break;
1406 case EDIT_ADD:
1407 if (!splice)
1408 splice = newSplice(index, [], 0);
1409
1410 splice.addedCount++;
1411 index++;
1412 break;
1413 case EDIT_DELETE:
1414 if (!splice)
1415 splice = newSplice(index, [], 0);
1416
1417 splice.removed.push(old[oldIndex]);
1418 oldIndex++;
1419 break;
1420 }
1421 }
1422
1423 if (splice) {
1424 splices.push(splice);
1425 }
1426 return splices;
1427 },
1428
1429 sharedPrefix: function(current, old, searchLength) {
1430 for (var i = 0; i < searchLength; i++)
1431 if (!this.equals(current[i], old[i]))
1432 return i;
1433 return searchLength;
1434 },
1435
1436 sharedSuffix: function(current, old, searchLength) {
1437 var index1 = current.length;
1438 var index2 = old.length;
1439 var count = 0;
1440 while (count < searchLength && this.equals(current[--index1], old[--index2 ]))
1441 count++;
1442
1443 return count;
1444 },
1445
1446 calculateSplices: function(current, previous) {
1447 return this.calcSplices(current, 0, current.length, previous, 0,
1448 previous.length);
1449 },
1450
1451 equals: function(currentValue, previousValue) {
1452 return currentValue === previousValue;
1453 }
1454 };
1455
1456 var arraySplice = new ArraySplice();
1457
1458 function calcSplices(current, currentStart, currentEnd,
1459 old, oldStart, oldEnd) {
1460 return arraySplice.calcSplices(current, currentStart, currentEnd,
1461 old, oldStart, oldEnd);
1462 }
1463
1464 function intersect(start1, end1, start2, end2) {
1465 // Disjoint
1466 if (end1 < start2 || end2 < start1)
1467 return -1;
1468
1469 // Adjacent
1470 if (end1 == start2 || end2 == start1)
1471 return 0;
1472
1473 // Non-zero intersect, span1 first
1474 if (start1 < start2) {
1475 if (end1 < end2)
1476 return end1 - start2; // Overlap
1477 else
1478 return end2 - start2; // Contained
1479 } else {
1480 // Non-zero intersect, span2 first
1481 if (end2 < end1)
1482 return end2 - start1; // Overlap
1483 else
1484 return end1 - start1; // Contained
1485 }
1486 }
1487
1488 function mergeSplice(splices, index, removed, addedCount) {
1489
1490 var splice = newSplice(index, removed, addedCount);
1491
1492 var inserted = false;
1493 var insertionOffset = 0;
1494
1495 for (var i = 0; i < splices.length; i++) {
1496 var current = splices[i];
1497 current.index += insertionOffset;
1498
1499 if (inserted)
1500 continue;
1501
1502 var intersectCount = intersect(splice.index,
1503 splice.index + splice.removed.length,
1504 current.index,
1505 current.index + current.addedCount);
1506
1507 if (intersectCount >= 0) {
1508 // Merge the two splices
1509
1510 splices.splice(i, 1);
1511 i--;
1512
1513 insertionOffset -= current.addedCount - current.removed.length;
1514
1515 splice.addedCount += current.addedCount - intersectCount;
1516 var deleteCount = splice.removed.length +
1517 current.removed.length - intersectCount;
1518
1519 if (!splice.addedCount && !deleteCount) {
1520 // merged splice is a noop. discard.
1521 inserted = true;
1522 } else {
1523 var removed = current.removed;
1524
1525 if (splice.index < current.index) {
1526 // some prefix of splice.removed is prepended to current.removed.
1527 var prepend = splice.removed.slice(0, current.index - splice.index);
1528 Array.prototype.push.apply(prepend, removed);
1529 removed = prepend;
1530 }
1531
1532 if (splice.index + splice.removed.length > current.index + current.add edCount) {
1533 // some suffix of splice.removed is appended to current.removed.
1534 var append = splice.removed.slice(current.index + current.addedCount - splice.index);
1535 Array.prototype.push.apply(removed, append);
1536 }
1537
1538 splice.removed = removed;
1539 if (current.index < splice.index) {
1540 splice.index = current.index;
1541 }
1542 }
1543 } else if (splice.index < current.index) {
1544 // Insert splice here.
1545
1546 inserted = true;
1547
1548 splices.splice(i, 0, splice);
1549 i++;
1550
1551 var offset = splice.addedCount - splice.removed.length
1552 current.index += offset;
1553 insertionOffset += offset;
1554 }
1555 }
1556
1557 if (!inserted)
1558 splices.push(splice);
1559 }
1560
1561 function createInitialSplices(array, changeRecords) {
1562 var splices = [];
1563
1564 for (var i = 0; i < changeRecords.length; i++) {
1565 var record = changeRecords[i];
1566 switch(record.type) {
1567 case ARRAY_SPLICE_TYPE:
1568 mergeSplice(splices, record.index, record.removed.slice(), record.adde dCount);
1569 break;
1570 case PROP_ADD_TYPE:
1571 case PROP_UPDATE_TYPE:
1572 case PROP_DELETE_TYPE:
1573 if (!isIndex(record.name))
1574 continue;
1575 var index = toNumber(record.name);
1576 if (index < 0)
1577 continue;
1578 mergeSplice(splices, index, [record.oldValue], 1);
1579 break;
1580 default:
1581 console.error('Unexpected record type: ' + JSON.stringify(record));
1582 break;
1583 }
1584 }
1585
1586 return splices;
1587 }
1588
1589 function projectArraySplices(array, changeRecords) {
1590 var splices = [];
1591
1592 createInitialSplices(array, changeRecords).forEach(function(splice) {
1593 if (splice.addedCount == 1 && splice.removed.length == 1) {
1594 if (splice.removed[0] !== array[splice.index])
1595 splices.push(splice);
1596
1597 return
1598 };
1599
1600 splices = splices.concat(calcSplices(array, splice.index, splice.index + s plice.addedCount,
1601 splice.removed, 0, splice.removed.len gth));
1602 });
1603
1604 return splices;
1605 }
1606
1607 global.Observer = Observer;
1608 global.Observer.runEOM_ = runEOM;
1609 global.Observer.hasObjectObserve = hasObserve;
1610 global.ArrayObserver = ArrayObserver;
1611 global.ArrayObserver.calculateSplices = function(current, previous) {
1612 return arraySplice.calculateSplices(current, previous);
1613 };
1614
1615 global.ArraySplice = ArraySplice;
1616 global.ObjectObserver = ObjectObserver;
1617 global.PathObserver = PathObserver;
1618 global.CompoundObserver = CompoundObserver;
1619 global.Path = Path;
1620 global.ObserverTransform = ObserverTransform;
1621
1622 // TODO(rafaelw): Only needed for testing until new change record names
1623 // make it to release.
1624 global.Observer.changeRecordTypes = {
1625 add: PROP_ADD_TYPE,
1626 update: PROP_UPDATE_TYPE,
1627 reconfigure: PROP_RECONFIGURE_TYPE,
1628 'delete': PROP_DELETE_TYPE,
1629 splice: ARRAY_SPLICE_TYPE
1630 };
1631 })(typeof global !== 'undefined' && global && typeof module !== 'undefined' && m odule ? global : this || window);
1632
1633 /*
1634 * Copyright 2012 The Polymer Authors. All rights reserved.
1635 * Use of this source code is governed by a BSD-style
1636 * license that can be found in the LICENSE file.
1637 */
1638
1639 if (typeof WeakMap === 'undefined') {
1640 (function() {
1641 var defineProperty = Object.defineProperty;
1642 var counter = Date.now() % 1e9;
1643
1644 var WeakMap = function() {
1645 this.name = '__st' + (Math.random() * 1e9 >>> 0) + (counter++ + '__');
1646 };
1647
1648 WeakMap.prototype = {
1649 set: function(key, value) {
1650 var entry = key[this.name];
1651 if (entry && entry[0] === key)
1652 entry[1] = value;
1653 else
1654 defineProperty(key, this.name, {value: [key, value], writable: true});
1655 },
1656 get: function(key) {
1657 var entry;
1658 return (entry = key[this.name]) && entry[0] === key ?
1659 entry[1] : undefined;
1660 },
1661 delete: function(key) {
1662 this.set(key, undefined);
1663 }
1664 };
1665
1666 window.WeakMap = WeakMap;
1667 })();
1668 }
1669
1670 // Copyright 2012 The Polymer Authors. All rights reserved.
1671 // Use of this source code is goverened by a BSD-style
1672 // license that can be found in the LICENSE file.
1673
1674 window.ShadowDOMPolyfill = {};
1675
1676 (function(scope) {
1677 'use strict';
1678
1679 var constructorTable = new WeakMap();
1680 var nativePrototypeTable = new WeakMap();
1681 var wrappers = Object.create(null);
1682
1683 // Don't test for eval if document has CSP securityPolicy object and we can
1684 // see that eval is not supported. This avoids an error message in console
1685 // even when the exception is caught
1686 var hasEval = !('securityPolicy' in document) ||
1687 document.securityPolicy.allowsEval;
1688 if (hasEval) {
1689 try {
1690 var f = new Function('', 'return true;');
1691 hasEval = f();
1692 } catch (ex) {
1693 hasEval = false;
1694 }
1695 }
1696
1697 function assert(b) {
1698 if (!b)
1699 throw new Error('Assertion failed');
1700 };
1701
1702 var defineProperty = Object.defineProperty;
1703 var getOwnPropertyNames = Object.getOwnPropertyNames;
1704 var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
1705
1706 function mixin(to, from) {
1707 getOwnPropertyNames(from).forEach(function(name) {
1708 defineProperty(to, name, getOwnPropertyDescriptor(from, name));
1709 });
1710 return to;
1711 };
1712
1713 function mixinStatics(to, from) {
1714 getOwnPropertyNames(from).forEach(function(name) {
1715 switch (name) {
1716 case 'arguments':
1717 case 'caller':
1718 case 'length':
1719 case 'name':
1720 case 'prototype':
1721 case 'toString':
1722 return;
1723 }
1724 defineProperty(to, name, getOwnPropertyDescriptor(from, name));
1725 });
1726 return to;
1727 };
1728
1729 function oneOf(object, propertyNames) {
1730 for (var i = 0; i < propertyNames.length; i++) {
1731 if (propertyNames[i] in object)
1732 return propertyNames[i];
1733 }
1734 }
1735
1736 // Mozilla's old DOM bindings are bretty busted:
1737 // https://bugzilla.mozilla.org/show_bug.cgi?id=855844
1738 // Make sure they are create before we start modifying things.
1739 getOwnPropertyNames(window);
1740
1741 function getWrapperConstructor(node) {
1742 var nativePrototype = node.__proto__ || Object.getPrototypeOf(node);
1743 var wrapperConstructor = constructorTable.get(nativePrototype);
1744 if (wrapperConstructor)
1745 return wrapperConstructor;
1746
1747 var parentWrapperConstructor = getWrapperConstructor(nativePrototype);
1748
1749 var GeneratedWrapper = createWrapperConstructor(parentWrapperConstructor);
1750 registerInternal(nativePrototype, GeneratedWrapper, node);
1751
1752 return GeneratedWrapper;
1753 }
1754
1755 function addForwardingProperties(nativePrototype, wrapperPrototype) {
1756 installProperty(nativePrototype, wrapperPrototype, true);
1757 }
1758
1759 function registerInstanceProperties(wrapperPrototype, instanceObject) {
1760 installProperty(instanceObject, wrapperPrototype, false);
1761 }
1762
1763 var isFirefox = /Firefox/.test(navigator.userAgent);
1764
1765 // This is used as a fallback when getting the descriptor fails in
1766 // installProperty.
1767 var dummyDescriptor = {
1768 get: function() {},
1769 set: function(v) {},
1770 configurable: true,
1771 enumerable: true
1772 };
1773
1774 function isEventHandlerName(name) {
1775 return /^on[a-z]+$/.test(name);
1776 }
1777
1778 function isIdentifierName(name) {
1779 return /^\w[a-zA-Z_0-9]*$/.test(name);
1780 }
1781
1782 function getGetter(name) {
1783 return hasEval && isIdentifierName(name) ?
1784 new Function('return this.impl.' + name) :
1785 function() { return this.impl[name]; };
1786 }
1787
1788 function getSetter(name) {
1789 return hasEval && isIdentifierName(name) ?
1790 new Function('v', 'this.impl.' + name + ' = v') :
1791 function(v) { this.impl[name] = v; };
1792 }
1793
1794 function getMethod(name) {
1795 return hasEval && isIdentifierName(name) ?
1796 new Function('return this.impl.' + name +
1797 '.apply(this.impl, arguments)') :
1798 function() { return this.impl[name].apply(this.impl, arguments); };
1799 }
1800
1801 function getDescriptor(source, name) {
1802 try {
1803 return Object.getOwnPropertyDescriptor(source, name);
1804 } catch (ex) {
1805 // JSC and V8 both use data properties instead of accessors which can
1806 // cause getting the property desciptor to throw an exception.
1807 // https://bugs.webkit.org/show_bug.cgi?id=49739
1808 return dummyDescriptor;
1809 }
1810 }
1811
1812 function installProperty(source, target, allowMethod, opt_blacklist) {
1813 var names = getOwnPropertyNames(source);
1814 for (var i = 0; i < names.length; i++) {
1815 var name = names[i];
1816 if (name === 'polymerBlackList_')
1817 continue;
1818
1819 if (name in target)
1820 continue;
1821
1822 if (source.polymerBlackList_ && source.polymerBlackList_[name])
1823 continue;
1824
1825 if (isFirefox) {
1826 // Tickle Firefox's old bindings.
1827 source.__lookupGetter__(name);
1828 }
1829 var descriptor = getDescriptor(source, name);
1830 var getter, setter;
1831 if (allowMethod && typeof descriptor.value === 'function') {
1832 target[name] = getMethod(name);
1833 continue;
1834 }
1835
1836 var isEvent = isEventHandlerName(name);
1837 if (isEvent)
1838 getter = scope.getEventHandlerGetter(name);
1839 else
1840 getter = getGetter(name);
1841
1842 if (descriptor.writable || descriptor.set) {
1843 if (isEvent)
1844 setter = scope.getEventHandlerSetter(name);
1845 else
1846 setter = getSetter(name);
1847 }
1848
1849 defineProperty(target, name, {
1850 get: getter,
1851 set: setter,
1852 configurable: descriptor.configurable,
1853 enumerable: descriptor.enumerable
1854 });
1855 }
1856 }
1857
1858 /**
1859 * @param {Function} nativeConstructor
1860 * @param {Function} wrapperConstructor
1861 * @param {Object=} opt_instance If present, this is used to extract
1862 * properties from an instance object.
1863 */
1864 function register(nativeConstructor, wrapperConstructor, opt_instance) {
1865 var nativePrototype = nativeConstructor.prototype;
1866 registerInternal(nativePrototype, wrapperConstructor, opt_instance);
1867 mixinStatics(wrapperConstructor, nativeConstructor);
1868 }
1869
1870 function registerInternal(nativePrototype, wrapperConstructor, opt_instance) {
1871 var wrapperPrototype = wrapperConstructor.prototype;
1872 assert(constructorTable.get(nativePrototype) === undefined);
1873
1874 constructorTable.set(nativePrototype, wrapperConstructor);
1875 nativePrototypeTable.set(wrapperPrototype, nativePrototype);
1876
1877 addForwardingProperties(nativePrototype, wrapperPrototype);
1878 if (opt_instance)
1879 registerInstanceProperties(wrapperPrototype, opt_instance);
1880 defineProperty(wrapperPrototype, 'constructor', {
1881 value: wrapperConstructor,
1882 configurable: true,
1883 enumerable: false,
1884 writable: true
1885 });
1886 }
1887
1888 function isWrapperFor(wrapperConstructor, nativeConstructor) {
1889 return constructorTable.get(nativeConstructor.prototype) ===
1890 wrapperConstructor;
1891 }
1892
1893 /**
1894 * Creates a generic wrapper constructor based on |object| and its
1895 * constructor.
1896 * @param {Node} object
1897 * @return {Function} The generated constructor.
1898 */
1899 function registerObject(object) {
1900 var nativePrototype = Object.getPrototypeOf(object);
1901
1902 var superWrapperConstructor = getWrapperConstructor(nativePrototype);
1903 var GeneratedWrapper = createWrapperConstructor(superWrapperConstructor);
1904 registerInternal(nativePrototype, GeneratedWrapper, object);
1905
1906 return GeneratedWrapper;
1907 }
1908
1909 function createWrapperConstructor(superWrapperConstructor) {
1910 function GeneratedWrapper(node) {
1911 superWrapperConstructor.call(this, node);
1912 }
1913 GeneratedWrapper.prototype =
1914 Object.create(superWrapperConstructor.prototype);
1915 GeneratedWrapper.prototype.constructor = GeneratedWrapper;
1916
1917 return GeneratedWrapper;
1918 }
1919
1920 var OriginalDOMImplementation = window.DOMImplementation;
1921 var OriginalEventTarget = window.EventTarget;
1922 var OriginalEvent = window.Event;
1923 var OriginalNode = window.Node;
1924 var OriginalWindow = window.Window;
1925 var OriginalRange = window.Range;
1926 var OriginalCanvasRenderingContext2D = window.CanvasRenderingContext2D;
1927 var OriginalWebGLRenderingContext = window.WebGLRenderingContext;
1928 var OriginalSVGElementInstance = window.SVGElementInstance;
1929
1930 function isWrapper(object) {
1931 return object instanceof wrappers.EventTarget ||
1932 object instanceof wrappers.Event ||
1933 object instanceof wrappers.Range ||
1934 object instanceof wrappers.DOMImplementation ||
1935 object instanceof wrappers.CanvasRenderingContext2D ||
1936 wrappers.WebGLRenderingContext &&
1937 object instanceof wrappers.WebGLRenderingContext;
1938 }
1939
1940 function isNative(object) {
1941 return OriginalEventTarget && object instanceof OriginalEventTarget ||
1942 object instanceof OriginalNode ||
1943 object instanceof OriginalEvent ||
1944 object instanceof OriginalWindow ||
1945 object instanceof OriginalRange ||
1946 object instanceof OriginalDOMImplementation ||
1947 object instanceof OriginalCanvasRenderingContext2D ||
1948 OriginalWebGLRenderingContext &&
1949 object instanceof OriginalWebGLRenderingContext ||
1950 OriginalSVGElementInstance &&
1951 object instanceof OriginalSVGElementInstance;
1952 }
1953
1954 /**
1955 * Wraps a node in a WrapperNode. If there already exists a wrapper for the
1956 * |node| that wrapper is returned instead.
1957 * @param {Node} node
1958 * @return {WrapperNode}
1959 */
1960 function wrap(impl) {
1961 if (impl === null)
1962 return null;
1963
1964 assert(isNative(impl));
1965 return impl.polymerWrapper_ ||
1966 (impl.polymerWrapper_ = new (getWrapperConstructor(impl))(impl));
1967 }
1968
1969 /**
1970 * Unwraps a wrapper and returns the node it is wrapping.
1971 * @param {WrapperNode} wrapper
1972 * @return {Node}
1973 */
1974 function unwrap(wrapper) {
1975 if (wrapper === null)
1976 return null;
1977 assert(isWrapper(wrapper));
1978 return wrapper.impl;
1979 }
1980
1981 /**
1982 * Unwraps object if it is a wrapper.
1983 * @param {Object} object
1984 * @return {Object} The native implementation object.
1985 */
1986 function unwrapIfNeeded(object) {
1987 return object && isWrapper(object) ? unwrap(object) : object;
1988 }
1989
1990 /**
1991 * Wraps object if it is not a wrapper.
1992 * @param {Object} object
1993 * @return {Object} The wrapper for object.
1994 */
1995 function wrapIfNeeded(object) {
1996 return object && !isWrapper(object) ? wrap(object) : object;
1997 }
1998
1999 /**
2000 * Overrides the current wrapper (if any) for node.
2001 * @param {Node} node
2002 * @param {WrapperNode=} wrapper If left out the wrapper will be created as
2003 * needed next time someone wraps the node.
2004 */
2005 function rewrap(node, wrapper) {
2006 if (wrapper === null)
2007 return;
2008 assert(isNative(node));
2009 assert(wrapper === undefined || isWrapper(wrapper));
2010 node.polymerWrapper_ = wrapper;
2011 }
2012
2013 function defineGetter(constructor, name, getter) {
2014 defineProperty(constructor.prototype, name, {
2015 get: getter,
2016 configurable: true,
2017 enumerable: true
2018 });
2019 }
2020
2021 function defineWrapGetter(constructor, name) {
2022 defineGetter(constructor, name, function() {
2023 return wrap(this.impl[name]);
2024 });
2025 }
2026
2027 /**
2028 * Forwards existing methods on the native object to the wrapper methods.
2029 * This does not wrap any of the arguments or the return value since the
2030 * wrapper implementation already takes care of that.
2031 * @param {Array.<Function>} constructors
2032 * @parem {Array.<string>} names
2033 */
2034 function forwardMethodsToWrapper(constructors, names) {
2035 constructors.forEach(function(constructor) {
2036 names.forEach(function(name) {
2037 constructor.prototype[name] = function() {
2038 var w = wrapIfNeeded(this);
2039 return w[name].apply(w, arguments);
2040 };
2041 });
2042 });
2043 }
2044
2045 scope.assert = assert;
2046 scope.constructorTable = constructorTable;
2047 scope.defineGetter = defineGetter;
2048 scope.defineWrapGetter = defineWrapGetter;
2049 scope.forwardMethodsToWrapper = forwardMethodsToWrapper;
2050 scope.isWrapper = isWrapper;
2051 scope.isWrapperFor = isWrapperFor;
2052 scope.mixin = mixin;
2053 scope.nativePrototypeTable = nativePrototypeTable;
2054 scope.oneOf = oneOf;
2055 scope.registerObject = registerObject;
2056 scope.registerWrapper = register;
2057 scope.rewrap = rewrap;
2058 scope.unwrap = unwrap;
2059 scope.unwrapIfNeeded = unwrapIfNeeded;
2060 scope.wrap = wrap;
2061 scope.wrapIfNeeded = wrapIfNeeded;
2062 scope.wrappers = wrappers;
2063
2064 })(window.ShadowDOMPolyfill);
2065
2066 /*
2067 * Copyright 2013 The Polymer Authors. All rights reserved.
2068 * Use of this source code is goverened by a BSD-style
2069 * license that can be found in the LICENSE file.
2070 */
2071
2072 (function(context) {
2073 'use strict';
2074
2075 var OriginalMutationObserver = window.MutationObserver;
2076 var callbacks = [];
2077 var pending = false;
2078 var timerFunc;
2079
2080 function handle() {
2081 pending = false;
2082 var copies = callbacks.slice(0);
2083 callbacks = [];
2084 for (var i = 0; i < copies.length; i++) {
2085 (0, copies[i])();
2086 }
2087 }
2088
2089 if (OriginalMutationObserver) {
2090 var counter = 1;
2091 var observer = new OriginalMutationObserver(handle);
2092 var textNode = document.createTextNode(counter);
2093 observer.observe(textNode, {characterData: true});
2094
2095 timerFunc = function() {
2096 counter = (counter + 1) % 2;
2097 textNode.data = counter;
2098 };
2099
2100 } else {
2101 timerFunc = window.setImmediate || window.setTimeout;
2102 }
2103
2104 function setEndOfMicrotask(func) {
2105 callbacks.push(func);
2106 if (pending)
2107 return;
2108 pending = true;
2109 timerFunc(handle, 0);
2110 }
2111
2112 context.setEndOfMicrotask = setEndOfMicrotask;
2113
2114 })(window.ShadowDOMPolyfill);
2115
2116 /*
2117 * Copyright 2013 The Polymer Authors. All rights reserved.
2118 * Use of this source code is goverened by a BSD-style
2119 * license that can be found in the LICENSE file.
2120 */
2121
2122 (function(scope) {
2123 'use strict';
2124
2125 var setEndOfMicrotask = scope.setEndOfMicrotask
2126 var wrapIfNeeded = scope.wrapIfNeeded
2127 var wrappers = scope.wrappers;
2128
2129 var registrationsTable = new WeakMap();
2130 var globalMutationObservers = [];
2131 var isScheduled = false;
2132
2133 function scheduleCallback(observer) {
2134 if (isScheduled)
2135 return;
2136 setEndOfMicrotask(notifyObservers);
2137 isScheduled = true;
2138 }
2139
2140 // http://dom.spec.whatwg.org/#mutation-observers
2141 function notifyObservers() {
2142 isScheduled = false;
2143
2144 do {
2145 var notifyList = globalMutationObservers.slice();
2146 var anyNonEmpty = false;
2147 for (var i = 0; i < notifyList.length; i++) {
2148 var mo = notifyList[i];
2149 var queue = mo.takeRecords();
2150 removeTransientObserversFor(mo);
2151 if (queue.length) {
2152 mo.callback_(queue, mo);
2153 anyNonEmpty = true;
2154 }
2155 }
2156 } while (anyNonEmpty);
2157 }
2158
2159 /**
2160 * @param {string} type
2161 * @param {Node} target
2162 * @constructor
2163 */
2164 function MutationRecord(type, target) {
2165 this.type = type;
2166 this.target = target;
2167 this.addedNodes = new wrappers.NodeList();
2168 this.removedNodes = new wrappers.NodeList();
2169 this.previousSibling = null;
2170 this.nextSibling = null;
2171 this.attributeName = null;
2172 this.attributeNamespace = null;
2173 this.oldValue = null;
2174 }
2175
2176 /**
2177 * Registers transient observers to ancestor and its ancesors for the node
2178 * which was removed.
2179 * @param {!Node} ancestor
2180 * @param {!Node} node
2181 */
2182 function registerTransientObservers(ancestor, node) {
2183 for (; ancestor; ancestor = ancestor.parentNode) {
2184 var registrations = registrationsTable.get(ancestor);
2185 if (!registrations)
2186 continue;
2187 for (var i = 0; i < registrations.length; i++) {
2188 var registration = registrations[i];
2189 if (registration.options.subtree)
2190 registration.addTransientObserver(node);
2191 }
2192 }
2193 }
2194
2195 function removeTransientObserversFor(observer) {
2196 for (var i = 0; i < observer.nodes_.length; i++) {
2197 var node = observer.nodes_[i];
2198 var registrations = registrationsTable.get(node);
2199 if (!registrations)
2200 return;
2201 for (var j = 0; j < registrations.length; j++) {
2202 var registration = registrations[j];
2203 if (registration.observer === observer)
2204 registration.removeTransientObservers();
2205 }
2206 }
2207 }
2208
2209 // http://dom.spec.whatwg.org/#queue-a-mutation-record
2210 function enqueueMutation(target, type, data) {
2211 // 1.
2212 var interestedObservers = Object.create(null);
2213 var associatedStrings = Object.create(null);
2214
2215 // 2.
2216 for (var node = target; node; node = node.parentNode) {
2217 // 3.
2218 var registrations = registrationsTable.get(node);
2219 if (!registrations)
2220 continue;
2221 for (var j = 0; j < registrations.length; j++) {
2222 var registration = registrations[j];
2223 var options = registration.options;
2224 // 1.
2225 if (node !== target && !options.subtree)
2226 continue;
2227
2228 // 2.
2229 if (type === 'attributes' && !options.attributes)
2230 continue;
2231
2232 // 3. If type is "attributes", options's attributeFilter is present, and
2233 // either options's attributeFilter does not contain name or namespace
2234 // is non-null, continue.
2235 if (type === 'attributes' && options.attributeFilter &&
2236 (data.namespace !== null ||
2237 options.attributeFilter.indexOf(data.name) === -1)) {
2238 continue;
2239 }
2240
2241 // 4.
2242 if (type === 'characterData' && !options.characterData)
2243 continue;
2244
2245 // 5.
2246 if (type === 'childList' && !options.childList)
2247 continue;
2248
2249 // 6.
2250 var observer = registration.observer;
2251 interestedObservers[observer.uid_] = observer;
2252
2253 // 7. If either type is "attributes" and options's attributeOldValue is
2254 // true, or type is "characterData" and options's characterDataOldValue
2255 // is true, set the paired string of registered observer's observer in
2256 // interested observers to oldValue.
2257 if (type === 'attributes' && options.attributeOldValue ||
2258 type === 'characterData' && options.characterDataOldValue) {
2259 associatedStrings[observer.uid_] = data.oldValue;
2260 }
2261 }
2262 }
2263
2264 var anyRecordsEnqueued = false;
2265
2266 // 4.
2267 for (var uid in interestedObservers) {
2268 var observer = interestedObservers[uid];
2269 var record = new MutationRecord(type, target);
2270
2271 // 2.
2272 if ('name' in data && 'namespace' in data) {
2273 record.attributeName = data.name;
2274 record.attributeNamespace = data.namespace;
2275 }
2276
2277 // 3.
2278 if (data.addedNodes)
2279 record.addedNodes = data.addedNodes;
2280
2281 // 4.
2282 if (data.removedNodes)
2283 record.removedNodes = data.removedNodes;
2284
2285 // 5.
2286 if (data.previousSibling)
2287 record.previousSibling = data.previousSibling;
2288
2289 // 6.
2290 if (data.nextSibling)
2291 record.nextSibling = data.nextSibling;
2292
2293 // 7.
2294 if (associatedStrings[uid] !== undefined)
2295 record.oldValue = associatedStrings[uid];
2296
2297 // 8.
2298 observer.records_.push(record);
2299
2300 anyRecordsEnqueued = true;
2301 }
2302
2303 if (anyRecordsEnqueued)
2304 scheduleCallback();
2305 }
2306
2307 var slice = Array.prototype.slice;
2308
2309 /**
2310 * @param {!Object} options
2311 * @constructor
2312 */
2313 function MutationObserverOptions(options) {
2314 this.childList = !!options.childList;
2315 this.subtree = !!options.subtree;
2316
2317 // 1. If either options' attributeOldValue or attributeFilter is present
2318 // and options' attributes is omitted, set options' attributes to true.
2319 if (!('attributes' in options) &&
2320 ('attributeOldValue' in options || 'attributeFilter' in options)) {
2321 this.attributes = true;
2322 } else {
2323 this.attributes = !!options.attributes;
2324 }
2325
2326 // 2. If options' characterDataOldValue is present and options'
2327 // characterData is omitted, set options' characterData to true.
2328 if ('characterDataOldValue' in options && !('characterData' in options))
2329 this.characterData = true;
2330 else
2331 this.characterData = !!options.characterData;
2332
2333 // 3. & 4.
2334 if (!this.attributes &&
2335 (options.attributeOldValue || 'attributeFilter' in options) ||
2336 // 5.
2337 !this.characterData && options.characterDataOldValue) {
2338 throw new TypeError();
2339 }
2340
2341 this.characterData = !!options.characterData;
2342 this.attributeOldValue = !!options.attributeOldValue;
2343 this.characterDataOldValue = !!options.characterDataOldValue;
2344 if ('attributeFilter' in options) {
2345 if (options.attributeFilter == null ||
2346 typeof options.attributeFilter !== 'object') {
2347 throw new TypeError();
2348 }
2349 this.attributeFilter = slice.call(options.attributeFilter);
2350 } else {
2351 this.attributeFilter = null;
2352 }
2353 }
2354
2355 var uidCounter = 0;
2356
2357 /**
2358 * The class that maps to the DOM MutationObserver interface.
2359 * @param {Function} callback.
2360 * @constructor
2361 */
2362 function MutationObserver(callback) {
2363 this.callback_ = callback;
2364 this.nodes_ = [];
2365 this.records_ = [];
2366 this.uid_ = ++uidCounter;
2367
2368 // This will leak. There is no way to implement this without WeakRefs :'(
2369 globalMutationObservers.push(this);
2370 }
2371
2372 MutationObserver.prototype = {
2373 // http://dom.spec.whatwg.org/#dom-mutationobserver-observe
2374 observe: function(target, options) {
2375 target = wrapIfNeeded(target);
2376
2377 var newOptions = new MutationObserverOptions(options);
2378
2379 // 6.
2380 var registration;
2381 var registrations = registrationsTable.get(target);
2382 if (!registrations)
2383 registrationsTable.set(target, registrations = []);
2384
2385 for (var i = 0; i < registrations.length; i++) {
2386 if (registrations[i].observer === this) {
2387 registration = registrations[i];
2388 // 6.1.
2389 registration.removeTransientObservers();
2390 // 6.2.
2391 registration.options = newOptions;
2392 }
2393 }
2394
2395 // 7.
2396 if (!registration) {
2397 registration = new Registration(this, target, newOptions);
2398 registrations.push(registration);
2399 this.nodes_.push(target);
2400 }
2401 },
2402
2403 // http://dom.spec.whatwg.org/#dom-mutationobserver-disconnect
2404 disconnect: function() {
2405 this.nodes_.forEach(function(node) {
2406 var registrations = registrationsTable.get(node);
2407 for (var i = 0; i < registrations.length; i++) {
2408 var registration = registrations[i];
2409 if (registration.observer === this) {
2410 registrations.splice(i, 1);
2411 // Each node can only have one registered observer associated with
2412 // this observer.
2413 break;
2414 }
2415 }
2416 }, this);
2417 this.records_ = [];
2418 },
2419
2420 takeRecords: function() {
2421 var copyOfRecords = this.records_;
2422 this.records_ = [];
2423 return copyOfRecords;
2424 }
2425 };
2426
2427 /**
2428 * Class used to represent a registered observer.
2429 * @param {MutationObserver} observer
2430 * @param {Node} target
2431 * @param {MutationObserverOptions} options
2432 * @constructor
2433 */
2434 function Registration(observer, target, options) {
2435 this.observer = observer;
2436 this.target = target;
2437 this.options = options;
2438 this.transientObservedNodes = [];
2439 }
2440
2441 Registration.prototype = {
2442 /**
2443 * Adds a transient observer on node. The transient observer gets removed
2444 * next time we deliver the change records.
2445 * @param {Node} node
2446 */
2447 addTransientObserver: function(node) {
2448 // Don't add transient observers on the target itself. We already have all
2449 // the required listeners set up on the target.
2450 if (node === this.target)
2451 return;
2452
2453 this.transientObservedNodes.push(node);
2454 var registrations = registrationsTable.get(node);
2455 if (!registrations)
2456 registrationsTable.set(node, registrations = []);
2457
2458 // We know that registrations does not contain this because we already
2459 // checked if node === this.target.
2460 registrations.push(this);
2461 },
2462
2463 removeTransientObservers: function() {
2464 var transientObservedNodes = this.transientObservedNodes;
2465 this.transientObservedNodes = [];
2466
2467 for (var i = 0; i < transientObservedNodes.length; i++) {
2468 var node = transientObservedNodes[i];
2469 var registrations = registrationsTable.get(node);
2470 for (var j = 0; j < registrations.length; j++) {
2471 if (registrations[j] === this) {
2472 registrations.splice(j, 1);
2473 // Each node can only have one registered observer associated with
2474 // this observer.
2475 break;
2476 }
2477 }
2478 }
2479 }
2480 };
2481
2482 scope.enqueueMutation = enqueueMutation;
2483 scope.registerTransientObservers = registerTransientObservers;
2484 scope.wrappers.MutationObserver = MutationObserver;
2485 scope.wrappers.MutationRecord = MutationRecord;
2486
2487 })(window.ShadowDOMPolyfill);
2488
2489 // Copyright 2013 The Polymer Authors. All rights reserved.
2490 // Use of this source code is goverened by a BSD-style
2491 // license that can be found in the LICENSE file.
2492
2493 (function(scope) {
2494 'use strict';
2495
2496 var forwardMethodsToWrapper = scope.forwardMethodsToWrapper;
2497 var mixin = scope.mixin;
2498 var registerWrapper = scope.registerWrapper;
2499 var unwrap = scope.unwrap;
2500 var wrap = scope.wrap;
2501 var wrappers = scope.wrappers;
2502
2503 var wrappedFuns = new WeakMap();
2504 var listenersTable = new WeakMap();
2505 var handledEventsTable = new WeakMap();
2506 var currentlyDispatchingEvents = new WeakMap();
2507 var targetTable = new WeakMap();
2508 var currentTargetTable = new WeakMap();
2509 var relatedTargetTable = new WeakMap();
2510 var eventPhaseTable = new WeakMap();
2511 var stopPropagationTable = new WeakMap();
2512 var stopImmediatePropagationTable = new WeakMap();
2513 var eventHandlersTable = new WeakMap();
2514 var eventPathTable = new WeakMap();
2515
2516 function isShadowRoot(node) {
2517 return node instanceof wrappers.ShadowRoot;
2518 }
2519
2520 function isInsertionPoint(node) {
2521 var localName = node.localName;
2522 return localName === 'content' || localName === 'shadow';
2523 }
2524
2525 function isShadowHost(node) {
2526 return !!node.shadowRoot;
2527 }
2528
2529 function getEventParent(node) {
2530 var dv;
2531 return node.parentNode || (dv = node.defaultView) && wrap(dv) || null;
2532 }
2533
2534 // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#df n-adjusted-parent
2535 function calculateParents(node, context, ancestors) {
2536 if (ancestors.length)
2537 return ancestors.shift();
2538
2539 // 1.
2540 if (isShadowRoot(node))
2541 return getInsertionParent(node) || node.host;
2542
2543 // 2.
2544 var eventParents = scope.eventParentsTable.get(node);
2545 if (eventParents) {
2546 // Copy over the remaining event parents for next iteration.
2547 for (var i = 1; i < eventParents.length; i++) {
2548 ancestors[i - 1] = eventParents[i];
2549 }
2550 return eventParents[0];
2551 }
2552
2553 // 3.
2554 if (context && isInsertionPoint(node)) {
2555 var parentNode = node.parentNode;
2556 if (parentNode && isShadowHost(parentNode)) {
2557 var trees = scope.getShadowTrees(parentNode);
2558 var p = getInsertionParent(context);
2559 for (var i = 0; i < trees.length; i++) {
2560 if (trees[i].contains(p))
2561 return p;
2562 }
2563 }
2564 }
2565
2566 return getEventParent(node);
2567 }
2568
2569 // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#ev ent-retargeting
2570 function retarget(node) {
2571 var stack = []; // 1.
2572 var ancestor = node; // 2.
2573 var targets = [];
2574 var ancestors = [];
2575 while (ancestor) { // 3.
2576 var context = null; // 3.2.
2577 // TODO(arv): Change order of these. If the stack is empty we always end
2578 // up pushing ancestor, no matter what.
2579 if (isInsertionPoint(ancestor)) { // 3.1.
2580 context = topMostNotInsertionPoint(stack); // 3.1.1.
2581 var top = stack[stack.length - 1] || ancestor; // 3.1.2.
2582 stack.push(top);
2583 } else if (!stack.length) {
2584 stack.push(ancestor); // 3.3.
2585 }
2586 var target = stack[stack.length - 1]; // 3.4.
2587 targets.push({target: target, currentTarget: ancestor}); // 3.5.
2588 if (isShadowRoot(ancestor)) // 3.6.
2589 stack.pop(); // 3.6.1.
2590
2591 ancestor = calculateParents(ancestor, context, ancestors); // 3.7.
2592 }
2593 return targets;
2594 }
2595
2596 function topMostNotInsertionPoint(stack) {
2597 for (var i = stack.length - 1; i >= 0; i--) {
2598 if (!isInsertionPoint(stack[i]))
2599 return stack[i];
2600 }
2601 return null;
2602 }
2603
2604 // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#df n-adjusted-related-target
2605 function adjustRelatedTarget(target, related) {
2606 var ancestors = [];
2607 while (target) { // 3.
2608 var stack = []; // 3.1.
2609 var ancestor = related; // 3.2.
2610 var last = undefined; // 3.3. Needs to be reset every iteration.
2611 while (ancestor) {
2612 var context = null;
2613 if (!stack.length) {
2614 stack.push(ancestor);
2615 } else {
2616 if (isInsertionPoint(ancestor)) { // 3.4.3.
2617 context = topMostNotInsertionPoint(stack);
2618 // isDistributed is more general than checking whether last is
2619 // assigned into ancestor.
2620 if (isDistributed(last)) { // 3.4.3.2.
2621 var head = stack[stack.length - 1];
2622 stack.push(head);
2623 }
2624 }
2625 }
2626
2627 if (inSameTree(ancestor, target)) // 3.4.4.
2628 return stack[stack.length - 1];
2629
2630 if (isShadowRoot(ancestor)) // 3.4.5.
2631 stack.pop();
2632
2633 last = ancestor; // 3.4.6.
2634 ancestor = calculateParents(ancestor, context, ancestors); // 3.4.7.
2635 }
2636 if (isShadowRoot(target)) // 3.5.
2637 target = target.host;
2638 else
2639 target = target.parentNode; // 3.6.
2640 }
2641 }
2642
2643 function getInsertionParent(node) {
2644 return scope.insertionParentTable.get(node);
2645 }
2646
2647 function isDistributed(node) {
2648 return getInsertionParent(node);
2649 }
2650
2651 function rootOfNode(node) {
2652 var p;
2653 while (p = node.parentNode) {
2654 node = p;
2655 }
2656 return node;
2657 }
2658
2659 function inSameTree(a, b) {
2660 return rootOfNode(a) === rootOfNode(b);
2661 }
2662
2663 function enclosedBy(a, b) {
2664 if (a === b)
2665 return true;
2666 if (a instanceof wrappers.ShadowRoot)
2667 return enclosedBy(rootOfNode(a.host), b);
2668 return false;
2669 }
2670
2671
2672 function dispatchOriginalEvent(originalEvent) {
2673 // Make sure this event is only dispatched once.
2674 if (handledEventsTable.get(originalEvent))
2675 return;
2676 handledEventsTable.set(originalEvent, true);
2677
2678 return dispatchEvent(wrap(originalEvent), wrap(originalEvent.target));
2679 }
2680
2681 function dispatchEvent(event, originalWrapperTarget) {
2682 if (currentlyDispatchingEvents.get(event))
2683 throw new Error('InvalidStateError')
2684 currentlyDispatchingEvents.set(event, true);
2685
2686 // Render to ensure that the event path is correct.
2687 scope.renderAllPending();
2688 var eventPath = retarget(originalWrapperTarget);
2689
2690 // For window load events the load event is dispatched at the window but
2691 // the target is set to the document.
2692 //
2693 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html# the-end
2694 //
2695 // TODO(arv): Find a less hacky way to do this.
2696 if (event.type === 'load' &&
2697 eventPath.length === 2 &&
2698 eventPath[0].target instanceof wrappers.Document) {
2699 eventPath.shift();
2700 }
2701
2702 eventPathTable.set(event, eventPath);
2703
2704 if (dispatchCapturing(event, eventPath)) {
2705 if (dispatchAtTarget(event, eventPath)) {
2706 dispatchBubbling(event, eventPath);
2707 }
2708 }
2709
2710 eventPhaseTable.set(event, Event.NONE);
2711 currentTargetTable.delete(event, null);
2712 currentlyDispatchingEvents.delete(event);
2713
2714 return event.defaultPrevented;
2715 }
2716
2717 function dispatchCapturing(event, eventPath) {
2718 var phase;
2719
2720 for (var i = eventPath.length - 1; i > 0; i--) {
2721 var target = eventPath[i].target;
2722 var currentTarget = eventPath[i].currentTarget;
2723 if (target === currentTarget)
2724 continue;
2725
2726 phase = Event.CAPTURING_PHASE;
2727 if (!invoke(eventPath[i], event, phase))
2728 return false;
2729 }
2730
2731 return true;
2732 }
2733
2734 function dispatchAtTarget(event, eventPath) {
2735 var phase = Event.AT_TARGET;
2736 return invoke(eventPath[0], event, phase);
2737 }
2738
2739 function dispatchBubbling(event, eventPath) {
2740 var bubbles = event.bubbles;
2741 var phase;
2742
2743 for (var i = 1; i < eventPath.length; i++) {
2744 var target = eventPath[i].target;
2745 var currentTarget = eventPath[i].currentTarget;
2746 if (target === currentTarget)
2747 phase = Event.AT_TARGET;
2748 else if (bubbles && !stopImmediatePropagationTable.get(event))
2749 phase = Event.BUBBLING_PHASE;
2750 else
2751 continue;
2752
2753 if (!invoke(eventPath[i], event, phase))
2754 return;
2755 }
2756 }
2757
2758 function invoke(tuple, event, phase) {
2759 var target = tuple.target;
2760 var currentTarget = tuple.currentTarget;
2761
2762 var listeners = listenersTable.get(currentTarget);
2763 if (!listeners)
2764 return true;
2765
2766 if ('relatedTarget' in event) {
2767 var originalEvent = unwrap(event);
2768 // X-Tag sets relatedTarget on a CustomEvent. If they do that there is no
2769 // way to have relatedTarget return the adjusted target but worse is that
2770 // the originalEvent might not have a relatedTarget so we hit an assert
2771 // when we try to wrap it.
2772 if (originalEvent.relatedTarget) {
2773 var relatedTarget = wrap(originalEvent.relatedTarget);
2774
2775 var adjusted = adjustRelatedTarget(currentTarget, relatedTarget);
2776 if (adjusted === target)
2777 return true;
2778
2779 relatedTargetTable.set(event, adjusted);
2780 }
2781 }
2782
2783 eventPhaseTable.set(event, phase);
2784 var type = event.type;
2785
2786 var anyRemoved = false;
2787 targetTable.set(event, target);
2788 currentTargetTable.set(event, currentTarget);
2789
2790 for (var i = 0; i < listeners.length; i++) {
2791 var listener = listeners[i];
2792 if (listener.removed) {
2793 anyRemoved = true;
2794 continue;
2795 }
2796
2797 if (listener.type !== type ||
2798 !listener.capture && phase === Event.CAPTURING_PHASE ||
2799 listener.capture && phase === Event.BUBBLING_PHASE) {
2800 continue;
2801 }
2802
2803 try {
2804 if (typeof listener.handler === 'function')
2805 listener.handler.call(currentTarget, event);
2806 else
2807 listener.handler.handleEvent(event);
2808
2809 if (stopImmediatePropagationTable.get(event))
2810 return false;
2811
2812 } catch (ex) {
2813 if (window.onerror)
2814 window.onerror(ex.message);
2815 else
2816 console.error(ex, ex.stack);
2817 }
2818 }
2819
2820 if (anyRemoved) {
2821 var copy = listeners.slice();
2822 listeners.length = 0;
2823 for (var i = 0; i < copy.length; i++) {
2824 if (!copy[i].removed)
2825 listeners.push(copy[i]);
2826 }
2827 }
2828
2829 return !stopPropagationTable.get(event);
2830 }
2831
2832 function Listener(type, handler, capture) {
2833 this.type = type;
2834 this.handler = handler;
2835 this.capture = Boolean(capture);
2836 }
2837 Listener.prototype = {
2838 equals: function(that) {
2839 return this.handler === that.handler && this.type === that.type &&
2840 this.capture === that.capture;
2841 },
2842 get removed() {
2843 return this.handler === null;
2844 },
2845 remove: function() {
2846 this.handler = null;
2847 }
2848 };
2849
2850 var OriginalEvent = window.Event;
2851 OriginalEvent.prototype.polymerBlackList_ = {
2852 returnValue: true,
2853 // TODO(arv): keyLocation is part of KeyboardEvent but Firefox does not
2854 // support constructable KeyboardEvent so we keep it here for now.
2855 keyLocation: true
2856 };
2857
2858 /**
2859 * Creates a new Event wrapper or wraps an existin native Event object.
2860 * @param {string|Event} type
2861 * @param {Object=} options
2862 * @constructor
2863 */
2864 function Event(type, options) {
2865 if (type instanceof OriginalEvent)
2866 this.impl = type;
2867 else
2868 return wrap(constructEvent(OriginalEvent, 'Event', type, options));
2869 }
2870 Event.prototype = {
2871 get target() {
2872 return targetTable.get(this);
2873 },
2874 get currentTarget() {
2875 return currentTargetTable.get(this);
2876 },
2877 get eventPhase() {
2878 return eventPhaseTable.get(this);
2879 },
2880 get path() {
2881 var nodeList = new wrappers.NodeList();
2882 var eventPath = eventPathTable.get(this);
2883 if (eventPath) {
2884 var index = 0;
2885 var lastIndex = eventPath.length - 1;
2886 var baseRoot = rootOfNode(currentTargetTable.get(this));
2887
2888 for (var i = 0; i <= lastIndex; i++) {
2889 var currentTarget = eventPath[i].currentTarget;
2890 var currentRoot = rootOfNode(currentTarget);
2891 if (enclosedBy(baseRoot, currentRoot) &&
2892 // Make sure we do not add Window to the path.
2893 (i !== lastIndex || currentTarget instanceof wrappers.Node)) {
2894 nodeList[index++] = currentTarget;
2895 }
2896 }
2897 nodeList.length = index;
2898 }
2899 return nodeList;
2900 },
2901 stopPropagation: function() {
2902 stopPropagationTable.set(this, true);
2903 },
2904 stopImmediatePropagation: function() {
2905 stopPropagationTable.set(this, true);
2906 stopImmediatePropagationTable.set(this, true);
2907 }
2908 };
2909 registerWrapper(OriginalEvent, Event, document.createEvent('Event'));
2910
2911 function unwrapOptions(options) {
2912 if (!options || !options.relatedTarget)
2913 return options;
2914 return Object.create(options, {
2915 relatedTarget: {value: unwrap(options.relatedTarget)}
2916 });
2917 }
2918
2919 function registerGenericEvent(name, SuperEvent, prototype) {
2920 var OriginalEvent = window[name];
2921 var GenericEvent = function(type, options) {
2922 if (type instanceof OriginalEvent)
2923 this.impl = type;
2924 else
2925 return wrap(constructEvent(OriginalEvent, name, type, options));
2926 };
2927 GenericEvent.prototype = Object.create(SuperEvent.prototype);
2928 if (prototype)
2929 mixin(GenericEvent.prototype, prototype);
2930 if (OriginalEvent) {
2931 // - Old versions of Safari fails on new FocusEvent (and others?).
2932 // - IE does not support event constructors.
2933 // - createEvent('FocusEvent') throws in Firefox.
2934 // => Try the best practice solution first and fallback to the old way
2935 // if needed.
2936 try {
2937 registerWrapper(OriginalEvent, GenericEvent, new OriginalEvent('temp'));
2938 } catch (ex) {
2939 registerWrapper(OriginalEvent, GenericEvent,
2940 document.createEvent(name));
2941 }
2942 }
2943 return GenericEvent;
2944 }
2945
2946 var UIEvent = registerGenericEvent('UIEvent', Event);
2947 var CustomEvent = registerGenericEvent('CustomEvent', Event);
2948
2949 var relatedTargetProto = {
2950 get relatedTarget() {
2951 return relatedTargetTable.get(this) || wrap(unwrap(this).relatedTarget);
2952 }
2953 };
2954
2955 function getInitFunction(name, relatedTargetIndex) {
2956 return function() {
2957 arguments[relatedTargetIndex] = unwrap(arguments[relatedTargetIndex]);
2958 var impl = unwrap(this);
2959 impl[name].apply(impl, arguments);
2960 };
2961 }
2962
2963 var mouseEventProto = mixin({
2964 initMouseEvent: getInitFunction('initMouseEvent', 14)
2965 }, relatedTargetProto);
2966
2967 var focusEventProto = mixin({
2968 initFocusEvent: getInitFunction('initFocusEvent', 5)
2969 }, relatedTargetProto);
2970
2971 var MouseEvent = registerGenericEvent('MouseEvent', UIEvent, mouseEventProto);
2972 var FocusEvent = registerGenericEvent('FocusEvent', UIEvent, focusEventProto);
2973
2974 // In case the browser does not support event constructors we polyfill that
2975 // by calling `createEvent('Foo')` and `initFooEvent` where the arguments to
2976 // `initFooEvent` are derived from the registered default event init dict.
2977 var defaultInitDicts = Object.create(null);
2978
2979 var supportsEventConstructors = (function() {
2980 try {
2981 new window.FocusEvent('focus');
2982 } catch (ex) {
2983 return false;
2984 }
2985 return true;
2986 })();
2987
2988 /**
2989 * Constructs a new native event.
2990 */
2991 function constructEvent(OriginalEvent, name, type, options) {
2992 if (supportsEventConstructors)
2993 return new OriginalEvent(type, unwrapOptions(options));
2994
2995 // Create the arguments from the default dictionary.
2996 var event = unwrap(document.createEvent(name));
2997 var defaultDict = defaultInitDicts[name];
2998 var args = [type];
2999 Object.keys(defaultDict).forEach(function(key) {
3000 var v = options != null && key in options ?
3001 options[key] : defaultDict[key];
3002 if (key === 'relatedTarget')
3003 v = unwrap(v);
3004 args.push(v);
3005 });
3006 event['init' + name].apply(event, args);
3007 return event;
3008 }
3009
3010 if (!supportsEventConstructors) {
3011 var configureEventConstructor = function(name, initDict, superName) {
3012 if (superName) {
3013 var superDict = defaultInitDicts[superName];
3014 initDict = mixin(mixin({}, superDict), initDict);
3015 }
3016
3017 defaultInitDicts[name] = initDict;
3018 };
3019
3020 // The order of the default event init dictionary keys is important, the
3021 // arguments to initFooEvent is derived from that.
3022 configureEventConstructor('Event', {bubbles: false, cancelable: false});
3023 configureEventConstructor('CustomEvent', {detail: null}, 'Event');
3024 configureEventConstructor('UIEvent', {view: null, detail: 0}, 'Event');
3025 configureEventConstructor('MouseEvent', {
3026 screenX: 0,
3027 screenY: 0,
3028 clientX: 0,
3029 clientY: 0,
3030 ctrlKey: false,
3031 altKey: false,
3032 shiftKey: false,
3033 metaKey: false,
3034 button: 0,
3035 relatedTarget: null
3036 }, 'UIEvent');
3037 configureEventConstructor('FocusEvent', {relatedTarget: null}, 'UIEvent');
3038 }
3039
3040 function BeforeUnloadEvent(impl) {
3041 Event.call(this);
3042 }
3043 BeforeUnloadEvent.prototype = Object.create(Event.prototype);
3044 mixin(BeforeUnloadEvent.prototype, {
3045 get returnValue() {
3046 return this.impl.returnValue;
3047 },
3048 set returnValue(v) {
3049 this.impl.returnValue = v;
3050 }
3051 });
3052
3053 function isValidListener(fun) {
3054 if (typeof fun === 'function')
3055 return true;
3056 return fun && fun.handleEvent;
3057 }
3058
3059 function isMutationEvent(type) {
3060 switch (type) {
3061 case 'DOMAttrModified':
3062 case 'DOMAttributeNameChanged':
3063 case 'DOMCharacterDataModified':
3064 case 'DOMElementNameChanged':
3065 case 'DOMNodeInserted':
3066 case 'DOMNodeInsertedIntoDocument':
3067 case 'DOMNodeRemoved':
3068 case 'DOMNodeRemovedFromDocument':
3069 case 'DOMSubtreeModified':
3070 return true;
3071 }
3072 return false;
3073 }
3074
3075 var OriginalEventTarget = window.EventTarget;
3076
3077 /**
3078 * This represents a wrapper for an EventTarget.
3079 * @param {!EventTarget} impl The original event target.
3080 * @constructor
3081 */
3082 function EventTarget(impl) {
3083 this.impl = impl;
3084 }
3085
3086 // Node and Window have different internal type checks in WebKit so we cannot
3087 // use the same method as the original function.
3088 var methodNames = [
3089 'addEventListener',
3090 'removeEventListener',
3091 'dispatchEvent'
3092 ];
3093
3094 [Node, Window].forEach(function(constructor) {
3095 var p = constructor.prototype;
3096 methodNames.forEach(function(name) {
3097 Object.defineProperty(p, name + '_', {value: p[name]});
3098 });
3099 });
3100
3101 function getTargetToListenAt(wrapper) {
3102 if (wrapper instanceof wrappers.ShadowRoot)
3103 wrapper = wrapper.host;
3104 return unwrap(wrapper);
3105 }
3106
3107 EventTarget.prototype = {
3108 addEventListener: function(type, fun, capture) {
3109 if (!isValidListener(fun) || isMutationEvent(type))
3110 return;
3111
3112 var listener = new Listener(type, fun, capture);
3113 var listeners = listenersTable.get(this);
3114 if (!listeners) {
3115 listeners = [];
3116 listenersTable.set(this, listeners);
3117 } else {
3118 // Might have a duplicate.
3119 for (var i = 0; i < listeners.length; i++) {
3120 if (listener.equals(listeners[i]))
3121 return;
3122 }
3123 }
3124
3125 listeners.push(listener);
3126
3127 var target = getTargetToListenAt(this);
3128 target.addEventListener_(type, dispatchOriginalEvent, true);
3129 },
3130 removeEventListener: function(type, fun, capture) {
3131 capture = Boolean(capture);
3132 var listeners = listenersTable.get(this);
3133 if (!listeners)
3134 return;
3135 var count = 0, found = false;
3136 for (var i = 0; i < listeners.length; i++) {
3137 if (listeners[i].type === type && listeners[i].capture === capture) {
3138 count++;
3139 if (listeners[i].handler === fun) {
3140 found = true;
3141 listeners[i].remove();
3142 }
3143 }
3144 }
3145
3146 if (found && count === 1) {
3147 var target = getTargetToListenAt(this);
3148 target.removeEventListener_(type, dispatchOriginalEvent, true);
3149 }
3150 },
3151 dispatchEvent: function(event) {
3152 // We want to use the native dispatchEvent because it triggers the default
3153 // actions (like checking a checkbox). However, if there are no listeners
3154 // in the composed tree then there are no events that will trigger and
3155 // listeners in the non composed tree that are part of the event path are
3156 // not notified.
3157 //
3158 // If we find out that there are no listeners in the composed tree we add
3159 // a temporary listener to the target which makes us get called back even
3160 // in that case.
3161
3162 var nativeEvent = unwrap(event);
3163 var eventType = nativeEvent.type;
3164
3165 // Allow dispatching the same event again. This is safe because if user
3166 // code calls this during an existing dispatch of the same event the
3167 // native dispatchEvent throws (that is required by the spec).
3168 handledEventsTable.set(nativeEvent, false);
3169
3170 // Force rendering since we prefer native dispatch and that works on the
3171 // composed tree.
3172 scope.renderAllPending();
3173
3174 var tempListener;
3175 if (!hasListenerInAncestors(this, eventType)) {
3176 tempListener = function() {};
3177 this.addEventListener(eventType, tempListener, true);
3178 }
3179
3180 try {
3181 return unwrap(this).dispatchEvent_(nativeEvent);
3182 } finally {
3183 if (tempListener)
3184 this.removeEventListener(eventType, tempListener, true);
3185 }
3186 }
3187 };
3188
3189 function hasListener(node, type) {
3190 var listeners = listenersTable.get(node);
3191 if (listeners) {
3192 for (var i = 0; i < listeners.length; i++) {
3193 if (!listeners[i].removed && listeners[i].type === type)
3194 return true;
3195 }
3196 }
3197 return false;
3198 }
3199
3200 function hasListenerInAncestors(target, type) {
3201 for (var node = unwrap(target); node; node = node.parentNode) {
3202 if (hasListener(wrap(node), type))
3203 return true;
3204 }
3205 return false;
3206 }
3207
3208 if (OriginalEventTarget)
3209 registerWrapper(OriginalEventTarget, EventTarget);
3210
3211 function wrapEventTargetMethods(constructors) {
3212 forwardMethodsToWrapper(constructors, methodNames);
3213 }
3214
3215 var originalElementFromPoint = document.elementFromPoint;
3216
3217 function elementFromPoint(self, document, x, y) {
3218 scope.renderAllPending();
3219
3220 var element = wrap(originalElementFromPoint.call(document.impl, x, y));
3221 var targets = retarget(element, this)
3222 for (var i = 0; i < targets.length; i++) {
3223 var target = targets[i];
3224 if (target.currentTarget === self)
3225 return target.target;
3226 }
3227 return null;
3228 }
3229
3230 /**
3231 * Returns a function that is to be used as a getter for `onfoo` properties.
3232 * @param {string} name
3233 * @return {Function}
3234 */
3235 function getEventHandlerGetter(name) {
3236 return function() {
3237 var inlineEventHandlers = eventHandlersTable.get(this);
3238 return inlineEventHandlers && inlineEventHandlers[name] &&
3239 inlineEventHandlers[name].value || null;
3240 };
3241 }
3242
3243 /**
3244 * Returns a function that is to be used as a setter for `onfoo` properties.
3245 * @param {string} name
3246 * @return {Function}
3247 */
3248 function getEventHandlerSetter(name) {
3249 var eventType = name.slice(2);
3250 return function(value) {
3251 var inlineEventHandlers = eventHandlersTable.get(this);
3252 if (!inlineEventHandlers) {
3253 inlineEventHandlers = Object.create(null);
3254 eventHandlersTable.set(this, inlineEventHandlers);
3255 }
3256
3257 var old = inlineEventHandlers[name];
3258 if (old)
3259 this.removeEventListener(eventType, old.wrapped, false);
3260
3261 if (typeof value === 'function') {
3262 var wrapped = function(e) {
3263 var rv = value.call(this, e);
3264 if (rv === false)
3265 e.preventDefault();
3266 else if (name === 'onbeforeunload' && typeof rv === 'string')
3267 e.returnValue = rv;
3268 // mouseover uses true for preventDefault but preventDefault for
3269 // mouseover is ignored by browsers these day.
3270 };
3271
3272 this.addEventListener(eventType, wrapped, false);
3273 inlineEventHandlers[name] = {
3274 value: value,
3275 wrapped: wrapped
3276 };
3277 }
3278 };
3279 }
3280
3281 scope.adjustRelatedTarget = adjustRelatedTarget;
3282 scope.elementFromPoint = elementFromPoint;
3283 scope.getEventHandlerGetter = getEventHandlerGetter;
3284 scope.getEventHandlerSetter = getEventHandlerSetter;
3285 scope.wrapEventTargetMethods = wrapEventTargetMethods;
3286 scope.wrappers.BeforeUnloadEvent = BeforeUnloadEvent;
3287 scope.wrappers.CustomEvent = CustomEvent;
3288 scope.wrappers.Event = Event;
3289 scope.wrappers.EventTarget = EventTarget;
3290 scope.wrappers.FocusEvent = FocusEvent;
3291 scope.wrappers.MouseEvent = MouseEvent;
3292 scope.wrappers.UIEvent = UIEvent;
3293
3294 })(window.ShadowDOMPolyfill);
3295
3296 // Copyright 2012 The Polymer Authors. All rights reserved.
3297 // Use of this source code is goverened by a BSD-style
3298 // license that can be found in the LICENSE file.
3299
3300 (function(scope) {
3301 'use strict';
3302
3303 var wrap = scope.wrap;
3304
3305 function nonEnum(obj, prop) {
3306 Object.defineProperty(obj, prop, {enumerable: false});
3307 }
3308
3309 function NodeList() {
3310 this.length = 0;
3311 nonEnum(this, 'length');
3312 }
3313 NodeList.prototype = {
3314 item: function(index) {
3315 return this[index];
3316 }
3317 };
3318 nonEnum(NodeList.prototype, 'item');
3319
3320 function wrapNodeList(list) {
3321 if (list == null)
3322 return list;
3323 var wrapperList = new NodeList();
3324 for (var i = 0, length = list.length; i < length; i++) {
3325 wrapperList[i] = wrap(list[i]);
3326 }
3327 wrapperList.length = length;
3328 return wrapperList;
3329 }
3330
3331 function addWrapNodeListMethod(wrapperConstructor, name) {
3332 wrapperConstructor.prototype[name] = function() {
3333 return wrapNodeList(this.impl[name].apply(this.impl, arguments));
3334 };
3335 }
3336
3337 scope.wrappers.NodeList = NodeList;
3338 scope.addWrapNodeListMethod = addWrapNodeListMethod;
3339 scope.wrapNodeList = wrapNodeList;
3340
3341 })(window.ShadowDOMPolyfill);
3342
3343 // Copyright 2012 The Polymer Authors. All rights reserved.
3344 // Use of this source code is goverened by a BSD-style
3345 // license that can be found in the LICENSE file.
3346
3347 (function(scope) {
3348 'use strict';
3349
3350 var EventTarget = scope.wrappers.EventTarget;
3351 var NodeList = scope.wrappers.NodeList;
3352 var assert = scope.assert;
3353 var defineWrapGetter = scope.defineWrapGetter;
3354 var enqueueMutation = scope.enqueueMutation;
3355 var isWrapper = scope.isWrapper;
3356 var mixin = scope.mixin;
3357 var registerTransientObservers = scope.registerTransientObservers;
3358 var registerWrapper = scope.registerWrapper;
3359 var unwrap = scope.unwrap;
3360 var wrap = scope.wrap;
3361 var wrapIfNeeded = scope.wrapIfNeeded;
3362
3363 function assertIsNodeWrapper(node) {
3364 assert(node instanceof Node);
3365 }
3366
3367 function createOneElementNodeList(node) {
3368 var nodes = new NodeList();
3369 nodes[0] = node;
3370 nodes.length = 1;
3371 return nodes;
3372 }
3373
3374 var surpressMutations = false;
3375
3376 /**
3377 * Called before node is inserted into a node to enqueue its removal from its
3378 * old parent.
3379 * @param {!Node} node The node that is about to be removed.
3380 * @param {!Node} parent The parent node that the node is being removed from.
3381 * @param {!NodeList} nodes The collected nodes.
3382 */
3383 function enqueueRemovalForInsertedNodes(node, parent, nodes) {
3384 enqueueMutation(parent, 'childList', {
3385 removedNodes: nodes,
3386 previousSibling: node.previousSibling,
3387 nextSibling: node.nextSibling
3388 });
3389 }
3390
3391 function enqueueRemovalForInsertedDocumentFragment(df, nodes) {
3392 enqueueMutation(df, 'childList', {
3393 removedNodes: nodes
3394 });
3395 }
3396
3397 /**
3398 * Collects nodes from a DocumentFragment or a Node for removal followed
3399 * by an insertion.
3400 *
3401 * This updates the internal pointers for node, previousNode and nextNode.
3402 */
3403 function collectNodes(node, parentNode, previousNode, nextNode) {
3404 if (node instanceof DocumentFragment) {
3405 var nodes = collectNodesForDocumentFragment(node);
3406
3407 // The extra loop is to work around bugs with DocumentFragments in IE.
3408 surpressMutations = true;
3409 for (var i = nodes.length - 1; i >= 0; i--) {
3410 node.removeChild(nodes[i]);
3411 nodes[i].parentNode_ = parentNode;
3412 }
3413 surpressMutations = false;
3414
3415 for (var i = 0; i < nodes.length; i++) {
3416 nodes[i].previousSibling_ = nodes[i - 1] || previousNode;
3417 nodes[i].nextSibling_ = nodes[i + 1] || nextNode;
3418 }
3419
3420 if (previousNode)
3421 previousNode.nextSibling_ = nodes[0];
3422 if (nextNode)
3423 nextNode.previousSibling_ = nodes[nodes.length - 1];
3424
3425 return nodes;
3426 }
3427
3428 var nodes = createOneElementNodeList(node);
3429 var oldParent = node.parentNode;
3430 if (oldParent) {
3431 // This will enqueue the mutation record for the removal as needed.
3432 oldParent.removeChild(node);
3433 }
3434
3435 node.parentNode_ = parentNode;
3436 node.previousSibling_ = previousNode;
3437 node.nextSibling_ = nextNode;
3438 if (previousNode)
3439 previousNode.nextSibling_ = node;
3440 if (nextNode)
3441 nextNode.previousSibling_ = node;
3442
3443 return nodes;
3444 }
3445
3446 function collectNodesNative(node) {
3447 if (node instanceof DocumentFragment)
3448 return collectNodesForDocumentFragment(node);
3449
3450 var nodes = createOneElementNodeList(node);
3451 var oldParent = node.parentNode;
3452 if (oldParent)
3453 enqueueRemovalForInsertedNodes(node, oldParent, nodes);
3454 return nodes;
3455 }
3456
3457 function collectNodesForDocumentFragment(node) {
3458 var nodes = new NodeList();
3459 var i = 0;
3460 for (var child = node.firstChild; child; child = child.nextSibling) {
3461 nodes[i++] = child;
3462 }
3463 nodes.length = i;
3464 enqueueRemovalForInsertedDocumentFragment(node, nodes);
3465 return nodes;
3466 }
3467
3468 function snapshotNodeList(nodeList) {
3469 // NodeLists are not live at the moment so just return the same object.
3470 return nodeList;
3471 }
3472
3473 // http://dom.spec.whatwg.org/#node-is-inserted
3474 function nodeWasAdded(node) {
3475 node.nodeIsInserted_();
3476 }
3477
3478 function nodesWereAdded(nodes) {
3479 for (var i = 0; i < nodes.length; i++) {
3480 nodeWasAdded(nodes[i]);
3481 }
3482 }
3483
3484 // http://dom.spec.whatwg.org/#node-is-removed
3485 function nodeWasRemoved(node) {
3486 // Nothing at this point in time.
3487 }
3488
3489 function nodesWereRemoved(nodes) {
3490 // Nothing at this point in time.
3491 }
3492
3493 function ensureSameOwnerDocument(parent, child) {
3494 var ownerDoc = parent.nodeType === Node.DOCUMENT_NODE ?
3495 parent : parent.ownerDocument;
3496 if (ownerDoc !== child.ownerDocument)
3497 ownerDoc.adoptNode(child);
3498 }
3499
3500 function adoptNodesIfNeeded(owner, nodes) {
3501 if (!nodes.length)
3502 return;
3503
3504 var ownerDoc = owner.ownerDocument;
3505
3506 // All nodes have the same ownerDocument when we get here.
3507 if (ownerDoc === nodes[0].ownerDocument)
3508 return;
3509
3510 for (var i = 0; i < nodes.length; i++) {
3511 scope.adoptNodeNoRemove(nodes[i], ownerDoc);
3512 }
3513 }
3514
3515 function unwrapNodesForInsertion(owner, nodes) {
3516 adoptNodesIfNeeded(owner, nodes);
3517 var length = nodes.length;
3518
3519 if (length === 1)
3520 return unwrap(nodes[0]);
3521
3522 var df = unwrap(owner.ownerDocument.createDocumentFragment());
3523 for (var i = 0; i < length; i++) {
3524 df.appendChild(unwrap(nodes[i]));
3525 }
3526 return df;
3527 }
3528
3529 function clearChildNodes(wrapper) {
3530 if (wrapper.firstChild_ !== undefined) {
3531 var child = wrapper.firstChild_;
3532 while (child) {
3533 var tmp = child;
3534 child = child.nextSibling_;
3535 tmp.parentNode_ = tmp.previousSibling_ = tmp.nextSibling_ = undefined;
3536 }
3537 }
3538 wrapper.firstChild_ = wrapper.lastChild_ = undefined;
3539 }
3540
3541 function removeAllChildNodes(wrapper) {
3542 if (wrapper.invalidateShadowRenderer()) {
3543 var childWrapper = wrapper.firstChild;
3544 while (childWrapper) {
3545 assert(childWrapper.parentNode === wrapper);
3546 var nextSibling = childWrapper.nextSibling;
3547 var childNode = unwrap(childWrapper);
3548 var parentNode = childNode.parentNode;
3549 if (parentNode)
3550 originalRemoveChild.call(parentNode, childNode);
3551 childWrapper.previousSibling_ = childWrapper.nextSibling_ =
3552 childWrapper.parentNode_ = null;
3553 childWrapper = nextSibling;
3554 }
3555 wrapper.firstChild_ = wrapper.lastChild_ = null;
3556 } else {
3557 var node = unwrap(wrapper);
3558 var child = node.firstChild;
3559 var nextSibling;
3560 while (child) {
3561 nextSibling = child.nextSibling;
3562 originalRemoveChild.call(node, child);
3563 child = nextSibling;
3564 }
3565 }
3566 }
3567
3568 function invalidateParent(node) {
3569 var p = node.parentNode;
3570 return p && p.invalidateShadowRenderer();
3571 }
3572
3573 function cleanupNodes(nodes) {
3574 for (var i = 0, n; i < nodes.length; i++) {
3575 n = nodes[i];
3576 n.parentNode.removeChild(n);
3577 }
3578 }
3579
3580 var OriginalNode = window.Node;
3581
3582 /**
3583 * This represents a wrapper of a native DOM node.
3584 * @param {!Node} original The original DOM node, aka, the visual DOM node.
3585 * @constructor
3586 * @extends {EventTarget}
3587 */
3588 function Node(original) {
3589 assert(original instanceof OriginalNode);
3590
3591 EventTarget.call(this, original);
3592
3593 // These properties are used to override the visual references with the
3594 // logical ones. If the value is undefined it means that the logical is the
3595 // same as the visual.
3596
3597 /**
3598 * @type {Node|undefined}
3599 * @private
3600 */
3601 this.parentNode_ = undefined;
3602
3603 /**
3604 * @type {Node|undefined}
3605 * @private
3606 */
3607 this.firstChild_ = undefined;
3608
3609 /**
3610 * @type {Node|undefined}
3611 * @private
3612 */
3613 this.lastChild_ = undefined;
3614
3615 /**
3616 * @type {Node|undefined}
3617 * @private
3618 */
3619 this.nextSibling_ = undefined;
3620
3621 /**
3622 * @type {Node|undefined}
3623 * @private
3624 */
3625 this.previousSibling_ = undefined;
3626 }
3627
3628 var OriginalDocumentFragment = window.DocumentFragment;
3629 var originalAppendChild = OriginalNode.prototype.appendChild;
3630 var originalCompareDocumentPosition =
3631 OriginalNode.prototype.compareDocumentPosition;
3632 var originalInsertBefore = OriginalNode.prototype.insertBefore;
3633 var originalRemoveChild = OriginalNode.prototype.removeChild;
3634 var originalReplaceChild = OriginalNode.prototype.replaceChild;
3635
3636 var isIe = /Trident/.test(navigator.userAgent);
3637
3638 var removeChildOriginalHelper = isIe ?
3639 function(parent, child) {
3640 try {
3641 originalRemoveChild.call(parent, child);
3642 } catch (ex) {
3643 if (!(parent instanceof OriginalDocumentFragment))
3644 throw ex;
3645 }
3646 } :
3647 function(parent, child) {
3648 originalRemoveChild.call(parent, child);
3649 };
3650
3651 Node.prototype = Object.create(EventTarget.prototype);
3652 mixin(Node.prototype, {
3653 appendChild: function(childWrapper) {
3654 return this.insertBefore(childWrapper, null);
3655 },
3656
3657 insertBefore: function(childWrapper, refWrapper) {
3658 assertIsNodeWrapper(childWrapper);
3659
3660 var refNode;
3661 if (refWrapper) {
3662 if (isWrapper(refWrapper)) {
3663 refNode = unwrap(refWrapper);
3664 } else {
3665 refNode = refWrapper;
3666 refWrapper = wrap(refNode);
3667 }
3668 } else {
3669 refWrapper = null;
3670 refNode = null;
3671 }
3672
3673 refWrapper && assert(refWrapper.parentNode === this);
3674
3675 var nodes;
3676 var previousNode =
3677 refWrapper ? refWrapper.previousSibling : this.lastChild;
3678
3679 var useNative = !this.invalidateShadowRenderer() &&
3680 !invalidateParent(childWrapper);
3681
3682 if (useNative)
3683 nodes = collectNodesNative(childWrapper);
3684 else
3685 nodes = collectNodes(childWrapper, this, previousNode, refWrapper);
3686
3687 if (useNative) {
3688 ensureSameOwnerDocument(this, childWrapper);
3689 clearChildNodes(this);
3690 originalInsertBefore.call(this.impl, unwrap(childWrapper), refNode);
3691 } else {
3692 if (!previousNode)
3693 this.firstChild_ = nodes[0];
3694 if (!refWrapper)
3695 this.lastChild_ = nodes[nodes.length - 1];
3696
3697 var parentNode = refNode ? refNode.parentNode : this.impl;
3698
3699 // insertBefore refWrapper no matter what the parent is?
3700 if (parentNode) {
3701 originalInsertBefore.call(parentNode,
3702 unwrapNodesForInsertion(this, nodes), refNode);
3703 } else {
3704 adoptNodesIfNeeded(this, nodes);
3705 }
3706 }
3707
3708 enqueueMutation(this, 'childList', {
3709 addedNodes: nodes,
3710 nextSibling: refWrapper,
3711 previousSibling: previousNode
3712 });
3713
3714 nodesWereAdded(nodes);
3715
3716 return childWrapper;
3717 },
3718
3719 removeChild: function(childWrapper) {
3720 assertIsNodeWrapper(childWrapper);
3721 if (childWrapper.parentNode !== this) {
3722 // IE has invalid DOM trees at times.
3723 var found = false;
3724 var childNodes = this.childNodes;
3725 for (var ieChild = this.firstChild; ieChild;
3726 ieChild = ieChild.nextSibling) {
3727 if (ieChild === childWrapper) {
3728 found = true;
3729 break;
3730 }
3731 }
3732 if (!found) {
3733 // TODO(arv): DOMException
3734 throw new Error('NotFoundError');
3735 }
3736 }
3737
3738 var childNode = unwrap(childWrapper);
3739 var childWrapperNextSibling = childWrapper.nextSibling;
3740 var childWrapperPreviousSibling = childWrapper.previousSibling;
3741
3742 if (this.invalidateShadowRenderer()) {
3743 // We need to remove the real node from the DOM before updating the
3744 // pointers. This is so that that mutation event is dispatched before
3745 // the pointers have changed.
3746 var thisFirstChild = this.firstChild;
3747 var thisLastChild = this.lastChild;
3748
3749 var parentNode = childNode.parentNode;
3750 if (parentNode)
3751 removeChildOriginalHelper(parentNode, childNode);
3752
3753 if (thisFirstChild === childWrapper)
3754 this.firstChild_ = childWrapperNextSibling;
3755 if (thisLastChild === childWrapper)
3756 this.lastChild_ = childWrapperPreviousSibling;
3757 if (childWrapperPreviousSibling)
3758 childWrapperPreviousSibling.nextSibling_ = childWrapperNextSibling;
3759 if (childWrapperNextSibling) {
3760 childWrapperNextSibling.previousSibling_ =
3761 childWrapperPreviousSibling;
3762 }
3763
3764 childWrapper.previousSibling_ = childWrapper.nextSibling_ =
3765 childWrapper.parentNode_ = undefined;
3766 } else {
3767 clearChildNodes(this);
3768 removeChildOriginalHelper(this.impl, childNode);
3769 }
3770
3771 if (!surpressMutations) {
3772 enqueueMutation(this, 'childList', {
3773 removedNodes: createOneElementNodeList(childWrapper),
3774 nextSibling: childWrapperNextSibling,
3775 previousSibling: childWrapperPreviousSibling
3776 });
3777 }
3778
3779 registerTransientObservers(this, childWrapper);
3780
3781 return childWrapper;
3782 },
3783
3784 replaceChild: function(newChildWrapper, oldChildWrapper) {
3785 assertIsNodeWrapper(newChildWrapper);
3786
3787 var oldChildNode;
3788 if (isWrapper(oldChildWrapper)) {
3789 oldChildNode = unwrap(oldChildWrapper);
3790 } else {
3791 oldChildNode = oldChildWrapper;
3792 oldChildWrapper = wrap(oldChildNode);
3793 }
3794
3795 if (oldChildWrapper.parentNode !== this) {
3796 // TODO(arv): DOMException
3797 throw new Error('NotFoundError');
3798 }
3799
3800 var nextNode = oldChildWrapper.nextSibling;
3801 var previousNode = oldChildWrapper.previousSibling;
3802 var nodes;
3803
3804 var useNative = !this.invalidateShadowRenderer() &&
3805 !invalidateParent(newChildWrapper);
3806
3807 if (useNative) {
3808 nodes = collectNodesNative(newChildWrapper);
3809 } else {
3810 if (nextNode === newChildWrapper)
3811 nextNode = newChildWrapper.nextSibling;
3812 nodes = collectNodes(newChildWrapper, this, previousNode, nextNode);
3813 }
3814
3815 if (!useNative) {
3816 if (this.firstChild === oldChildWrapper)
3817 this.firstChild_ = nodes[0];
3818 if (this.lastChild === oldChildWrapper)
3819 this.lastChild_ = nodes[nodes.length - 1];
3820
3821 oldChildWrapper.previousSibling_ = oldChildWrapper.nextSibling_ =
3822 oldChildWrapper.parentNode_ = undefined;
3823
3824 // replaceChild no matter what the parent is?
3825 if (oldChildNode.parentNode) {
3826 originalReplaceChild.call(
3827 oldChildNode.parentNode,
3828 unwrapNodesForInsertion(this, nodes),
3829 oldChildNode);
3830 }
3831 } else {
3832 ensureSameOwnerDocument(this, newChildWrapper);
3833 clearChildNodes(this);
3834 originalReplaceChild.call(this.impl, unwrap(newChildWrapper),
3835 oldChildNode);
3836 }
3837
3838 enqueueMutation(this, 'childList', {
3839 addedNodes: nodes,
3840 removedNodes: createOneElementNodeList(oldChildWrapper),
3841 nextSibling: nextNode,
3842 previousSibling: previousNode
3843 });
3844
3845 nodeWasRemoved(oldChildWrapper);
3846 nodesWereAdded(nodes);
3847
3848 return oldChildWrapper;
3849 },
3850
3851 /**
3852 * Called after a node was inserted. Subclasses override this to invalidate
3853 * the renderer as needed.
3854 * @private
3855 */
3856 nodeIsInserted_: function() {
3857 for (var child = this.firstChild; child; child = child.nextSibling) {
3858 child.nodeIsInserted_();
3859 }
3860 },
3861
3862 hasChildNodes: function() {
3863 return this.firstChild !== null;
3864 },
3865
3866 /** @type {Node} */
3867 get parentNode() {
3868 // If the parentNode has not been overridden, use the original parentNode.
3869 return this.parentNode_ !== undefined ?
3870 this.parentNode_ : wrap(this.impl.parentNode);
3871 },
3872
3873 /** @type {Node} */
3874 get firstChild() {
3875 return this.firstChild_ !== undefined ?
3876 this.firstChild_ : wrap(this.impl.firstChild);
3877 },
3878
3879 /** @type {Node} */
3880 get lastChild() {
3881 return this.lastChild_ !== undefined ?
3882 this.lastChild_ : wrap(this.impl.lastChild);
3883 },
3884
3885 /** @type {Node} */
3886 get nextSibling() {
3887 return this.nextSibling_ !== undefined ?
3888 this.nextSibling_ : wrap(this.impl.nextSibling);
3889 },
3890
3891 /** @type {Node} */
3892 get previousSibling() {
3893 return this.previousSibling_ !== undefined ?
3894 this.previousSibling_ : wrap(this.impl.previousSibling);
3895 },
3896
3897 get parentElement() {
3898 var p = this.parentNode;
3899 while (p && p.nodeType !== Node.ELEMENT_NODE) {
3900 p = p.parentNode;
3901 }
3902 return p;
3903 },
3904
3905 get textContent() {
3906 // TODO(arv): This should fallback to this.impl.textContent if there
3907 // are no shadow trees below or above the context node.
3908 var s = '';
3909 for (var child = this.firstChild; child; child = child.nextSibling) {
3910 if (child.nodeType != Node.COMMENT_NODE) {
3911 s += child.textContent;
3912 }
3913 }
3914 return s;
3915 },
3916 set textContent(textContent) {
3917 var removedNodes = snapshotNodeList(this.childNodes);
3918
3919 if (this.invalidateShadowRenderer()) {
3920 removeAllChildNodes(this);
3921 if (textContent !== '') {
3922 var textNode = this.impl.ownerDocument.createTextNode(textContent);
3923 this.appendChild(textNode);
3924 }
3925 } else {
3926 clearChildNodes(this);
3927 this.impl.textContent = textContent;
3928 }
3929
3930 var addedNodes = snapshotNodeList(this.childNodes);
3931
3932 enqueueMutation(this, 'childList', {
3933 addedNodes: addedNodes,
3934 removedNodes: removedNodes
3935 });
3936
3937 nodesWereRemoved(removedNodes);
3938 nodesWereAdded(addedNodes);
3939 },
3940
3941 get childNodes() {
3942 var wrapperList = new NodeList();
3943 var i = 0;
3944 for (var child = this.firstChild; child; child = child.nextSibling) {
3945 wrapperList[i++] = child;
3946 }
3947 wrapperList.length = i;
3948 return wrapperList;
3949 },
3950
3951 cloneNode: function(deep) {
3952 var clone = wrap(this.impl.cloneNode(false));
3953 if (deep) {
3954 for (var child = this.firstChild; child; child = child.nextSibling) {
3955 clone.appendChild(child.cloneNode(true));
3956 }
3957 }
3958 // TODO(arv): Some HTML elements also clone other data like value.
3959 return clone;
3960 },
3961
3962 contains: function(child) {
3963 if (!child)
3964 return false;
3965
3966 child = wrapIfNeeded(child);
3967
3968 // TODO(arv): Optimize using ownerDocument etc.
3969 if (child === this)
3970 return true;
3971 var parentNode = child.parentNode;
3972 if (!parentNode)
3973 return false;
3974 return this.contains(parentNode);
3975 },
3976
3977 compareDocumentPosition: function(otherNode) {
3978 // This only wraps, it therefore only operates on the composed DOM and not
3979 // the logical DOM.
3980 return originalCompareDocumentPosition.call(this.impl, unwrap(otherNode));
3981 },
3982
3983 normalize: function() {
3984 var nodes = snapshotNodeList(this.childNodes);
3985 var remNodes = [];
3986 var s = '';
3987 var modNode;
3988
3989 for (var i = 0, n; i < nodes.length; i++) {
3990 n = nodes[i];
3991 if (n.nodeType === Node.TEXT_NODE) {
3992 if (!modNode && !n.data.length)
3993 this.removeNode(n);
3994 else if (!modNode)
3995 modNode = n;
3996 else {
3997 s += n.data;
3998 remNodes.push(n);
3999 }
4000 } else {
4001 if (modNode && remNodes.length) {
4002 modNode.data += s;
4003 cleanUpNodes(remNodes);
4004 }
4005 remNodes = [];
4006 s = '';
4007 modNode = null;
4008 if (n.childNodes.length)
4009 n.normalize();
4010 }
4011 }
4012
4013 // handle case where >1 text nodes are the last children
4014 if (modNode && remNodes.length) {
4015 modNode.data += s;
4016 cleanupNodes(remNodes);
4017 }
4018 }
4019 });
4020
4021 defineWrapGetter(Node, 'ownerDocument');
4022
4023 // We use a DocumentFragment as a base and then delete the properties of
4024 // DocumentFragment.prototype from the wrapper Node. Since delete makes
4025 // objects slow in some JS engines we recreate the prototype object.
4026 registerWrapper(OriginalNode, Node, document.createDocumentFragment());
4027 delete Node.prototype.querySelector;
4028 delete Node.prototype.querySelectorAll;
4029 Node.prototype = mixin(Object.create(EventTarget.prototype), Node.prototype);
4030
4031 scope.nodeWasAdded = nodeWasAdded;
4032 scope.nodeWasRemoved = nodeWasRemoved;
4033 scope.nodesWereAdded = nodesWereAdded;
4034 scope.nodesWereRemoved = nodesWereRemoved;
4035 scope.snapshotNodeList = snapshotNodeList;
4036 scope.wrappers.Node = Node;
4037
4038 })(window.ShadowDOMPolyfill);
4039
4040 // Copyright 2013 The Polymer Authors. All rights reserved.
4041 // Use of this source code is governed by a BSD-style
4042 // license that can be found in the LICENSE file.
4043
4044 (function(scope) {
4045 'use strict';
4046
4047 function findOne(node, selector) {
4048 var m, el = node.firstElementChild;
4049 while (el) {
4050 if (el.matches(selector))
4051 return el;
4052 m = findOne(el, selector);
4053 if (m)
4054 return m;
4055 el = el.nextElementSibling;
4056 }
4057 return null;
4058 }
4059
4060 function findAll(node, selector, results) {
4061 var el = node.firstElementChild;
4062 while (el) {
4063 if (el.matches(selector))
4064 results[results.length++] = el;
4065 findAll(el, selector, results);
4066 el = el.nextElementSibling;
4067 }
4068 return results;
4069 }
4070
4071 // find and findAll will only match Simple Selectors,
4072 // Structural Pseudo Classes are not guarenteed to be correct
4073 // http://www.w3.org/TR/css3-selectors/#simple-selectors
4074
4075 var SelectorsInterface = {
4076 querySelector: function(selector) {
4077 return findOne(this, selector);
4078 },
4079 querySelectorAll: function(selector) {
4080 return findAll(this, selector, new NodeList())
4081 }
4082 };
4083
4084 var GetElementsByInterface = {
4085 getElementsByTagName: function(tagName) {
4086 // TODO(arv): Check tagName?
4087 return this.querySelectorAll(tagName);
4088 },
4089 getElementsByClassName: function(className) {
4090 // TODO(arv): Check className?
4091 return this.querySelectorAll('.' + className);
4092 },
4093 getElementsByTagNameNS: function(ns, tagName) {
4094 if (ns === '*')
4095 return this.getElementsByTagName(tagName);
4096
4097 // TODO(arv): Check tagName?
4098 var result = new NodeList;
4099 var els = this.getElementsByTagName(tagName);
4100 for (var i = 0, j = 0; i < els.length; i++) {
4101 if (els[i].namespaceURI === ns)
4102 result[j++] = els[i];
4103 }
4104 result.length = j;
4105 return result;
4106 }
4107 };
4108
4109 scope.GetElementsByInterface = GetElementsByInterface;
4110 scope.SelectorsInterface = SelectorsInterface;
4111
4112 })(window.ShadowDOMPolyfill);
4113
4114 // Copyright 2013 The Polymer Authors. All rights reserved.
4115 // Use of this source code is goverened by a BSD-style
4116 // license that can be found in the LICENSE file.
4117
4118 (function(scope) {
4119 'use strict';
4120
4121 var NodeList = scope.wrappers.NodeList;
4122
4123 function forwardElement(node) {
4124 while (node && node.nodeType !== Node.ELEMENT_NODE) {
4125 node = node.nextSibling;
4126 }
4127 return node;
4128 }
4129
4130 function backwardsElement(node) {
4131 while (node && node.nodeType !== Node.ELEMENT_NODE) {
4132 node = node.previousSibling;
4133 }
4134 return node;
4135 }
4136
4137 var ParentNodeInterface = {
4138 get firstElementChild() {
4139 return forwardElement(this.firstChild);
4140 },
4141
4142 get lastElementChild() {
4143 return backwardsElement(this.lastChild);
4144 },
4145
4146 get childElementCount() {
4147 var count = 0;
4148 for (var child = this.firstElementChild;
4149 child;
4150 child = child.nextElementSibling) {
4151 count++;
4152 }
4153 return count;
4154 },
4155
4156 get children() {
4157 var wrapperList = new NodeList();
4158 var i = 0;
4159 for (var child = this.firstElementChild;
4160 child;
4161 child = child.nextElementSibling) {
4162 wrapperList[i++] = child;
4163 }
4164 wrapperList.length = i;
4165 return wrapperList;
4166 }
4167 };
4168
4169 var ChildNodeInterface = {
4170 get nextElementSibling() {
4171 return forwardElement(this.nextSibling);
4172 },
4173
4174 get previousElementSibling() {
4175 return backwardsElement(this.previousSibling);
4176 }
4177 };
4178
4179 scope.ChildNodeInterface = ChildNodeInterface;
4180 scope.ParentNodeInterface = ParentNodeInterface;
4181
4182 })(window.ShadowDOMPolyfill);
4183
4184 // Copyright 2013 The Polymer Authors. All rights reserved.
4185 // Use of this source code is goverened by a BSD-style
4186 // license that can be found in the LICENSE file.
4187
4188 (function(scope) {
4189 'use strict';
4190
4191 var ChildNodeInterface = scope.ChildNodeInterface;
4192 var Node = scope.wrappers.Node;
4193 var enqueueMutation = scope.enqueueMutation;
4194 var mixin = scope.mixin;
4195 var registerWrapper = scope.registerWrapper;
4196
4197 var OriginalCharacterData = window.CharacterData;
4198
4199 function CharacterData(node) {
4200 Node.call(this, node);
4201 }
4202 CharacterData.prototype = Object.create(Node.prototype);
4203 mixin(CharacterData.prototype, {
4204 get textContent() {
4205 return this.data;
4206 },
4207 set textContent(value) {
4208 this.data = value;
4209 },
4210 get data() {
4211 return this.impl.data;
4212 },
4213 set data(value) {
4214 var oldValue = this.impl.data;
4215 enqueueMutation(this, 'characterData', {
4216 oldValue: oldValue
4217 });
4218 this.impl.data = value;
4219 }
4220 });
4221
4222 mixin(CharacterData.prototype, ChildNodeInterface);
4223
4224 registerWrapper(OriginalCharacterData, CharacterData,
4225 document.createTextNode(''));
4226
4227 scope.wrappers.CharacterData = CharacterData;
4228 })(window.ShadowDOMPolyfill);
4229
4230 // Copyright 2014 The Polymer Authors. All rights reserved.
4231 // Use of this source code is goverened by a BSD-style
4232 // license that can be found in the LICENSE file.
4233
4234 (function(scope) {
4235 'use strict';
4236
4237 var CharacterData = scope.wrappers.CharacterData;
4238 var enqueueMutation = scope.enqueueMutation;
4239 var mixin = scope.mixin;
4240 var registerWrapper = scope.registerWrapper;
4241
4242 function toUInt32(x) {
4243 return x >>> 0;
4244 }
4245
4246 var OriginalText = window.Text;
4247
4248 function Text(node) {
4249 CharacterData.call(this, node);
4250 }
4251 Text.prototype = Object.create(CharacterData.prototype);
4252 mixin(Text.prototype, {
4253 splitText: function(offset) {
4254 offset = toUInt32(offset);
4255 var s = this.data;
4256 if (offset > s.length)
4257 throw new Error('IndexSizeError');
4258 var head = s.slice(0, offset);
4259 var tail = s.slice(offset);
4260 this.data = head;
4261 var newTextNode = this.ownerDocument.createTextNode(tail);
4262 if (this.parentNode)
4263 this.parentNode.insertBefore(newTextNode, this.nextSibling);
4264 return newTextNode;
4265 }
4266 });
4267
4268 registerWrapper(OriginalText, Text, document.createTextNode(''));
4269
4270 scope.wrappers.Text = Text;
4271 })(window.ShadowDOMPolyfill);
4272
4273 // Copyright 2013 The Polymer Authors. All rights reserved.
4274 // Use of this source code is goverened by a BSD-style
4275 // license that can be found in the LICENSE file.
4276
4277 (function(scope) {
4278 'use strict';
4279
4280 var ChildNodeInterface = scope.ChildNodeInterface;
4281 var GetElementsByInterface = scope.GetElementsByInterface;
4282 var Node = scope.wrappers.Node;
4283 var ParentNodeInterface = scope.ParentNodeInterface;
4284 var SelectorsInterface = scope.SelectorsInterface;
4285 var addWrapNodeListMethod = scope.addWrapNodeListMethod;
4286 var enqueueMutation = scope.enqueueMutation;
4287 var mixin = scope.mixin;
4288 var oneOf = scope.oneOf;
4289 var registerWrapper = scope.registerWrapper;
4290 var wrappers = scope.wrappers;
4291
4292 var OriginalElement = window.Element;
4293
4294 var matchesNames = [
4295 'matches', // needs to come first.
4296 'mozMatchesSelector',
4297 'msMatchesSelector',
4298 'webkitMatchesSelector',
4299 ].filter(function(name) {
4300 return OriginalElement.prototype[name];
4301 });
4302
4303 var matchesName = matchesNames[0];
4304
4305 var originalMatches = OriginalElement.prototype[matchesName];
4306
4307 function invalidateRendererBasedOnAttribute(element, name) {
4308 // Only invalidate if parent node is a shadow host.
4309 var p = element.parentNode;
4310 if (!p || !p.shadowRoot)
4311 return;
4312
4313 var renderer = scope.getRendererForHost(p);
4314 if (renderer.dependsOnAttribute(name))
4315 renderer.invalidate();
4316 }
4317
4318 function enqueAttributeChange(element, name, oldValue) {
4319 // This is not fully spec compliant. We should use localName (which might
4320 // have a different case than name) and the namespace (which requires us
4321 // to get the Attr object).
4322 enqueueMutation(element, 'attributes', {
4323 name: name,
4324 namespace: null,
4325 oldValue: oldValue
4326 });
4327 }
4328
4329 function Element(node) {
4330 Node.call(this, node);
4331 }
4332 Element.prototype = Object.create(Node.prototype);
4333 mixin(Element.prototype, {
4334 createShadowRoot: function() {
4335 var newShadowRoot = new wrappers.ShadowRoot(this);
4336 this.impl.polymerShadowRoot_ = newShadowRoot;
4337
4338 var renderer = scope.getRendererForHost(this);
4339 renderer.invalidate();
4340
4341 return newShadowRoot;
4342 },
4343
4344 get shadowRoot() {
4345 return this.impl.polymerShadowRoot_ || null;
4346 },
4347
4348 setAttribute: function(name, value) {
4349 var oldValue = this.impl.getAttribute(name);
4350 this.impl.setAttribute(name, value);
4351 enqueAttributeChange(this, name, oldValue);
4352 invalidateRendererBasedOnAttribute(this, name);
4353 },
4354
4355 removeAttribute: function(name) {
4356 var oldValue = this.impl.getAttribute(name);
4357 this.impl.removeAttribute(name);
4358 enqueAttributeChange(this, name, oldValue);
4359 invalidateRendererBasedOnAttribute(this, name);
4360 },
4361
4362 matches: function(selector) {
4363 return originalMatches.call(this.impl, selector);
4364 }
4365 });
4366
4367 matchesNames.forEach(function(name) {
4368 if (name !== 'matches') {
4369 Element.prototype[name] = function(selector) {
4370 return this.matches(selector);
4371 };
4372 }
4373 });
4374
4375 if (OriginalElement.prototype.webkitCreateShadowRoot) {
4376 Element.prototype.webkitCreateShadowRoot =
4377 Element.prototype.createShadowRoot;
4378 }
4379
4380 /**
4381 * Useful for generating the accessor pair for a property that reflects an
4382 * attribute.
4383 */
4384 function setterDirtiesAttribute(prototype, propertyName, opt_attrName) {
4385 var attrName = opt_attrName || propertyName;
4386 Object.defineProperty(prototype, propertyName, {
4387 get: function() {
4388 return this.impl[propertyName];
4389 },
4390 set: function(v) {
4391 this.impl[propertyName] = v;
4392 invalidateRendererBasedOnAttribute(this, attrName);
4393 },
4394 configurable: true,
4395 enumerable: true
4396 });
4397 }
4398
4399 setterDirtiesAttribute(Element.prototype, 'id');
4400 setterDirtiesAttribute(Element.prototype, 'className', 'class');
4401
4402 mixin(Element.prototype, ChildNodeInterface);
4403 mixin(Element.prototype, GetElementsByInterface);
4404 mixin(Element.prototype, ParentNodeInterface);
4405 mixin(Element.prototype, SelectorsInterface);
4406
4407 registerWrapper(OriginalElement, Element,
4408 document.createElementNS(null, 'x'));
4409
4410 // TODO(arv): Export setterDirtiesAttribute and apply it to more bindings
4411 // that reflect attributes.
4412 scope.matchesNames = matchesNames;
4413 scope.wrappers.Element = Element;
4414 })(window.ShadowDOMPolyfill);
4415
4416 // Copyright 2013 The Polymer Authors. All rights reserved.
4417 // Use of this source code is goverened by a BSD-style
4418 // license that can be found in the LICENSE file.
4419
4420 (function(scope) {
4421 'use strict';
4422
4423 var Element = scope.wrappers.Element;
4424 var defineGetter = scope.defineGetter;
4425 var enqueueMutation = scope.enqueueMutation;
4426 var mixin = scope.mixin;
4427 var nodesWereAdded = scope.nodesWereAdded;
4428 var nodesWereRemoved = scope.nodesWereRemoved;
4429 var registerWrapper = scope.registerWrapper;
4430 var snapshotNodeList = scope.snapshotNodeList;
4431 var unwrap = scope.unwrap;
4432 var wrap = scope.wrap;
4433
4434 /////////////////////////////////////////////////////////////////////////////
4435 // innerHTML and outerHTML
4436
4437 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#es capingString
4438 var escapeAttrRegExp = /[&\u00A0"]/g;
4439 var escapeDataRegExp = /[&\u00A0<>]/g;
4440
4441 function escapeReplace(c) {
4442 switch (c) {
4443 case '&':
4444 return '&amp;';
4445 case '<':
4446 return '&lt;';
4447 case '>':
4448 return '&gt;';
4449 case '"':
4450 return '&quot;'
4451 case '\u00A0':
4452 return '&nbsp;';
4453 }
4454 }
4455
4456 function escapeAttr(s) {
4457 return s.replace(escapeAttrRegExp, escapeReplace);
4458 }
4459
4460 function escapeData(s) {
4461 return s.replace(escapeDataRegExp, escapeReplace);
4462 }
4463
4464 function makeSet(arr) {
4465 var set = {};
4466 for (var i = 0; i < arr.length; i++) {
4467 set[arr[i]] = true;
4468 }
4469 return set;
4470 }
4471
4472 // http://www.whatwg.org/specs/web-apps/current-work/#void-elements
4473 var voidElements = makeSet([
4474 'area',
4475 'base',
4476 'br',
4477 'col',
4478 'command',
4479 'embed',
4480 'hr',
4481 'img',
4482 'input',
4483 'keygen',
4484 'link',
4485 'meta',
4486 'param',
4487 'source',
4488 'track',
4489 'wbr'
4490 ]);
4491
4492 var plaintextParents = makeSet([
4493 'style',
4494 'script',
4495 'xmp',
4496 'iframe',
4497 'noembed',
4498 'noframes',
4499 'plaintext',
4500 'noscript'
4501 ]);
4502
4503 function getOuterHTML(node, parentNode) {
4504 switch (node.nodeType) {
4505 case Node.ELEMENT_NODE:
4506 var tagName = node.tagName.toLowerCase();
4507 var s = '<' + tagName;
4508 var attrs = node.attributes;
4509 for (var i = 0, attr; attr = attrs[i]; i++) {
4510 s += ' ' + attr.name + '="' + escapeAttr(attr.value) + '"';
4511 }
4512 s += '>';
4513 if (voidElements[tagName])
4514 return s;
4515
4516 return s + getInnerHTML(node) + '</' + tagName + '>';
4517
4518 case Node.TEXT_NODE:
4519 var data = node.data;
4520 if (parentNode && plaintextParents[parentNode.localName])
4521 return data;
4522 return escapeData(data);
4523
4524 case Node.COMMENT_NODE:
4525 return '<!--' + node.data + '-->';
4526
4527 default:
4528 console.error(node);
4529 throw new Error('not implemented');
4530 }
4531 }
4532
4533 function getInnerHTML(node) {
4534 var s = '';
4535 for (var child = node.firstChild; child; child = child.nextSibling) {
4536 s += getOuterHTML(child, node);
4537 }
4538 return s;
4539 }
4540
4541 function setInnerHTML(node, value, opt_tagName) {
4542 var tagName = opt_tagName || 'div';
4543 node.textContent = '';
4544 var tempElement = unwrap(node.ownerDocument.createElement(tagName));
4545 tempElement.innerHTML = value;
4546 var firstChild;
4547 while (firstChild = tempElement.firstChild) {
4548 node.appendChild(wrap(firstChild));
4549 }
4550 }
4551
4552 // IE11 does not have MSIE in the user agent string.
4553 var oldIe = /MSIE/.test(navigator.userAgent);
4554
4555 var OriginalHTMLElement = window.HTMLElement;
4556
4557 function HTMLElement(node) {
4558 Element.call(this, node);
4559 }
4560 HTMLElement.prototype = Object.create(Element.prototype);
4561 mixin(HTMLElement.prototype, {
4562 get innerHTML() {
4563 // TODO(arv): This should fallback to this.impl.innerHTML if there
4564 // are no shadow trees below or above the context node.
4565 return getInnerHTML(this);
4566 },
4567 set innerHTML(value) {
4568 // IE9 does not handle set innerHTML correctly on plaintextParents. It
4569 // creates element children. For example
4570 //
4571 // scriptElement.innerHTML = '<a>test</a>'
4572 //
4573 // Creates a single HTMLAnchorElement child.
4574 if (oldIe && plaintextParents[this.localName]) {
4575 this.textContent = value;
4576 return;
4577 }
4578
4579 var removedNodes = snapshotNodeList(this.childNodes);
4580
4581 if (this.invalidateShadowRenderer())
4582 setInnerHTML(this, value, this.tagName);
4583 else
4584 this.impl.innerHTML = value;
4585 var addedNodes = snapshotNodeList(this.childNodes);
4586
4587 enqueueMutation(this, 'childList', {
4588 addedNodes: addedNodes,
4589 removedNodes: removedNodes
4590 });
4591
4592 nodesWereRemoved(removedNodes);
4593 nodesWereAdded(addedNodes);
4594 },
4595
4596 get outerHTML() {
4597 return getOuterHTML(this, this.parentNode);
4598 },
4599 set outerHTML(value) {
4600 var p = this.parentNode;
4601 if (p) {
4602 p.invalidateShadowRenderer();
4603 var df = frag(p, value);
4604 p.replaceChild(df, this);
4605 }
4606 },
4607
4608 insertAdjacentHTML: function(position, text) {
4609 var contextElement, refNode;
4610 switch (String(position).toLowerCase()) {
4611 case 'beforebegin':
4612 contextElement = this.parentNode;
4613 refNode = this;
4614 break;
4615 case 'afterend':
4616 contextElement = this.parentNode;
4617 refNode = this.nextSibling;
4618 break;
4619 case 'afterbegin':
4620 contextElement = this;
4621 refNode = this.firstChild;
4622 break;
4623 case 'beforeend':
4624 contextElement = this;
4625 refNode = null;
4626 break;
4627 default:
4628 return;
4629 }
4630
4631 var df = frag(contextElement, text);
4632 contextElement.insertBefore(df, refNode);
4633 }
4634 });
4635
4636 function frag(contextElement, html) {
4637 // TODO(arv): This does not work with SVG and other non HTML elements.
4638 var p = unwrap(contextElement.cloneNode(false));
4639 p.innerHTML = html;
4640 var df = unwrap(document.createDocumentFragment());
4641 var c;
4642 while (c = p.firstChild) {
4643 df.appendChild(c);
4644 }
4645 return wrap(df);
4646 }
4647
4648 function getter(name) {
4649 return function() {
4650 scope.renderAllPending();
4651 return this.impl[name];
4652 };
4653 }
4654
4655 function getterRequiresRendering(name) {
4656 defineGetter(HTMLElement, name, getter(name));
4657 }
4658
4659 [
4660 'clientHeight',
4661 'clientLeft',
4662 'clientTop',
4663 'clientWidth',
4664 'offsetHeight',
4665 'offsetLeft',
4666 'offsetTop',
4667 'offsetWidth',
4668 'scrollHeight',
4669 'scrollWidth',
4670 ].forEach(getterRequiresRendering);
4671
4672 function getterAndSetterRequiresRendering(name) {
4673 Object.defineProperty(HTMLElement.prototype, name, {
4674 get: getter(name),
4675 set: function(v) {
4676 scope.renderAllPending();
4677 this.impl[name] = v;
4678 },
4679 configurable: true,
4680 enumerable: true
4681 });
4682 }
4683
4684 [
4685 'scrollLeft',
4686 'scrollTop',
4687 ].forEach(getterAndSetterRequiresRendering);
4688
4689 function methodRequiresRendering(name) {
4690 Object.defineProperty(HTMLElement.prototype, name, {
4691 value: function() {
4692 scope.renderAllPending();
4693 return this.impl[name].apply(this.impl, arguments);
4694 },
4695 configurable: true,
4696 enumerable: true
4697 });
4698 }
4699
4700 [
4701 'getBoundingClientRect',
4702 'getClientRects',
4703 'scrollIntoView'
4704 ].forEach(methodRequiresRendering);
4705
4706 // HTMLElement is abstract so we use a subclass that has no members.
4707 registerWrapper(OriginalHTMLElement, HTMLElement,
4708 document.createElement('b'));
4709
4710 scope.wrappers.HTMLElement = HTMLElement;
4711
4712 // TODO: Find a better way to share these two with WrapperShadowRoot.
4713 scope.getInnerHTML = getInnerHTML;
4714 scope.setInnerHTML = setInnerHTML
4715 })(window.ShadowDOMPolyfill);
4716
4717 // Copyright 2013 The Polymer Authors. All rights reserved.
4718 // Use of this source code is goverened by a BSD-style
4719 // license that can be found in the LICENSE file.
4720
4721 (function(scope) {
4722 'use strict';
4723
4724 var HTMLElement = scope.wrappers.HTMLElement;
4725 var mixin = scope.mixin;
4726 var registerWrapper = scope.registerWrapper;
4727 var wrap = scope.wrap;
4728
4729 var OriginalHTMLCanvasElement = window.HTMLCanvasElement;
4730
4731 function HTMLCanvasElement(node) {
4732 HTMLElement.call(this, node);
4733 }
4734 HTMLCanvasElement.prototype = Object.create(HTMLElement.prototype);
4735
4736 mixin(HTMLCanvasElement.prototype, {
4737 getContext: function() {
4738 var context = this.impl.getContext.apply(this.impl, arguments);
4739 return context && wrap(context);
4740 }
4741 });
4742
4743 registerWrapper(OriginalHTMLCanvasElement, HTMLCanvasElement,
4744 document.createElement('canvas'));
4745
4746 scope.wrappers.HTMLCanvasElement = HTMLCanvasElement;
4747 })(window.ShadowDOMPolyfill);
4748
4749 // Copyright 2013 The Polymer Authors. All rights reserved.
4750 // Use of this source code is goverened by a BSD-style
4751 // license that can be found in the LICENSE file.
4752
4753 (function(scope) {
4754 'use strict';
4755
4756 var HTMLElement = scope.wrappers.HTMLElement;
4757 var mixin = scope.mixin;
4758 var registerWrapper = scope.registerWrapper;
4759
4760 var OriginalHTMLContentElement = window.HTMLContentElement;
4761
4762 function HTMLContentElement(node) {
4763 HTMLElement.call(this, node);
4764 }
4765 HTMLContentElement.prototype = Object.create(HTMLElement.prototype);
4766 mixin(HTMLContentElement.prototype, {
4767 get select() {
4768 return this.getAttribute('select');
4769 },
4770 set select(value) {
4771 this.setAttribute('select', value);
4772 },
4773
4774 setAttribute: function(n, v) {
4775 HTMLElement.prototype.setAttribute.call(this, n, v);
4776 if (String(n).toLowerCase() === 'select')
4777 this.invalidateShadowRenderer(true);
4778 }
4779
4780 // getDistributedNodes is added in ShadowRenderer
4781
4782 // TODO: attribute boolean resetStyleInheritance;
4783 });
4784
4785 if (OriginalHTMLContentElement)
4786 registerWrapper(OriginalHTMLContentElement, HTMLContentElement);
4787
4788 scope.wrappers.HTMLContentElement = HTMLContentElement;
4789 })(window.ShadowDOMPolyfill);
4790
4791 // Copyright 2013 The Polymer Authors. All rights reserved.
4792 // Use of this source code is goverened by a BSD-style
4793 // license that can be found in the LICENSE file.
4794
4795 (function(scope) {
4796 'use strict';
4797
4798 var HTMLElement = scope.wrappers.HTMLElement;
4799 var registerWrapper = scope.registerWrapper;
4800 var unwrap = scope.unwrap;
4801 var rewrap = scope.rewrap;
4802
4803 var OriginalHTMLImageElement = window.HTMLImageElement;
4804
4805 function HTMLImageElement(node) {
4806 HTMLElement.call(this, node);
4807 }
4808 HTMLImageElement.prototype = Object.create(HTMLElement.prototype);
4809
4810 registerWrapper(OriginalHTMLImageElement, HTMLImageElement,
4811 document.createElement('img'));
4812
4813 function Image(width, height) {
4814 if (!(this instanceof Image)) {
4815 throw new TypeError(
4816 'DOM object constructor cannot be called as a function.');
4817 }
4818
4819 var node = unwrap(document.createElement('img'));
4820 HTMLElement.call(this, node);
4821 rewrap(node, this);
4822
4823 if (width !== undefined)
4824 node.width = width;
4825 if (height !== undefined)
4826 node.height = height;
4827 }
4828
4829 Image.prototype = HTMLImageElement.prototype;
4830
4831 scope.wrappers.HTMLImageElement = HTMLImageElement;
4832 scope.wrappers.Image = Image;
4833 })(window.ShadowDOMPolyfill);
4834
4835 // Copyright 2013 The Polymer Authors. All rights reserved.
4836 // Use of this source code is goverened by a BSD-style
4837 // license that can be found in the LICENSE file.
4838
4839 (function(scope) {
4840 'use strict';
4841
4842 var HTMLElement = scope.wrappers.HTMLElement;
4843 var mixin = scope.mixin;
4844 var registerWrapper = scope.registerWrapper;
4845
4846 var OriginalHTMLShadowElement = window.HTMLShadowElement;
4847
4848 function HTMLShadowElement(node) {
4849 HTMLElement.call(this, node);
4850 }
4851 HTMLShadowElement.prototype = Object.create(HTMLElement.prototype);
4852 mixin(HTMLShadowElement.prototype, {
4853 // TODO: attribute boolean resetStyleInheritance;
4854 });
4855
4856 if (OriginalHTMLShadowElement)
4857 registerWrapper(OriginalHTMLShadowElement, HTMLShadowElement);
4858
4859 scope.wrappers.HTMLShadowElement = HTMLShadowElement;
4860 })(window.ShadowDOMPolyfill);
4861
4862 // Copyright 2013 The Polymer Authors. All rights reserved.
4863 // Use of this source code is goverened by a BSD-style
4864 // license that can be found in the LICENSE file.
4865
4866 (function(scope) {
4867 'use strict';
4868
4869 var HTMLElement = scope.wrappers.HTMLElement;
4870 var getInnerHTML = scope.getInnerHTML;
4871 var mixin = scope.mixin;
4872 var registerWrapper = scope.registerWrapper;
4873 var setInnerHTML = scope.setInnerHTML;
4874 var unwrap = scope.unwrap;
4875 var wrap = scope.wrap;
4876
4877 var contentTable = new WeakMap();
4878 var templateContentsOwnerTable = new WeakMap();
4879
4880 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html# dfn-template-contents-owner
4881 function getTemplateContentsOwner(doc) {
4882 if (!doc.defaultView)
4883 return doc;
4884 var d = templateContentsOwnerTable.get(doc);
4885 if (!d) {
4886 // TODO(arv): This should either be a Document or HTMLDocument depending
4887 // on doc.
4888 d = doc.implementation.createHTMLDocument('');
4889 while (d.lastChild) {
4890 d.removeChild(d.lastChild);
4891 }
4892 templateContentsOwnerTable.set(doc, d);
4893 }
4894 return d;
4895 }
4896
4897 function extractContent(templateElement) {
4898 // templateElement is not a wrapper here.
4899 var doc = getTemplateContentsOwner(templateElement.ownerDocument);
4900 var df = unwrap(doc.createDocumentFragment());
4901 var child;
4902 while (child = templateElement.firstChild) {
4903 df.appendChild(child);
4904 }
4905 return df;
4906 }
4907
4908 var OriginalHTMLTemplateElement = window.HTMLTemplateElement;
4909
4910 function HTMLTemplateElement(node) {
4911 HTMLElement.call(this, node);
4912 if (!OriginalHTMLTemplateElement) {
4913 var content = extractContent(node);
4914 contentTable.set(this, wrap(content));
4915 }
4916 }
4917 HTMLTemplateElement.prototype = Object.create(HTMLElement.prototype);
4918
4919 mixin(HTMLTemplateElement.prototype, {
4920 get content() {
4921 if (OriginalHTMLTemplateElement)
4922 return wrap(this.impl.content);
4923 return contentTable.get(this);
4924 },
4925
4926 get innerHTML() {
4927 return getInnerHTML(this.content);
4928 },
4929 set innerHTML(value) {
4930 setInnerHTML(this.content, value);
4931 }
4932
4933 // TODO(arv): cloneNode needs to clone content.
4934
4935 });
4936
4937 if (OriginalHTMLTemplateElement)
4938 registerWrapper(OriginalHTMLTemplateElement, HTMLTemplateElement);
4939
4940 scope.wrappers.HTMLTemplateElement = HTMLTemplateElement;
4941 })(window.ShadowDOMPolyfill);
4942
4943 // Copyright 2013 The Polymer Authors. All rights reserved.
4944 // Use of this source code is goverened by a BSD-style
4945 // license that can be found in the LICENSE file.
4946
4947 (function(scope) {
4948 'use strict';
4949
4950 var HTMLElement = scope.wrappers.HTMLElement;
4951 var registerWrapper = scope.registerWrapper;
4952
4953 var OriginalHTMLMediaElement = window.HTMLMediaElement;
4954
4955 function HTMLMediaElement(node) {
4956 HTMLElement.call(this, node);
4957 }
4958 HTMLMediaElement.prototype = Object.create(HTMLElement.prototype);
4959
4960 registerWrapper(OriginalHTMLMediaElement, HTMLMediaElement,
4961 document.createElement('audio'));
4962
4963 scope.wrappers.HTMLMediaElement = HTMLMediaElement;
4964 })(window.ShadowDOMPolyfill);
4965
4966 // Copyright 2013 The Polymer Authors. All rights reserved.
4967 // Use of this source code is goverened by a BSD-style
4968 // license that can be found in the LICENSE file.
4969
4970 (function(scope) {
4971 'use strict';
4972
4973 var HTMLMediaElement = scope.wrappers.HTMLMediaElement;
4974 var registerWrapper = scope.registerWrapper;
4975 var unwrap = scope.unwrap;
4976 var rewrap = scope.rewrap;
4977
4978 var OriginalHTMLAudioElement = window.HTMLAudioElement;
4979
4980 function HTMLAudioElement(node) {
4981 HTMLMediaElement.call(this, node);
4982 }
4983 HTMLAudioElement.prototype = Object.create(HTMLMediaElement.prototype);
4984
4985 registerWrapper(OriginalHTMLAudioElement, HTMLAudioElement,
4986 document.createElement('audio'));
4987
4988 function Audio(src) {
4989 if (!(this instanceof Audio)) {
4990 throw new TypeError(
4991 'DOM object constructor cannot be called as a function.');
4992 }
4993
4994 var node = unwrap(document.createElement('audio'));
4995 HTMLMediaElement.call(this, node);
4996 rewrap(node, this);
4997
4998 node.setAttribute('preload', 'auto');
4999 if (src !== undefined)
5000 node.setAttribute('src', src);
5001 }
5002
5003 Audio.prototype = HTMLAudioElement.prototype;
5004
5005 scope.wrappers.HTMLAudioElement = HTMLAudioElement;
5006 scope.wrappers.Audio = Audio;
5007 })(window.ShadowDOMPolyfill);
5008
5009 // Copyright 2013 The Polymer Authors. All rights reserved.
5010 // Use of this source code is goverened by a BSD-style
5011 // license that can be found in the LICENSE file.
5012
5013 (function(scope) {
5014 'use strict';
5015
5016 var HTMLElement = scope.wrappers.HTMLElement;
5017 var mixin = scope.mixin;
5018 var registerWrapper = scope.registerWrapper;
5019 var rewrap = scope.rewrap;
5020 var unwrap = scope.unwrap;
5021 var wrap = scope.wrap;
5022
5023 var OriginalHTMLOptionElement = window.HTMLOptionElement;
5024
5025 function trimText(s) {
5026 return s.replace(/\s+/g, ' ').trim();
5027 }
5028
5029 function HTMLOptionElement(node) {
5030 HTMLElement.call(this, node);
5031 }
5032 HTMLOptionElement.prototype = Object.create(HTMLElement.prototype);
5033 mixin(HTMLOptionElement.prototype, {
5034 get text() {
5035 return trimText(this.textContent);
5036 },
5037 set text(value) {
5038 this.textContent = trimText(String(value));
5039 },
5040 get form() {
5041 return wrap(unwrap(this).form);
5042 }
5043 });
5044
5045 registerWrapper(OriginalHTMLOptionElement, HTMLOptionElement,
5046 document.createElement('option'));
5047
5048 function Option(text, value, defaultSelected, selected) {
5049 if (!(this instanceof Option)) {
5050 throw new TypeError(
5051 'DOM object constructor cannot be called as a function.');
5052 }
5053
5054 var node = unwrap(document.createElement('option'));
5055 HTMLElement.call(this, node);
5056 rewrap(node, this);
5057
5058 if (text !== undefined)
5059 node.text = text;
5060 if (value !== undefined)
5061 node.setAttribute('value', value);
5062 if (defaultSelected === true)
5063 node.setAttribute('selected', '');
5064 node.selected = selected === true;
5065 }
5066
5067 Option.prototype = HTMLOptionElement.prototype;
5068
5069 scope.wrappers.HTMLOptionElement = HTMLOptionElement;
5070 scope.wrappers.Option = Option;
5071 })(window.ShadowDOMPolyfill);
5072
5073 // Copyright 2013 The Polymer Authors. All rights reserved.
5074 // Use of this source code is goverened by a BSD-style
5075 // license that can be found in the LICENSE file.
5076
5077 (function(scope) {
5078 'use strict';
5079
5080 var HTMLContentElement = scope.wrappers.HTMLContentElement;
5081 var HTMLElement = scope.wrappers.HTMLElement;
5082 var HTMLShadowElement = scope.wrappers.HTMLShadowElement;
5083 var HTMLTemplateElement = scope.wrappers.HTMLTemplateElement;
5084 var mixin = scope.mixin;
5085 var registerWrapper = scope.registerWrapper;
5086
5087 var OriginalHTMLUnknownElement = window.HTMLUnknownElement;
5088
5089 function HTMLUnknownElement(node) {
5090 switch (node.localName) {
5091 case 'content':
5092 return new HTMLContentElement(node);
5093 case 'shadow':
5094 return new HTMLShadowElement(node);
5095 case 'template':
5096 return new HTMLTemplateElement(node);
5097 }
5098 HTMLElement.call(this, node);
5099 }
5100 HTMLUnknownElement.prototype = Object.create(HTMLElement.prototype);
5101 registerWrapper(OriginalHTMLUnknownElement, HTMLUnknownElement);
5102 scope.wrappers.HTMLUnknownElement = HTMLUnknownElement;
5103 })(window.ShadowDOMPolyfill);
5104
5105 // Copyright 2014 The Polymer Authors. All rights reserved.
5106 // Use of this source code is goverened by a BSD-style
5107 // license that can be found in the LICENSE file.
5108
5109 (function(scope) {
5110 'use strict';
5111
5112 var registerObject = scope.registerObject;
5113
5114 var SVG_NS = 'http://www.w3.org/2000/svg';
5115 var svgTitleElement = document.createElementNS(SVG_NS, 'title');
5116 var SVGTitleElement = registerObject(svgTitleElement);
5117 var SVGElement = Object.getPrototypeOf(SVGTitleElement.prototype).constructor;
5118
5119 scope.wrappers.SVGElement = SVGElement;
5120 })(window.ShadowDOMPolyfill);
5121
5122 // Copyright 2014 The Polymer Authors. All rights reserved.
5123 // Use of this source code is goverened by a BSD-style
5124 // license that can be found in the LICENSE file.
5125
5126 (function(scope) {
5127 'use strict';
5128
5129 var mixin = scope.mixin;
5130 var registerWrapper = scope.registerWrapper;
5131 var unwrap = scope.unwrap;
5132 var wrap = scope.wrap;
5133
5134 var OriginalSVGUseElement = window.SVGUseElement;
5135
5136 // IE uses SVGElement as parent interface, SVG2 (Blink & Gecko) uses
5137 // SVGGraphicsElement. Use the <g> element to get the right prototype.
5138
5139 var SVG_NS = 'http://www.w3.org/2000/svg';
5140 var gWrapper = wrap(document.createElementNS(SVG_NS, 'g'));
5141 var useElement = document.createElementNS(SVG_NS, 'use');
5142 var SVGGElement = gWrapper.constructor;
5143 var parentInterfacePrototype = Object.getPrototypeOf(SVGGElement.prototype);
5144 var parentInterface = parentInterfacePrototype.constructor;
5145
5146 function SVGUseElement(impl) {
5147 parentInterface.call(this, impl);
5148 }
5149
5150 SVGUseElement.prototype = Object.create(parentInterfacePrototype);
5151
5152 // Firefox does not expose instanceRoot.
5153 if ('instanceRoot' in useElement) {
5154 mixin(SVGUseElement.prototype, {
5155 get instanceRoot() {
5156 return wrap(unwrap(this).instanceRoot);
5157 },
5158 get animatedInstanceRoot() {
5159 return wrap(unwrap(this).animatedInstanceRoot);
5160 },
5161 });
5162 }
5163
5164 registerWrapper(OriginalSVGUseElement, SVGUseElement, useElement);
5165
5166 scope.wrappers.SVGUseElement = SVGUseElement;
5167 })(window.ShadowDOMPolyfill);
5168
5169 // Copyright 2014 The Polymer Authors. All rights reserved.
5170 // Use of this source code is goverened by a BSD-style
5171 // license that can be found in the LICENSE file.
5172
5173 (function(scope) {
5174 'use strict';
5175
5176 var EventTarget = scope.wrappers.EventTarget;
5177 var mixin = scope.mixin;
5178 var registerWrapper = scope.registerWrapper;
5179 var wrap = scope.wrap;
5180
5181 var OriginalSVGElementInstance = window.SVGElementInstance;
5182 if (!OriginalSVGElementInstance)
5183 return;
5184
5185 function SVGElementInstance(impl) {
5186 EventTarget.call(this, impl);
5187 }
5188
5189 SVGElementInstance.prototype = Object.create(EventTarget.prototype);
5190 mixin(SVGElementInstance.prototype, {
5191 /** @type {SVGElement} */
5192 get correspondingElement() {
5193 return wrap(this.impl.correspondingElement);
5194 },
5195
5196 /** @type {SVGUseElement} */
5197 get correspondingUseElement() {
5198 return wrap(this.impl.correspondingUseElement);
5199 },
5200
5201 /** @type {SVGElementInstance} */
5202 get parentNode() {
5203 return wrap(this.impl.parentNode);
5204 },
5205
5206 /** @type {SVGElementInstanceList} */
5207 get childNodes() {
5208 throw new Error('Not implemented');
5209 },
5210
5211 /** @type {SVGElementInstance} */
5212 get firstChild() {
5213 return wrap(this.impl.firstChild);
5214 },
5215
5216 /** @type {SVGElementInstance} */
5217 get lastChild() {
5218 return wrap(this.impl.lastChild);
5219 },
5220
5221 /** @type {SVGElementInstance} */
5222 get previousSibling() {
5223 return wrap(this.impl.previousSibling);
5224 },
5225
5226 /** @type {SVGElementInstance} */
5227 get nextSibling() {
5228 return wrap(this.impl.nextSibling);
5229 }
5230 });
5231
5232 registerWrapper(OriginalSVGElementInstance, SVGElementInstance);
5233
5234 scope.wrappers.SVGElementInstance = SVGElementInstance;
5235 })(window.ShadowDOMPolyfill);
5236
5237 // Copyright 2013 The Polymer Authors. All rights reserved.
5238 // Use of this source code is goverened by a BSD-style
5239 // license that can be found in the LICENSE file.
5240
5241 (function(scope) {
5242 'use strict';
5243
5244 var mixin = scope.mixin;
5245 var registerWrapper = scope.registerWrapper;
5246 var unwrap = scope.unwrap;
5247 var unwrapIfNeeded = scope.unwrapIfNeeded;
5248 var wrap = scope.wrap;
5249
5250 var OriginalCanvasRenderingContext2D = window.CanvasRenderingContext2D;
5251
5252 function CanvasRenderingContext2D(impl) {
5253 this.impl = impl;
5254 }
5255
5256 mixin(CanvasRenderingContext2D.prototype, {
5257 get canvas() {
5258 return wrap(this.impl.canvas);
5259 },
5260
5261 drawImage: function() {
5262 arguments[0] = unwrapIfNeeded(arguments[0]);
5263 this.impl.drawImage.apply(this.impl, arguments);
5264 },
5265
5266 createPattern: function() {
5267 arguments[0] = unwrap(arguments[0]);
5268 return this.impl.createPattern.apply(this.impl, arguments);
5269 }
5270 });
5271
5272 registerWrapper(OriginalCanvasRenderingContext2D, CanvasRenderingContext2D,
5273 document.createElement('canvas').getContext('2d'));
5274
5275 scope.wrappers.CanvasRenderingContext2D = CanvasRenderingContext2D;
5276 })(window.ShadowDOMPolyfill);
5277
5278 // Copyright 2013 The Polymer Authors. All rights reserved.
5279 // Use of this source code is goverened by a BSD-style
5280 // license that can be found in the LICENSE file.
5281
5282 (function(scope) {
5283 'use strict';
5284
5285 var mixin = scope.mixin;
5286 var registerWrapper = scope.registerWrapper;
5287 var unwrapIfNeeded = scope.unwrapIfNeeded;
5288 var wrap = scope.wrap;
5289
5290 var OriginalWebGLRenderingContext = window.WebGLRenderingContext;
5291
5292 // IE10 does not have WebGL.
5293 if (!OriginalWebGLRenderingContext)
5294 return;
5295
5296 function WebGLRenderingContext(impl) {
5297 this.impl = impl;
5298 }
5299
5300 mixin(WebGLRenderingContext.prototype, {
5301 get canvas() {
5302 return wrap(this.impl.canvas);
5303 },
5304
5305 texImage2D: function() {
5306 arguments[5] = unwrapIfNeeded(arguments[5]);
5307 this.impl.texImage2D.apply(this.impl, arguments);
5308 },
5309
5310 texSubImage2D: function() {
5311 arguments[6] = unwrapIfNeeded(arguments[6]);
5312 this.impl.texSubImage2D.apply(this.impl, arguments);
5313 }
5314 });
5315
5316 // Blink/WebKit has broken DOM bindings. Usually we would create an instance
5317 // of the object and pass it into registerWrapper as a "blueprint" but
5318 // creating WebGL contexts is expensive and might fail so we use a dummy
5319 // object with dummy instance properties for these broken browsers.
5320 var instanceProperties = /WebKit/.test(navigator.userAgent) ?
5321 {drawingBufferHeight: null, drawingBufferWidth: null} : {};
5322
5323 registerWrapper(OriginalWebGLRenderingContext, WebGLRenderingContext,
5324 instanceProperties);
5325
5326 scope.wrappers.WebGLRenderingContext = WebGLRenderingContext;
5327 })(window.ShadowDOMPolyfill);
5328
5329 // Copyright 2013 The Polymer Authors. All rights reserved.
5330 // Use of this source code is goverened by a BSD-style
5331 // license that can be found in the LICENSE file.
5332
5333 (function(scope) {
5334 'use strict';
5335
5336 var registerWrapper = scope.registerWrapper;
5337 var unwrap = scope.unwrap;
5338 var unwrapIfNeeded = scope.unwrapIfNeeded;
5339 var wrap = scope.wrap;
5340
5341 var OriginalRange = window.Range;
5342
5343 function Range(impl) {
5344 this.impl = impl;
5345 }
5346 Range.prototype = {
5347 get startContainer() {
5348 return wrap(this.impl.startContainer);
5349 },
5350 get endContainer() {
5351 return wrap(this.impl.endContainer);
5352 },
5353 get commonAncestorContainer() {
5354 return wrap(this.impl.commonAncestorContainer);
5355 },
5356 setStart: function(refNode,offset) {
5357 this.impl.setStart(unwrapIfNeeded(refNode), offset);
5358 },
5359 setEnd: function(refNode,offset) {
5360 this.impl.setEnd(unwrapIfNeeded(refNode), offset);
5361 },
5362 setStartBefore: function(refNode) {
5363 this.impl.setStartBefore(unwrapIfNeeded(refNode));
5364 },
5365 setStartAfter: function(refNode) {
5366 this.impl.setStartAfter(unwrapIfNeeded(refNode));
5367 },
5368 setEndBefore: function(refNode) {
5369 this.impl.setEndBefore(unwrapIfNeeded(refNode));
5370 },
5371 setEndAfter: function(refNode) {
5372 this.impl.setEndAfter(unwrapIfNeeded(refNode));
5373 },
5374 selectNode: function(refNode) {
5375 this.impl.selectNode(unwrapIfNeeded(refNode));
5376 },
5377 selectNodeContents: function(refNode) {
5378 this.impl.selectNodeContents(unwrapIfNeeded(refNode));
5379 },
5380 compareBoundaryPoints: function(how, sourceRange) {
5381 return this.impl.compareBoundaryPoints(how, unwrap(sourceRange));
5382 },
5383 extractContents: function() {
5384 return wrap(this.impl.extractContents());
5385 },
5386 cloneContents: function() {
5387 return wrap(this.impl.cloneContents());
5388 },
5389 insertNode: function(node) {
5390 this.impl.insertNode(unwrapIfNeeded(node));
5391 },
5392 surroundContents: function(newParent) {
5393 this.impl.surroundContents(unwrapIfNeeded(newParent));
5394 },
5395 cloneRange: function() {
5396 return wrap(this.impl.cloneRange());
5397 },
5398 isPointInRange: function(node, offset) {
5399 return this.impl.isPointInRange(unwrapIfNeeded(node), offset);
5400 },
5401 comparePoint: function(node, offset) {
5402 return this.impl.comparePoint(unwrapIfNeeded(node), offset);
5403 },
5404 intersectsNode: function(node) {
5405 return this.impl.intersectsNode(unwrapIfNeeded(node));
5406 },
5407 toString: function() {
5408 return this.impl.toString();
5409 }
5410 };
5411
5412 // IE9 does not have createContextualFragment.
5413 if (OriginalRange.prototype.createContextualFragment) {
5414 Range.prototype.createContextualFragment = function(html) {
5415 return wrap(this.impl.createContextualFragment(html));
5416 };
5417 }
5418
5419 registerWrapper(window.Range, Range, document.createRange());
5420
5421 scope.wrappers.Range = Range;
5422
5423 })(window.ShadowDOMPolyfill);
5424
5425 // Copyright 2013 The Polymer Authors. All rights reserved.
5426 // Use of this source code is goverened by a BSD-style
5427 // license that can be found in the LICENSE file.
5428
5429 (function(scope) {
5430 'use strict';
5431
5432 var GetElementsByInterface = scope.GetElementsByInterface;
5433 var ParentNodeInterface = scope.ParentNodeInterface;
5434 var SelectorsInterface = scope.SelectorsInterface;
5435 var mixin = scope.mixin;
5436 var registerObject = scope.registerObject;
5437
5438 var DocumentFragment = registerObject(document.createDocumentFragment());
5439 mixin(DocumentFragment.prototype, ParentNodeInterface);
5440 mixin(DocumentFragment.prototype, SelectorsInterface);
5441 mixin(DocumentFragment.prototype, GetElementsByInterface);
5442
5443 var Comment = registerObject(document.createComment(''));
5444
5445 scope.wrappers.Comment = Comment;
5446 scope.wrappers.DocumentFragment = DocumentFragment;
5447
5448 })(window.ShadowDOMPolyfill);
5449
5450 // Copyright 2013 The Polymer Authors. All rights reserved.
5451 // Use of this source code is goverened by a BSD-style
5452 // license that can be found in the LICENSE file.
5453
5454 (function(scope) {
5455 'use strict';
5456
5457 var DocumentFragment = scope.wrappers.DocumentFragment;
5458 var elementFromPoint = scope.elementFromPoint;
5459 var getInnerHTML = scope.getInnerHTML;
5460 var mixin = scope.mixin;
5461 var rewrap = scope.rewrap;
5462 var setInnerHTML = scope.setInnerHTML;
5463 var unwrap = scope.unwrap;
5464
5465 var shadowHostTable = new WeakMap();
5466 var nextOlderShadowTreeTable = new WeakMap();
5467
5468 var spaceCharRe = /[ \t\n\r\f]/;
5469
5470 function ShadowRoot(hostWrapper) {
5471 var node = unwrap(hostWrapper.impl.ownerDocument.createDocumentFragment());
5472 DocumentFragment.call(this, node);
5473
5474 // createDocumentFragment associates the node with a wrapper
5475 // DocumentFragment instance. Override that.
5476 rewrap(node, this);
5477
5478 var oldShadowRoot = hostWrapper.shadowRoot;
5479 nextOlderShadowTreeTable.set(this, oldShadowRoot);
5480
5481 shadowHostTable.set(this, hostWrapper);
5482 }
5483 ShadowRoot.prototype = Object.create(DocumentFragment.prototype);
5484 mixin(ShadowRoot.prototype, {
5485 get innerHTML() {
5486 return getInnerHTML(this);
5487 },
5488 set innerHTML(value) {
5489 setInnerHTML(this, value);
5490 this.invalidateShadowRenderer();
5491 },
5492
5493 get olderShadowRoot() {
5494 return nextOlderShadowTreeTable.get(this) || null;
5495 },
5496
5497 get host() {
5498 return shadowHostTable.get(this) || null;
5499 },
5500
5501 invalidateShadowRenderer: function() {
5502 return shadowHostTable.get(this).invalidateShadowRenderer();
5503 },
5504
5505 elementFromPoint: function(x, y) {
5506 return elementFromPoint(this, this.ownerDocument, x, y);
5507 },
5508
5509 getElementById: function(id) {
5510 if (spaceCharRe.test(id))
5511 return null;
5512 return this.querySelector('[id="' + id + '"]');
5513 }
5514 });
5515
5516 scope.wrappers.ShadowRoot = ShadowRoot;
5517
5518 })(window.ShadowDOMPolyfill);
5519
5520 // Copyright 2013 The Polymer Authors. All rights reserved.
5521 // Use of this source code is governed by a BSD-style
5522 // license that can be found in the LICENSE file.
5523
5524 (function(scope) {
5525 'use strict';
5526
5527 var Element = scope.wrappers.Element;
5528 var HTMLContentElement = scope.wrappers.HTMLContentElement;
5529 var HTMLShadowElement = scope.wrappers.HTMLShadowElement;
5530 var Node = scope.wrappers.Node;
5531 var ShadowRoot = scope.wrappers.ShadowRoot;
5532 var assert = scope.assert;
5533 var mixin = scope.mixin;
5534 var oneOf = scope.oneOf;
5535 var unwrap = scope.unwrap;
5536 var wrap = scope.wrap;
5537
5538 /**
5539 * Updates the fields of a wrapper to a snapshot of the logical DOM as needed.
5540 * Up means parentNode
5541 * Sideways means previous and next sibling.
5542 * @param {!Node} wrapper
5543 */
5544 function updateWrapperUpAndSideways(wrapper) {
5545 wrapper.previousSibling_ = wrapper.previousSibling;
5546 wrapper.nextSibling_ = wrapper.nextSibling;
5547 wrapper.parentNode_ = wrapper.parentNode;
5548 }
5549
5550 /**
5551 * Updates the fields of a wrapper to a snapshot of the logical DOM as needed.
5552 * Down means first and last child
5553 * @param {!Node} wrapper
5554 */
5555 function updateWrapperDown(wrapper) {
5556 wrapper.firstChild_ = wrapper.firstChild;
5557 wrapper.lastChild_ = wrapper.lastChild;
5558 }
5559
5560 function updateAllChildNodes(parentNodeWrapper) {
5561 assert(parentNodeWrapper instanceof Node);
5562 for (var childWrapper = parentNodeWrapper.firstChild;
5563 childWrapper;
5564 childWrapper = childWrapper.nextSibling) {
5565 updateWrapperUpAndSideways(childWrapper);
5566 }
5567 updateWrapperDown(parentNodeWrapper);
5568 }
5569
5570 function insertBefore(parentNodeWrapper, newChildWrapper, refChildWrapper) {
5571 var parentNode = unwrap(parentNodeWrapper);
5572 var newChild = unwrap(newChildWrapper);
5573 var refChild = refChildWrapper ? unwrap(refChildWrapper) : null;
5574
5575 remove(newChildWrapper);
5576 updateWrapperUpAndSideways(newChildWrapper);
5577
5578 if (!refChildWrapper) {
5579 parentNodeWrapper.lastChild_ = parentNodeWrapper.lastChild;
5580 if (parentNodeWrapper.lastChild === parentNodeWrapper.firstChild)
5581 parentNodeWrapper.firstChild_ = parentNodeWrapper.firstChild;
5582
5583 var lastChildWrapper = wrap(parentNode.lastChild);
5584 if (lastChildWrapper)
5585 lastChildWrapper.nextSibling_ = lastChildWrapper.nextSibling;
5586 } else {
5587 if (parentNodeWrapper.firstChild === refChildWrapper)
5588 parentNodeWrapper.firstChild_ = refChildWrapper;
5589
5590 refChildWrapper.previousSibling_ = refChildWrapper.previousSibling;
5591 }
5592
5593 parentNode.insertBefore(newChild, refChild);
5594 }
5595
5596 function remove(nodeWrapper) {
5597 var node = unwrap(nodeWrapper)
5598 var parentNode = node.parentNode;
5599 if (!parentNode)
5600 return;
5601
5602 var parentNodeWrapper = wrap(parentNode);
5603 updateWrapperUpAndSideways(nodeWrapper);
5604
5605 if (nodeWrapper.previousSibling)
5606 nodeWrapper.previousSibling.nextSibling_ = nodeWrapper;
5607 if (nodeWrapper.nextSibling)
5608 nodeWrapper.nextSibling.previousSibling_ = nodeWrapper;
5609
5610 if (parentNodeWrapper.lastChild === nodeWrapper)
5611 parentNodeWrapper.lastChild_ = nodeWrapper;
5612 if (parentNodeWrapper.firstChild === nodeWrapper)
5613 parentNodeWrapper.firstChild_ = nodeWrapper;
5614
5615 parentNode.removeChild(node);
5616 }
5617
5618 var distributedChildNodesTable = new WeakMap();
5619 var eventParentsTable = new WeakMap();
5620 var insertionParentTable = new WeakMap();
5621 var rendererForHostTable = new WeakMap();
5622
5623 function distributeChildToInsertionPoint(child, insertionPoint) {
5624 getDistributedChildNodes(insertionPoint).push(child);
5625 assignToInsertionPoint(child, insertionPoint);
5626
5627 var eventParents = eventParentsTable.get(child);
5628 if (!eventParents)
5629 eventParentsTable.set(child, eventParents = []);
5630 eventParents.push(insertionPoint);
5631 }
5632
5633 function resetDistributedChildNodes(insertionPoint) {
5634 distributedChildNodesTable.set(insertionPoint, []);
5635 }
5636
5637 function getDistributedChildNodes(insertionPoint) {
5638 return distributedChildNodesTable.get(insertionPoint);
5639 }
5640
5641 function getChildNodesSnapshot(node) {
5642 var result = [], i = 0;
5643 for (var child = node.firstChild; child; child = child.nextSibling) {
5644 result[i++] = child;
5645 }
5646 return result;
5647 }
5648
5649 /**
5650 * Visits all nodes in the tree that fulfils the |predicate|. If the |visitor|
5651 * function returns |false| the traversal is aborted.
5652 * @param {!Node} tree
5653 * @param {function(!Node) : boolean} predicate
5654 * @param {function(!Node) : *} visitor
5655 */
5656 function visit(tree, predicate, visitor) {
5657 // This operates on logical DOM.
5658 for (var node = tree.firstChild; node; node = node.nextSibling) {
5659 if (predicate(node)) {
5660 if (visitor(node) === false)
5661 return;
5662 } else {
5663 visit(node, predicate, visitor);
5664 }
5665 }
5666 }
5667
5668 // Matching Insertion Points
5669 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#mat ching-insertion-points
5670
5671 // TODO(arv): Verify this... I don't remember why I picked this regexp.
5672 var selectorMatchRegExp = /^[*.:#[a-zA-Z_|]/;
5673
5674 var allowedPseudoRegExp = new RegExp('^:(' + [
5675 'link',
5676 'visited',
5677 'target',
5678 'enabled',
5679 'disabled',
5680 'checked',
5681 'indeterminate',
5682 'nth-child',
5683 'nth-last-child',
5684 'nth-of-type',
5685 'nth-last-of-type',
5686 'first-child',
5687 'last-child',
5688 'first-of-type',
5689 'last-of-type',
5690 'only-of-type',
5691 ].join('|') + ')');
5692
5693
5694 /**
5695 * @param {Element} node
5696 * @oaram {Element} point The insertion point element.
5697 * @return {boolean} Whether the node matches the insertion point.
5698 */
5699 function matchesCriteria(node, point) {
5700 var select = point.getAttribute('select');
5701 if (!select)
5702 return true;
5703
5704 // Here we know the select attribute is a non empty string.
5705 select = select.trim();
5706 if (!select)
5707 return true;
5708
5709 if (!(node instanceof Element))
5710 return false;
5711
5712 // The native matches function in IE9 does not correctly work with elements
5713 // that are not in the document.
5714 // TODO(arv): Implement matching in JS.
5715 // https://github.com/Polymer/ShadowDOM/issues/361
5716 if (select === '*' || select === node.localName)
5717 return true;
5718
5719 // TODO(arv): This does not seem right. Need to check for a simple selector.
5720 if (!selectorMatchRegExp.test(select))
5721 return false;
5722
5723 // TODO(arv): This no longer matches the spec.
5724 if (select[0] === ':' && !allowedPseudoRegExp.test(select))
5725 return false;
5726
5727 try {
5728 return node.matches(select);
5729 } catch (ex) {
5730 // Invalid selector.
5731 return false;
5732 }
5733 }
5734
5735 var request = oneOf(window, [
5736 'requestAnimationFrame',
5737 'mozRequestAnimationFrame',
5738 'webkitRequestAnimationFrame',
5739 'setTimeout'
5740 ]);
5741
5742 var pendingDirtyRenderers = [];
5743 var renderTimer;
5744
5745 function renderAllPending() {
5746 for (var i = 0; i < pendingDirtyRenderers.length; i++) {
5747 pendingDirtyRenderers[i].render();
5748 }
5749 pendingDirtyRenderers = [];
5750 }
5751
5752 function handleRequestAnimationFrame() {
5753 renderTimer = null;
5754 renderAllPending();
5755 }
5756
5757 /**
5758 * Returns existing shadow renderer for a host or creates it if it is needed.
5759 * @params {!Element} host
5760 * @return {!ShadowRenderer}
5761 */
5762 function getRendererForHost(host) {
5763 var renderer = rendererForHostTable.get(host);
5764 if (!renderer) {
5765 renderer = new ShadowRenderer(host);
5766 rendererForHostTable.set(host, renderer);
5767 }
5768 return renderer;
5769 }
5770
5771 function getShadowRootAncestor(node) {
5772 for (; node; node = node.parentNode) {
5773 if (node instanceof ShadowRoot)
5774 return node;
5775 }
5776 return null;
5777 }
5778
5779 function getRendererForShadowRoot(shadowRoot) {
5780 return getRendererForHost(shadowRoot.host);
5781 }
5782
5783 var spliceDiff = new ArraySplice();
5784 spliceDiff.equals = function(renderNode, rawNode) {
5785 return unwrap(renderNode.node) === rawNode;
5786 };
5787
5788 /**
5789 * RenderNode is used as an in memory "render tree". When we render the
5790 * composed tree we create a tree of RenderNodes, then we diff this against
5791 * the real DOM tree and make minimal changes as needed.
5792 */
5793 function RenderNode(node) {
5794 this.skip = false;
5795 this.node = node;
5796 this.childNodes = [];
5797 }
5798
5799 RenderNode.prototype = {
5800 append: function(node) {
5801 var rv = new RenderNode(node);
5802 this.childNodes.push(rv);
5803 return rv;
5804 },
5805
5806 sync: function(opt_added) {
5807 if (this.skip)
5808 return;
5809
5810 var nodeWrapper = this.node;
5811 // plain array of RenderNodes
5812 var newChildren = this.childNodes;
5813 // plain array of real nodes.
5814 var oldChildren = getChildNodesSnapshot(unwrap(nodeWrapper));
5815 var added = opt_added || new WeakMap();
5816
5817 var splices = spliceDiff.calculateSplices(newChildren, oldChildren);
5818
5819 var newIndex = 0, oldIndex = 0;
5820 var lastIndex = 0;
5821 for (var i = 0; i < splices.length; i++) {
5822 var splice = splices[i];
5823 for (; lastIndex < splice.index; lastIndex++) {
5824 oldIndex++;
5825 newChildren[newIndex++].sync(added);
5826 }
5827
5828 var removedCount = splice.removed.length;
5829 for (var j = 0; j < removedCount; j++) {
5830 var wrapper = wrap(oldChildren[oldIndex++]);
5831 if (!added.get(wrapper))
5832 remove(wrapper);
5833 }
5834
5835 var addedCount = splice.addedCount;
5836 var refNode = oldChildren[oldIndex] && wrap(oldChildren[oldIndex]);
5837 for (var j = 0; j < addedCount; j++) {
5838 var newChildRenderNode = newChildren[newIndex++];
5839 var newChildWrapper = newChildRenderNode.node;
5840 insertBefore(nodeWrapper, newChildWrapper, refNode);
5841
5842 // Keep track of added so that we do not remove the node after it
5843 // has been added.
5844 added.set(newChildWrapper, true);
5845
5846 newChildRenderNode.sync(added);
5847 }
5848
5849 lastIndex += addedCount;
5850 }
5851
5852 for (var i = lastIndex; i < newChildren.length; i++) {
5853 newChildren[i].sync(added);
5854 }
5855 }
5856 };
5857
5858 function ShadowRenderer(host) {
5859 this.host = host;
5860 this.dirty = false;
5861 this.invalidateAttributes();
5862 this.associateNode(host);
5863 }
5864
5865 ShadowRenderer.prototype = {
5866
5867 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#r endering-shadow-trees
5868 render: function(opt_renderNode) {
5869 if (!this.dirty)
5870 return;
5871
5872 this.invalidateAttributes();
5873 this.treeComposition();
5874
5875 var host = this.host;
5876 var shadowRoot = host.shadowRoot;
5877
5878 this.associateNode(host);
5879 var topMostRenderer = !renderNode;
5880 var renderNode = opt_renderNode || new RenderNode(host);
5881
5882 for (var node = shadowRoot.firstChild; node; node = node.nextSibling) {
5883 this.renderNode(shadowRoot, renderNode, node, false);
5884 }
5885
5886 if (topMostRenderer)
5887 renderNode.sync();
5888
5889 this.dirty = false;
5890 },
5891
5892 invalidate: function() {
5893 if (!this.dirty) {
5894 this.dirty = true;
5895 pendingDirtyRenderers.push(this);
5896 if (renderTimer)
5897 return;
5898 renderTimer = window[request](handleRequestAnimationFrame, 0);
5899 }
5900 },
5901
5902 renderNode: function(shadowRoot, renderNode, node, isNested) {
5903 if (isShadowHost(node)) {
5904 renderNode = renderNode.append(node);
5905 var renderer = getRendererForHost(node);
5906 renderer.dirty = true; // Need to rerender due to reprojection.
5907 renderer.render(renderNode);
5908 } else if (isInsertionPoint(node)) {
5909 this.renderInsertionPoint(shadowRoot, renderNode, node, isNested);
5910 } else if (isShadowInsertionPoint(node)) {
5911 this.renderShadowInsertionPoint(shadowRoot, renderNode, node);
5912 } else {
5913 this.renderAsAnyDomTree(shadowRoot, renderNode, node, isNested);
5914 }
5915 },
5916
5917 renderAsAnyDomTree: function(shadowRoot, renderNode, node, isNested) {
5918 renderNode = renderNode.append(node);
5919
5920 if (isShadowHost(node)) {
5921 var renderer = getRendererForHost(node);
5922 renderNode.skip = !renderer.dirty;
5923 renderer.render(renderNode);
5924 } else {
5925 for (var child = node.firstChild; child; child = child.nextSibling) {
5926 this.renderNode(shadowRoot, renderNode, child, isNested);
5927 }
5928 }
5929 },
5930
5931 renderInsertionPoint: function(shadowRoot, renderNode, insertionPoint,
5932 isNested) {
5933 var distributedChildNodes = getDistributedChildNodes(insertionPoint);
5934 if (distributedChildNodes.length) {
5935 this.associateNode(insertionPoint);
5936
5937 for (var i = 0; i < distributedChildNodes.length; i++) {
5938 var child = distributedChildNodes[i];
5939 if (isInsertionPoint(child) && isNested)
5940 this.renderInsertionPoint(shadowRoot, renderNode, child, isNested);
5941 else
5942 this.renderAsAnyDomTree(shadowRoot, renderNode, child, isNested);
5943 }
5944 } else {
5945 this.renderFallbackContent(shadowRoot, renderNode, insertionPoint);
5946 }
5947 this.associateNode(insertionPoint.parentNode);
5948 },
5949
5950 renderShadowInsertionPoint: function(shadowRoot, renderNode,
5951 shadowInsertionPoint) {
5952 var nextOlderTree = shadowRoot.olderShadowRoot;
5953 if (nextOlderTree) {
5954 assignToInsertionPoint(nextOlderTree, shadowInsertionPoint);
5955 this.associateNode(shadowInsertionPoint.parentNode);
5956 for (var node = nextOlderTree.firstChild;
5957 node;
5958 node = node.nextSibling) {
5959 this.renderNode(nextOlderTree, renderNode, node, true);
5960 }
5961 } else {
5962 this.renderFallbackContent(shadowRoot, renderNode,
5963 shadowInsertionPoint);
5964 }
5965 },
5966
5967 renderFallbackContent: function(shadowRoot, renderNode, fallbackHost) {
5968 this.associateNode(fallbackHost);
5969 this.associateNode(fallbackHost.parentNode);
5970 for (var node = fallbackHost.firstChild; node; node = node.nextSibling) {
5971 this.renderAsAnyDomTree(shadowRoot, renderNode, node, false);
5972 }
5973 },
5974
5975 /**
5976 * Invalidates the attributes used to keep track of which attributes may
5977 * cause the renderer to be invalidated.
5978 */
5979 invalidateAttributes: function() {
5980 this.attributes = Object.create(null);
5981 },
5982
5983 /**
5984 * Parses the selector and makes this renderer dependent on the attribute
5985 * being used in the selector.
5986 * @param {string} selector
5987 */
5988 updateDependentAttributes: function(selector) {
5989 if (!selector)
5990 return;
5991
5992 var attributes = this.attributes;
5993
5994 // .class
5995 if (/\.\w+/.test(selector))
5996 attributes['class'] = true;
5997
5998 // #id
5999 if (/#\w+/.test(selector))
6000 attributes['id'] = true;
6001
6002 selector.replace(/\[\s*([^\s=\|~\]]+)/g, function(_, name) {
6003 attributes[name] = true;
6004 });
6005
6006 // Pseudo selectors have been removed from the spec.
6007 },
6008
6009 dependsOnAttribute: function(name) {
6010 return this.attributes[name];
6011 },
6012
6013 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#d fn-distribution-algorithm
6014 distribute: function(tree, pool) {
6015 var self = this;
6016
6017 visit(tree, isActiveInsertionPoint,
6018 function(insertionPoint) {
6019 resetDistributedChildNodes(insertionPoint);
6020 self.updateDependentAttributes(
6021 insertionPoint.getAttribute('select'));
6022
6023 for (var i = 0; i < pool.length; i++) { // 1.2
6024 var node = pool[i]; // 1.2.1
6025 if (node === undefined) // removed
6026 continue;
6027 if (matchesCriteria(node, insertionPoint)) { // 1.2.2
6028 distributeChildToInsertionPoint(node, insertionPoint); // 1.2.2 .1
6029 pool[i] = undefined; // 1.2.2.2
6030 }
6031 }
6032 });
6033 },
6034
6035 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#d fn-tree-composition
6036 treeComposition: function () {
6037 var shadowHost = this.host;
6038 var tree = shadowHost.shadowRoot; // 1.
6039 var pool = []; // 2.
6040
6041 for (var child = shadowHost.firstChild;
6042 child;
6043 child = child.nextSibling) { // 3.
6044 if (isInsertionPoint(child)) { // 3.2.
6045 var reprojected = getDistributedChildNodes(child); // 3.2.1.
6046 // if reprojected is undef... reset it?
6047 if (!reprojected || !reprojected.length) // 3.2.2.
6048 reprojected = getChildNodesSnapshot(child);
6049 pool.push.apply(pool, reprojected); // 3.2.3.
6050 } else {
6051 pool.push(child); // 3.3.
6052 }
6053 }
6054
6055 var shadowInsertionPoint, point;
6056 while (tree) { // 4.
6057 // 4.1.
6058 shadowInsertionPoint = undefined; // Reset every iteration.
6059 visit(tree, isActiveShadowInsertionPoint, function(point) {
6060 shadowInsertionPoint = point;
6061 return false;
6062 });
6063 point = shadowInsertionPoint;
6064
6065 this.distribute(tree, pool); // 4.2.
6066 if (point) { // 4.3.
6067 var nextOlderTree = tree.olderShadowRoot; // 4.3.1.
6068 if (!nextOlderTree) {
6069 break; // 4.3.1.1.
6070 } else {
6071 tree = nextOlderTree; // 4.3.2.2.
6072 assignToInsertionPoint(tree, point); // 4.3.2.2.
6073 continue; // 4.3.2.3.
6074 }
6075 } else {
6076 break; // 4.4.
6077 }
6078 }
6079 },
6080
6081 associateNode: function(node) {
6082 node.impl.polymerShadowRenderer_ = this;
6083 }
6084 };
6085
6086 function isInsertionPoint(node) {
6087 // Should this include <shadow>?
6088 return node instanceof HTMLContentElement;
6089 }
6090
6091 function isActiveInsertionPoint(node) {
6092 // <content> inside another <content> or <shadow> is considered inactive.
6093 return node instanceof HTMLContentElement;
6094 }
6095
6096 function isShadowInsertionPoint(node) {
6097 return node instanceof HTMLShadowElement;
6098 }
6099
6100 function isActiveShadowInsertionPoint(node) {
6101 // <shadow> inside another <content> or <shadow> is considered inactive.
6102 return node instanceof HTMLShadowElement;
6103 }
6104
6105 function isShadowHost(shadowHost) {
6106 return shadowHost.shadowRoot;
6107 }
6108
6109 function getShadowTrees(host) {
6110 var trees = [];
6111
6112 for (var tree = host.shadowRoot; tree; tree = tree.olderShadowRoot) {
6113 trees.push(tree);
6114 }
6115 return trees;
6116 }
6117
6118 function assignToInsertionPoint(tree, point) {
6119 insertionParentTable.set(tree, point);
6120 }
6121
6122 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#ren dering-shadow-trees
6123 function render(host) {
6124 new ShadowRenderer(host).render();
6125 };
6126
6127 // Need to rerender shadow host when:
6128 //
6129 // - a direct child to the ShadowRoot is added or removed
6130 // - a direct child to the host is added or removed
6131 // - a new shadow root is created
6132 // - a direct child to a content/shadow element is added or removed
6133 // - a sibling to a content/shadow element is added or removed
6134 // - content[select] is changed
6135 // - an attribute in a direct child to a host is modified
6136
6137 /**
6138 * This gets called when a node was added or removed to it.
6139 */
6140 Node.prototype.invalidateShadowRenderer = function(force) {
6141 var renderer = this.impl.polymerShadowRenderer_;
6142 if (renderer) {
6143 renderer.invalidate();
6144 return true;
6145 }
6146
6147 return false;
6148 };
6149
6150 HTMLContentElement.prototype.getDistributedNodes = function() {
6151 // TODO(arv): We should only rerender the dirty ancestor renderers (from
6152 // the root and down).
6153 renderAllPending();
6154 return getDistributedChildNodes(this);
6155 };
6156
6157 HTMLShadowElement.prototype.nodeIsInserted_ =
6158 HTMLContentElement.prototype.nodeIsInserted_ = function() {
6159 // Invalidate old renderer if any.
6160 this.invalidateShadowRenderer();
6161
6162 var shadowRoot = getShadowRootAncestor(this);
6163 var renderer;
6164 if (shadowRoot)
6165 renderer = getRendererForShadowRoot(shadowRoot);
6166 this.impl.polymerShadowRenderer_ = renderer;
6167 if (renderer)
6168 renderer.invalidate();
6169 };
6170
6171 scope.eventParentsTable = eventParentsTable;
6172 scope.getRendererForHost = getRendererForHost;
6173 scope.getShadowTrees = getShadowTrees;
6174 scope.insertionParentTable = insertionParentTable;
6175 scope.renderAllPending = renderAllPending;
6176
6177 // Exposed for testing
6178 scope.visual = {
6179 insertBefore: insertBefore,
6180 remove: remove,
6181 };
6182
6183 })(window.ShadowDOMPolyfill);
6184
6185 // Copyright 2013 The Polymer Authors. All rights reserved.
6186 // Use of this source code is goverened by a BSD-style
6187 // license that can be found in the LICENSE file.
6188
6189 (function(scope) {
6190 'use strict';
6191
6192 var HTMLElement = scope.wrappers.HTMLElement;
6193 var assert = scope.assert;
6194 var mixin = scope.mixin;
6195 var registerWrapper = scope.registerWrapper;
6196 var unwrap = scope.unwrap;
6197 var wrap = scope.wrap;
6198
6199 var elementsWithFormProperty = [
6200 'HTMLButtonElement',
6201 'HTMLFieldSetElement',
6202 'HTMLInputElement',
6203 'HTMLKeygenElement',
6204 'HTMLLabelElement',
6205 'HTMLLegendElement',
6206 'HTMLObjectElement',
6207 // HTMLOptionElement is handled in HTMLOptionElement.js
6208 'HTMLOutputElement',
6209 'HTMLSelectElement',
6210 'HTMLTextAreaElement',
6211 ];
6212
6213 function createWrapperConstructor(name) {
6214 if (!window[name])
6215 return;
6216
6217 // Ensure we are not overriding an already existing constructor.
6218 assert(!scope.wrappers[name]);
6219
6220 var GeneratedWrapper = function(node) {
6221 // At this point all of them extend HTMLElement.
6222 HTMLElement.call(this, node);
6223 }
6224 GeneratedWrapper.prototype = Object.create(HTMLElement.prototype);
6225 mixin(GeneratedWrapper.prototype, {
6226 get form() {
6227 return wrap(unwrap(this).form);
6228 },
6229 });
6230
6231 registerWrapper(window[name], GeneratedWrapper,
6232 document.createElement(name.slice(4, -7)));
6233 scope.wrappers[name] = GeneratedWrapper;
6234 }
6235
6236 elementsWithFormProperty.forEach(createWrapperConstructor);
6237
6238 })(window.ShadowDOMPolyfill);
6239
6240 // Copyright 2014 The Polymer Authors. All rights reserved.
6241 // Use of this source code is goverened by a BSD-style
6242 // license that can be found in the LICENSE file.
6243
6244 (function(scope) {
6245 'use strict';
6246
6247 var registerWrapper = scope.registerWrapper;
6248 var unwrap = scope.unwrap;
6249 var unwrapIfNeeded = scope.unwrapIfNeeded;
6250 var wrap = scope.wrap;
6251
6252 var OriginalSelection = window.Selection;
6253
6254 function Selection(impl) {
6255 this.impl = impl;
6256 }
6257 Selection.prototype = {
6258 get anchorNode() {
6259 return wrap(this.impl.anchorNode);
6260 },
6261 get focusNode() {
6262 return wrap(this.impl.focusNode);
6263 },
6264 addRange: function(range) {
6265 this.impl.addRange(unwrap(range));
6266 },
6267 collapse: function(node, index) {
6268 this.impl.collapse(unwrapIfNeeded(node), index);
6269 },
6270 containsNode: function(node, allowPartial) {
6271 return this.impl.containsNode(unwrapIfNeeded(node), allowPartial);
6272 },
6273 extend: function(node, offset) {
6274 this.impl.extend(unwrapIfNeeded(node), offset);
6275 },
6276 getRangeAt: function(index) {
6277 return wrap(this.impl.getRangeAt(index));
6278 },
6279 removeRange: function(range) {
6280 this.impl.removeRange(unwrap(range));
6281 },
6282 selectAllChildren: function(node) {
6283 this.impl.selectAllChildren(unwrapIfNeeded(node));
6284 },
6285 toString: function() {
6286 return this.impl.toString();
6287 }
6288 };
6289
6290 // WebKit extensions. Not implemented.
6291 // readonly attribute Node baseNode;
6292 // readonly attribute long baseOffset;
6293 // readonly attribute Node extentNode;
6294 // readonly attribute long extentOffset;
6295 // [RaisesException] void setBaseAndExtent([Default=Undefined] optional Node b aseNode,
6296 // [Default=Undefined] optional long baseOffset,
6297 // [Default=Undefined] optional Node extentNode,
6298 // [Default=Undefined] optional long extentOffset);
6299 // [RaisesException, ImplementedAs=collapse] void setPosition([Default=Undefin ed] optional Node node,
6300 // [Default=Undefined] optional long offset);
6301
6302 registerWrapper(window.Selection, Selection, window.getSelection());
6303
6304 scope.wrappers.Selection = Selection;
6305
6306 })(window.ShadowDOMPolyfill);
6307
6308 // Copyright 2013 The Polymer Authors. All rights reserved.
6309 // Use of this source code is goverened by a BSD-style
6310 // license that can be found in the LICENSE file.
6311
6312 (function(scope) {
6313 'use strict';
6314
6315 var GetElementsByInterface = scope.GetElementsByInterface;
6316 var Node = scope.wrappers.Node;
6317 var ParentNodeInterface = scope.ParentNodeInterface;
6318 var Selection = scope.wrappers.Selection;
6319 var SelectorsInterface = scope.SelectorsInterface;
6320 var ShadowRoot = scope.wrappers.ShadowRoot;
6321 var defineWrapGetter = scope.defineWrapGetter;
6322 var elementFromPoint = scope.elementFromPoint;
6323 var forwardMethodsToWrapper = scope.forwardMethodsToWrapper;
6324 var matchesNames = scope.matchesNames;
6325 var mixin = scope.mixin;
6326 var registerWrapper = scope.registerWrapper;
6327 var renderAllPending = scope.renderAllPending;
6328 var rewrap = scope.rewrap;
6329 var unwrap = scope.unwrap;
6330 var wrap = scope.wrap;
6331 var wrapEventTargetMethods = scope.wrapEventTargetMethods;
6332 var wrapNodeList = scope.wrapNodeList;
6333
6334 var implementationTable = new WeakMap();
6335
6336 function Document(node) {
6337 Node.call(this, node);
6338 }
6339 Document.prototype = Object.create(Node.prototype);
6340
6341 defineWrapGetter(Document, 'documentElement');
6342
6343 // Conceptually both body and head can be in a shadow but suporting that seems
6344 // overkill at this point.
6345 defineWrapGetter(Document, 'body');
6346 defineWrapGetter(Document, 'head');
6347
6348 // document cannot be overridden so we override a bunch of its methods
6349 // directly on the instance.
6350
6351 function wrapMethod(name) {
6352 var original = document[name];
6353 Document.prototype[name] = function() {
6354 return wrap(original.apply(this.impl, arguments));
6355 };
6356 }
6357
6358 [
6359 'createComment',
6360 'createDocumentFragment',
6361 'createElement',
6362 'createElementNS',
6363 'createEvent',
6364 'createEventNS',
6365 'createRange',
6366 'createTextNode',
6367 'getElementById'
6368 ].forEach(wrapMethod);
6369
6370 var originalAdoptNode = document.adoptNode;
6371
6372 function adoptNodeNoRemove(node, doc) {
6373 originalAdoptNode.call(doc.impl, unwrap(node));
6374 adoptSubtree(node, doc);
6375 }
6376
6377 function adoptSubtree(node, doc) {
6378 if (node.shadowRoot)
6379 doc.adoptNode(node.shadowRoot);
6380 if (node instanceof ShadowRoot)
6381 adoptOlderShadowRoots(node, doc);
6382 for (var child = node.firstChild; child; child = child.nextSibling) {
6383 adoptSubtree(child, doc);
6384 }
6385 }
6386
6387 function adoptOlderShadowRoots(shadowRoot, doc) {
6388 var oldShadowRoot = shadowRoot.olderShadowRoot;
6389 if (oldShadowRoot)
6390 doc.adoptNode(oldShadowRoot);
6391 }
6392
6393 var originalImportNode = document.importNode;
6394 var originalGetSelection = document.getSelection;
6395
6396 mixin(Document.prototype, {
6397 adoptNode: function(node) {
6398 if (node.parentNode)
6399 node.parentNode.removeChild(node);
6400 adoptNodeNoRemove(node, this);
6401 return node;
6402 },
6403 elementFromPoint: function(x, y) {
6404 return elementFromPoint(this, this, x, y);
6405 },
6406 importNode: function(node, deep) {
6407 // We need to manually walk the tree to ensure we do not include rendered
6408 // shadow trees.
6409 var clone = wrap(originalImportNode.call(this.impl, unwrap(node), false));
6410 if (deep) {
6411 for (var child = node.firstChild; child; child = child.nextSibling) {
6412 clone.appendChild(this.importNode(child, true));
6413 }
6414 }
6415 return clone;
6416 },
6417 getSelection: function() {
6418 renderAllPending();
6419 return new Selection(originalGetSelection.call(unwrap(this)));
6420 }
6421 });
6422
6423 if (document.registerElement) {
6424 var originalRegisterElement = document.registerElement;
6425 Document.prototype.registerElement = function(tagName, object) {
6426 var prototype = object.prototype;
6427
6428 // If we already used the object as a prototype for another custom
6429 // element.
6430 if (scope.nativePrototypeTable.get(prototype)) {
6431 // TODO(arv): DOMException
6432 throw new Error('NotSupportedError');
6433 }
6434
6435 // Find first object on the prototype chain that already have a native
6436 // prototype. Keep track of all the objects before that so we can create
6437 // a similar structure for the native case.
6438 var proto = Object.getPrototypeOf(prototype);
6439 var nativePrototype;
6440 var prototypes = [];
6441 while (proto) {
6442 nativePrototype = scope.nativePrototypeTable.get(proto);
6443 if (nativePrototype)
6444 break;
6445 prototypes.push(proto);
6446 proto = Object.getPrototypeOf(proto);
6447 }
6448
6449 if (!nativePrototype) {
6450 // TODO(arv): DOMException
6451 throw new Error('NotSupportedError');
6452 }
6453
6454 // This works by creating a new prototype object that is empty, but has
6455 // the native prototype as its proto. The original prototype object
6456 // passed into register is used as the wrapper prototype.
6457
6458 var newPrototype = Object.create(nativePrototype);
6459 for (var i = prototypes.length - 1; i >= 0; i--) {
6460 newPrototype = Object.create(newPrototype);
6461 }
6462
6463 // Add callbacks if present.
6464 // Names are taken from:
6465 // https://code.google.com/p/chromium/codesearch#chromium/src/third_part y/WebKit/Source/bindings/v8/CustomElementConstructorBuilder.cpp&sq=package:chrom ium&type=cs&l=156
6466 // and not from the spec since the spec is out of date.
6467 [
6468 'createdCallback',
6469 'attachedCallback',
6470 'detachedCallback',
6471 'attributeChangedCallback',
6472 ].forEach(function(name) {
6473 var f = prototype[name];
6474 if (!f)
6475 return;
6476 newPrototype[name] = function() {
6477 // if this element has been wrapped prior to registration,
6478 // the wrapper is stale; in this case rewrap
6479 if (!(wrap(this) instanceof CustomElementConstructor)) {
6480 rewrap(this);
6481 }
6482 f.apply(wrap(this), arguments);
6483 };
6484 });
6485
6486 var p = {prototype: newPrototype};
6487 if (object.extends)
6488 p.extends = object.extends;
6489
6490 function CustomElementConstructor(node) {
6491 if (!node) {
6492 if (object.extends) {
6493 return document.createElement(object.extends, tagName);
6494 } else {
6495 return document.createElement(tagName);
6496 }
6497 }
6498 this.impl = node;
6499 }
6500 CustomElementConstructor.prototype = prototype;
6501 CustomElementConstructor.prototype.constructor = CustomElementConstructor;
6502
6503 scope.constructorTable.set(newPrototype, CustomElementConstructor);
6504 scope.nativePrototypeTable.set(prototype, newPrototype);
6505
6506 // registration is synchronous so do it last
6507 var nativeConstructor = originalRegisterElement.call(unwrap(this),
6508 tagName, p);
6509 return CustomElementConstructor;
6510 };
6511
6512 forwardMethodsToWrapper([
6513 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocume nt
6514 ], [
6515 'registerElement',
6516 ]);
6517 }
6518
6519 // We also override some of the methods on document.body and document.head
6520 // for convenience.
6521 forwardMethodsToWrapper([
6522 window.HTMLBodyElement,
6523 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument
6524 window.HTMLHeadElement,
6525 window.HTMLHtmlElement,
6526 ], [
6527 'appendChild',
6528 'compareDocumentPosition',
6529 'contains',
6530 'getElementsByClassName',
6531 'getElementsByTagName',
6532 'getElementsByTagNameNS',
6533 'insertBefore',
6534 'querySelector',
6535 'querySelectorAll',
6536 'removeChild',
6537 'replaceChild',
6538 ].concat(matchesNames));
6539
6540 forwardMethodsToWrapper([
6541 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument
6542 ], [
6543 'adoptNode',
6544 'importNode',
6545 'contains',
6546 'createComment',
6547 'createDocumentFragment',
6548 'createElement',
6549 'createElementNS',
6550 'createEvent',
6551 'createEventNS',
6552 'createRange',
6553 'createTextNode',
6554 'elementFromPoint',
6555 'getElementById',
6556 'getSelection',
6557 ]);
6558
6559 mixin(Document.prototype, GetElementsByInterface);
6560 mixin(Document.prototype, ParentNodeInterface);
6561 mixin(Document.prototype, SelectorsInterface);
6562
6563 mixin(Document.prototype, {
6564 get implementation() {
6565 var implementation = implementationTable.get(this);
6566 if (implementation)
6567 return implementation;
6568 implementation =
6569 new DOMImplementation(unwrap(this).implementation);
6570 implementationTable.set(this, implementation);
6571 return implementation;
6572 }
6573 });
6574
6575 registerWrapper(window.Document, Document,
6576 document.implementation.createHTMLDocument(''));
6577
6578 // Both WebKit and Gecko uses HTMLDocument for document. HTML5/DOM only has
6579 // one Document interface and IE implements the standard correctly.
6580 if (window.HTMLDocument)
6581 registerWrapper(window.HTMLDocument, Document);
6582
6583 wrapEventTargetMethods([
6584 window.HTMLBodyElement,
6585 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument
6586 window.HTMLHeadElement,
6587 ]);
6588
6589 function DOMImplementation(impl) {
6590 this.impl = impl;
6591 }
6592
6593 function wrapImplMethod(constructor, name) {
6594 var original = document.implementation[name];
6595 constructor.prototype[name] = function() {
6596 return wrap(original.apply(this.impl, arguments));
6597 };
6598 }
6599
6600 function forwardImplMethod(constructor, name) {
6601 var original = document.implementation[name];
6602 constructor.prototype[name] = function() {
6603 return original.apply(this.impl, arguments);
6604 };
6605 }
6606
6607 wrapImplMethod(DOMImplementation, 'createDocumentType');
6608 wrapImplMethod(DOMImplementation, 'createDocument');
6609 wrapImplMethod(DOMImplementation, 'createHTMLDocument');
6610 forwardImplMethod(DOMImplementation, 'hasFeature');
6611
6612 registerWrapper(window.DOMImplementation, DOMImplementation);
6613
6614 forwardMethodsToWrapper([
6615 window.DOMImplementation,
6616 ], [
6617 'createDocumentType',
6618 'createDocument',
6619 'createHTMLDocument',
6620 'hasFeature',
6621 ]);
6622
6623 scope.adoptNodeNoRemove = adoptNodeNoRemove;
6624 scope.wrappers.DOMImplementation = DOMImplementation;
6625 scope.wrappers.Document = Document;
6626
6627 })(window.ShadowDOMPolyfill);
6628
6629 // Copyright 2013 The Polymer Authors. All rights reserved.
6630 // Use of this source code is goverened by a BSD-style
6631 // license that can be found in the LICENSE file.
6632
6633 (function(scope) {
6634 'use strict';
6635
6636 var EventTarget = scope.wrappers.EventTarget;
6637 var Selection = scope.wrappers.Selection;
6638 var mixin = scope.mixin;
6639 var registerWrapper = scope.registerWrapper;
6640 var renderAllPending = scope.renderAllPending;
6641 var unwrap = scope.unwrap;
6642 var unwrapIfNeeded = scope.unwrapIfNeeded;
6643 var wrap = scope.wrap;
6644
6645 var OriginalWindow = window.Window;
6646 var originalGetComputedStyle = window.getComputedStyle;
6647 var originalGetSelection = window.getSelection;
6648
6649 function Window(impl) {
6650 EventTarget.call(this, impl);
6651 }
6652 Window.prototype = Object.create(EventTarget.prototype);
6653
6654 OriginalWindow.prototype.getComputedStyle = function(el, pseudo) {
6655 return wrap(this || window).getComputedStyle(unwrapIfNeeded(el), pseudo);
6656 };
6657
6658 OriginalWindow.prototype.getSelection = function() {
6659 return wrap(this || window).getSelection();
6660 };
6661
6662 // Work around for https://bugzilla.mozilla.org/show_bug.cgi?id=943065
6663 delete window.getComputedStyle;
6664 delete window.getSelection;
6665
6666 ['addEventListener', 'removeEventListener', 'dispatchEvent'].forEach(
6667 function(name) {
6668 OriginalWindow.prototype[name] = function() {
6669 var w = wrap(this || window);
6670 return w[name].apply(w, arguments);
6671 };
6672
6673 // Work around for https://bugzilla.mozilla.org/show_bug.cgi?id=943065
6674 delete window[name];
6675 });
6676
6677 mixin(Window.prototype, {
6678 getComputedStyle: function(el, pseudo) {
6679 renderAllPending();
6680 return originalGetComputedStyle.call(unwrap(this), unwrapIfNeeded(el),
6681 pseudo);
6682 },
6683 getSelection: function() {
6684 renderAllPending();
6685 return new Selection(originalGetSelection.call(unwrap(this)));
6686 },
6687 });
6688
6689 registerWrapper(OriginalWindow, Window);
6690
6691 scope.wrappers.Window = Window;
6692
6693 })(window.ShadowDOMPolyfill);
6694
6695 // Copyright 2013 The Polymer Authors. All rights reserved.
6696 // Use of this source code is goverened by a BSD-style
6697 // license that can be found in the LICENSE file.
6698
6699 (function(scope) {
6700 'use strict';
6701
6702 var isWrapperFor = scope.isWrapperFor;
6703
6704 // This is a list of the elements we currently override the global constructor
6705 // for.
6706 var elements = {
6707 'a': 'HTMLAnchorElement',
6708
6709 // Do not create an applet element by default since it shows a warning in
6710 // IE.
6711 // https://github.com/Polymer/polymer/issues/217
6712 // 'applet': 'HTMLAppletElement',
6713
6714 'area': 'HTMLAreaElement',
6715 'br': 'HTMLBRElement',
6716 'base': 'HTMLBaseElement',
6717 'body': 'HTMLBodyElement',
6718 'button': 'HTMLButtonElement',
6719 // 'command': 'HTMLCommandElement', // Not fully implemented in Gecko.
6720 'dl': 'HTMLDListElement',
6721 'datalist': 'HTMLDataListElement',
6722 'data': 'HTMLDataElement',
6723 'dir': 'HTMLDirectoryElement',
6724 'div': 'HTMLDivElement',
6725 'embed': 'HTMLEmbedElement',
6726 'fieldset': 'HTMLFieldSetElement',
6727 'font': 'HTMLFontElement',
6728 'form': 'HTMLFormElement',
6729 'frame': 'HTMLFrameElement',
6730 'frameset': 'HTMLFrameSetElement',
6731 'hr': 'HTMLHRElement',
6732 'head': 'HTMLHeadElement',
6733 'h1': 'HTMLHeadingElement',
6734 'html': 'HTMLHtmlElement',
6735 'iframe': 'HTMLIFrameElement',
6736 'input': 'HTMLInputElement',
6737 'li': 'HTMLLIElement',
6738 'label': 'HTMLLabelElement',
6739 'legend': 'HTMLLegendElement',
6740 'link': 'HTMLLinkElement',
6741 'map': 'HTMLMapElement',
6742 'marquee': 'HTMLMarqueeElement',
6743 'menu': 'HTMLMenuElement',
6744 'menuitem': 'HTMLMenuItemElement',
6745 'meta': 'HTMLMetaElement',
6746 'meter': 'HTMLMeterElement',
6747 'del': 'HTMLModElement',
6748 'ol': 'HTMLOListElement',
6749 'object': 'HTMLObjectElement',
6750 'optgroup': 'HTMLOptGroupElement',
6751 'option': 'HTMLOptionElement',
6752 'output': 'HTMLOutputElement',
6753 'p': 'HTMLParagraphElement',
6754 'param': 'HTMLParamElement',
6755 'pre': 'HTMLPreElement',
6756 'progress': 'HTMLProgressElement',
6757 'q': 'HTMLQuoteElement',
6758 'script': 'HTMLScriptElement',
6759 'select': 'HTMLSelectElement',
6760 'source': 'HTMLSourceElement',
6761 'span': 'HTMLSpanElement',
6762 'style': 'HTMLStyleElement',
6763 'time': 'HTMLTimeElement',
6764 'caption': 'HTMLTableCaptionElement',
6765 // WebKit and Moz are wrong:
6766 // https://bugs.webkit.org/show_bug.cgi?id=111469
6767 // https://bugzilla.mozilla.org/show_bug.cgi?id=848096
6768 // 'td': 'HTMLTableCellElement',
6769 'col': 'HTMLTableColElement',
6770 'table': 'HTMLTableElement',
6771 'tr': 'HTMLTableRowElement',
6772 'thead': 'HTMLTableSectionElement',
6773 'tbody': 'HTMLTableSectionElement',
6774 'textarea': 'HTMLTextAreaElement',
6775 'track': 'HTMLTrackElement',
6776 'title': 'HTMLTitleElement',
6777 'ul': 'HTMLUListElement',
6778 'video': 'HTMLVideoElement',
6779 };
6780
6781 function overrideConstructor(tagName) {
6782 var nativeConstructorName = elements[tagName];
6783 var nativeConstructor = window[nativeConstructorName];
6784 if (!nativeConstructor)
6785 return;
6786 var element = document.createElement(tagName);
6787 var wrapperConstructor = element.constructor;
6788 window[nativeConstructorName] = wrapperConstructor;
6789 }
6790
6791 Object.keys(elements).forEach(overrideConstructor);
6792
6793 Object.getOwnPropertyNames(scope.wrappers).forEach(function(name) {
6794 window[name] = scope.wrappers[name]
6795 });
6796
6797 // Export for testing.
6798 scope.knownElements = elements;
6799
6800 })(window.ShadowDOMPolyfill);
6801
6802 /*
6803 * Copyright 2013 The Polymer Authors. All rights reserved.
6804 * Use of this source code is governed by a BSD-style
6805 * license that can be found in the LICENSE file.
6806 */
6807 (function() {
6808 var ShadowDOMPolyfill = window.ShadowDOMPolyfill;
6809 var wrap = ShadowDOMPolyfill.wrap;
6810
6811 // patch in prefixed name
6812 Object.defineProperties(HTMLElement.prototype, {
6813 //TODO(sjmiles): review accessor alias with Arv
6814 webkitShadowRoot: {
6815 get: function() {
6816 return this.shadowRoot;
6817 }
6818 }
6819 });
6820
6821 // ShadowCSS needs this:
6822 window.wrap = window.ShadowDOMPolyfill.wrap;
6823 window.unwrap = window.ShadowDOMPolyfill.unwrap;
6824
6825 //TODO(sjmiles): review method alias with Arv
6826 HTMLElement.prototype.webkitCreateShadowRoot =
6827 HTMLElement.prototype.createShadowRoot;
6828
6829 // TODO(jmesserly): we need to wrap document somehow (a dart:html hook?)
6830 window.dartExperimentalFixupGetTag = function(originalGetTag) {
6831 var NodeList = ShadowDOMPolyfill.wrappers.NodeList;
6832 var ShadowRoot = ShadowDOMPolyfill.wrappers.ShadowRoot;
6833 var unwrapIfNeeded = ShadowDOMPolyfill.unwrapIfNeeded;
6834 function getTag(obj) {
6835 // TODO(jmesserly): do we still need these?
6836 if (obj instanceof NodeList) return 'NodeList';
6837 if (obj instanceof ShadowRoot) return 'ShadowRoot';
6838 if (window.MutationRecord && (obj instanceof MutationRecord))
6839 return 'MutationRecord';
6840 if (window.MutationObserver && (obj instanceof MutationObserver))
6841 return 'MutationObserver';
6842
6843 // TODO(jmesserly): this prevents incorrect interaction between ShadowDOM
6844 // and dart:html's <template> polyfill. Essentially, ShadowDOM is
6845 // polyfilling native template, but our Dart polyfill fails to detect this
6846 // because the unwrapped node is an HTMLUnknownElement, leading it to
6847 // think the node has no content.
6848 if (obj instanceof HTMLTemplateElement) return 'HTMLTemplateElement';
6849
6850 var unwrapped = unwrapIfNeeded(obj);
6851 if (obj !== unwrapped) {
6852 // Fix up class names for Firefox.
6853 // For some of them (like HTMLFormElement and HTMLInputElement),
6854 // the "constructor" property of the unwrapped nodes points at the
6855 // same constructor as the wrapper.
6856 var ctor = obj.constructor
6857 if (ctor === unwrapped.constructor) {
6858 var name = ctor._ShadowDOMPolyfill$cacheTag_;
6859 if (!name) {
6860 name = Object.prototype.toString.call(unwrapped);
6861 name = name.substring(8, name.length - 1);
6862 ctor._ShadowDOMPolyfill$cacheTag_ = name;
6863 }
6864 return name;
6865 }
6866
6867 obj = unwrapped;
6868 }
6869 return originalGetTag(obj);
6870 }
6871
6872 return getTag;
6873 };
6874 })();
6875
6876 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
6877 // for details. All rights reserved. Use of this source code is governed by a
6878 // BSD-style license that can be found in the LICENSE file.
6879
6880 var Platform = {};
6881
6882 /*
6883 * Copyright 2012 The Polymer Authors. All rights reserved.
6884 * Use of this source code is governed by a BSD-style
6885 * license that can be found in the LICENSE file.
6886 */
6887
6888 /*
6889 This is a limited shim for ShadowDOM css styling.
6890 https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#style s
6891
6892 The intention here is to support only the styling features which can be
6893 relatively simply implemented. The goal is to allow users to avoid the
6894 most obvious pitfalls and do so without compromising performance significantly .
6895 For ShadowDOM styling that's not covered here, a set of best practices
6896 can be provided that should allow users to accomplish more complex styling.
6897
6898 The following is a list of specific ShadowDOM styling features and a brief
6899 discussion of the approach used to shim.
6900
6901 Shimmed features:
6902
6903 * @host: ShadowDOM allows styling of the shadowRoot's host element using the
6904 @host rule. To shim this feature, the @host styles are reformatted and
6905 prefixed with a given scope name and promoted to a document level stylesheet.
6906 For example, given a scope name of .foo, a rule like this:
6907
6908 @host {
6909 * {
6910 background: red;
6911 }
6912 }
6913
6914 becomes:
6915
6916 .foo {
6917 background: red;
6918 }
6919
6920 * encapsultion: Styles defined within ShadowDOM, apply only to
6921 dom inside the ShadowDOM. Polymer uses one of two techniques to imlement
6922 this feature.
6923
6924 By default, rules are prefixed with the host element tag name
6925 as a descendant selector. This ensures styling does not leak out of the 'top'
6926 of the element's ShadowDOM. For example,
6927
6928 div {
6929 font-weight: bold;
6930 }
6931
6932 becomes:
6933
6934 x-foo div {
6935 font-weight: bold;
6936 }
6937
6938 becomes:
6939
6940
6941 Alternatively, if Platform.ShadowCSS.strictStyling is set to true then
6942 selectors are scoped by adding an attribute selector suffix to each
6943 simple selector that contains the host element tag name. Each element
6944 in the element's ShadowDOM template is also given the scope attribute.
6945 Thus, these rules match only elements that have the scope attribute.
6946 For example, given a scope name of x-foo, a rule like this:
6947
6948 div {
6949 font-weight: bold;
6950 }
6951
6952 becomes:
6953
6954 div[x-foo] {
6955 font-weight: bold;
6956 }
6957
6958 Note that elements that are dynamically added to a scope must have the scope
6959 selector added to them manually.
6960
6961 * ::pseudo: These rules are converted to rules that take advantage of the
6962 pseudo attribute. For example, a shadowRoot like this inside an x-foo
6963
6964 <div pseudo="x-special">Special</div>
6965
6966 with a rule like this:
6967
6968 x-foo::x-special { ... }
6969
6970 becomes:
6971
6972 x-foo [pseudo=x-special] { ... }
6973
6974 * ::part(): These rules are converted to rules that take advantage of the
6975 part attribute. For example, a shadowRoot like this inside an x-foo
6976
6977 <div part="special">Special</div>
6978
6979 with a rule like this:
6980
6981 x-foo::part(special) { ... }
6982
6983 becomes:
6984
6985 x-foo [part=special] { ... }
6986
6987 Unaddressed ShadowDOM styling features:
6988
6989 * upper/lower bound encapsulation: Styles which are defined outside a
6990 shadowRoot should not cross the ShadowDOM boundary and should not apply
6991 inside a shadowRoot.
6992
6993 This styling behavior is not emulated. Some possible ways to do this that
6994 were rejected due to complexity and/or performance concerns include: (1) reset
6995 every possible property for every possible selector for a given scope name;
6996 (2) re-implement css in javascript.
6997
6998 As an alternative, users should make sure to use selectors
6999 specific to the scope in which they are working.
7000
7001 * ::distributed: This behavior is not emulated. It's often not necessary
7002 to style the contents of a specific insertion point and instead, descendants
7003 of the host element can be styled selectively. Users can also create an
7004 extra node around an insertion point and style that node's contents
7005 via descendent selectors. For example, with a shadowRoot like this:
7006
7007 <style>
7008 content::-webkit-distributed(div) {
7009 background: red;
7010 }
7011 </style>
7012 <content></content>
7013
7014 could become:
7015
7016 <style>
7017 / *@polyfill .content-container div * /
7018 content::-webkit-distributed(div) {
7019 background: red;
7020 }
7021 </style>
7022 <div class="content-container">
7023 <content></content>
7024 </div>
7025
7026 Note the use of @polyfill in the comment above a ShadowDOM specific style
7027 declaration. This is a directive to the styling shim to use the selector
7028 in comments in lieu of the next selector when running under polyfill.
7029 */
7030 (function(scope) {
7031
7032 var loader = scope.loader;
7033
7034 var ShadowCSS = {
7035 strictStyling: false,
7036 registry: {},
7037 // Shim styles for a given root associated with a name and extendsName
7038 // 1. cache root styles by name
7039 // 2. optionally tag root nodes with scope name
7040 // 3. shim polyfill directives /* @polyfill */ and /* @polyfill-rule */
7041 // 4. shim @host and scoping
7042 shimStyling: function(root, name, extendsName) {
7043 var typeExtension = this.isTypeExtension(extendsName);
7044 // use caching to make working with styles nodes easier and to facilitate
7045 // lookup of extendee
7046 var def = this.registerDefinition(root, name, extendsName);
7047 // find styles and apply shimming...
7048 if (this.strictStyling) {
7049 this.applyScopeToContent(root, name);
7050 }
7051 var cssText = this.stylesToShimmedCssText(def.rootStyles, def.scopeStyles,
7052 name, typeExtension);
7053 // provide shimmedStyle for user extensibility
7054 def.shimmedStyle = cssTextToStyle(cssText);
7055 if (root) {
7056 root.shimmedStyle = def.shimmedStyle;
7057 }
7058 // remove existing style elements
7059 for (var i=0, l=def.rootStyles.length, s; (i<l) && (s=def.rootStyles[i]);
7060 i++) {
7061 s.parentNode.removeChild(s);
7062 }
7063 // add style to document
7064 addCssToDocument(cssText);
7065 },
7066 // apply @polyfill rules + @host and scope shimming
7067 stylesToShimmedCssText: function(rootStyles, scopeStyles, name,
7068 typeExtension) {
7069 name = name || '';
7070 // insert @polyfill and @polyfill-rule rules into style elements
7071 // scoping process takes care of shimming these
7072 this.insertPolyfillDirectives(rootStyles);
7073 this.insertPolyfillRules(rootStyles);
7074 var cssText = this.shimAtHost(scopeStyles, name, typeExtension) +
7075 this.shimScoping(scopeStyles, name, typeExtension);
7076 // note: we only need to do rootStyles since these are unscoped.
7077 cssText += this.extractPolyfillUnscopedRules(rootStyles);
7078 return cssText;
7079 },
7080 registerDefinition: function(root, name, extendsName) {
7081 var def = this.registry[name] = {
7082 root: root,
7083 name: name,
7084 extendsName: extendsName
7085 }
7086 var styles = root ? root.querySelectorAll('style') : [];
7087 styles = styles ? Array.prototype.slice.call(styles, 0) : [];
7088 def.rootStyles = styles;
7089 def.scopeStyles = def.rootStyles;
7090 var extendee = this.registry[def.extendsName];
7091 if (extendee && (!root || root.querySelector('shadow'))) {
7092 def.scopeStyles = extendee.scopeStyles.concat(def.scopeStyles);
7093 }
7094 return def;
7095 },
7096 isTypeExtension: function(extendsName) {
7097 return extendsName && extendsName.indexOf('-') < 0;
7098 },
7099 applyScopeToContent: function(root, name) {
7100 if (root) {
7101 // add the name attribute to each node in root.
7102 Array.prototype.forEach.call(root.querySelectorAll('*'),
7103 function(node) {
7104 node.setAttribute(name, '');
7105 });
7106 // and template contents too
7107 Array.prototype.forEach.call(root.querySelectorAll('template'),
7108 function(template) {
7109 this.applyScopeToContent(template.content, name);
7110 },
7111 this);
7112 }
7113 },
7114 /*
7115 * Process styles to convert native ShadowDOM rules that will trip
7116 * up the css parser; we rely on decorating the stylesheet with comments.
7117 *
7118 * For example, we convert this rule:
7119 *
7120 * (comment start) @polyfill :host menu-item (comment end)
7121 * shadow::-webkit-distributed(menu-item) {
7122 *
7123 * to this:
7124 *
7125 * scopeName menu-item {
7126 *
7127 **/
7128 insertPolyfillDirectives: function(styles) {
7129 if (styles) {
7130 Array.prototype.forEach.call(styles, function(s) {
7131 s.textContent = this.insertPolyfillDirectivesInCssText(s.textContent);
7132 }, this);
7133 }
7134 },
7135 insertPolyfillDirectivesInCssText: function(cssText) {
7136 return cssText.replace(cssPolyfillCommentRe, function(match, p1) {
7137 // remove end comment delimiter and add block start
7138 return p1.slice(0, -2) + '{';
7139 });
7140 },
7141 /*
7142 * Process styles to add rules which will only apply under the polyfill
7143 *
7144 * For example, we convert this rule:
7145 *
7146 * (comment start) @polyfill-rule :host menu-item {
7147 * ... } (comment end)
7148 *
7149 * to this:
7150 *
7151 * scopeName menu-item {...}
7152 *
7153 **/
7154 insertPolyfillRules: function(styles) {
7155 if (styles) {
7156 Array.prototype.forEach.call(styles, function(s) {
7157 s.textContent = this.insertPolyfillRulesInCssText(s.textContent);
7158 }, this);
7159 }
7160 },
7161 insertPolyfillRulesInCssText: function(cssText) {
7162 return cssText.replace(cssPolyfillRuleCommentRe, function(match, p1) {
7163 // remove end comment delimiter
7164 return p1.slice(0, -1);
7165 });
7166 },
7167 /*
7168 * Process styles to add rules which will only apply under the polyfill
7169 * and do not process via CSSOM. (CSSOM is destructive to rules on rare
7170 * occasions, e.g. -webkit-calc on Safari.)
7171 * For example, we convert this rule:
7172 *
7173 * (comment start) @polyfill-unscoped-rule menu-item {
7174 * ... } (comment end)
7175 *
7176 * to this:
7177 *
7178 * menu-item {...}
7179 *
7180 **/
7181 extractPolyfillUnscopedRules: function(styles) {
7182 var cssText = '';
7183 if (styles) {
7184 Array.prototype.forEach.call(styles, function(s) {
7185 cssText += this.extractPolyfillUnscopedRulesFromCssText(
7186 s.textContent) + '\n\n';
7187 }, this);
7188 }
7189 return cssText;
7190 },
7191 extractPolyfillUnscopedRulesFromCssText: function(cssText) {
7192 var r = '', matches;
7193 while (matches = cssPolyfillUnscopedRuleCommentRe.exec(cssText)) {
7194 r += matches[1].slice(0, -1) + '\n\n';
7195 }
7196 return r;
7197 },
7198 // form: @host { .foo { declarations } }
7199 // becomes: scopeName.foo { declarations }
7200 shimAtHost: function(styles, name, typeExtension) {
7201 if (styles) {
7202 return this.convertAtHostStyles(styles, name, typeExtension);
7203 }
7204 },
7205 convertAtHostStyles: function(styles, name, typeExtension) {
7206 var cssText = stylesToCssText(styles), self = this;
7207 cssText = cssText.replace(hostRuleRe, function(m, p1) {
7208 return self.scopeHostCss(p1, name, typeExtension);
7209 });
7210 cssText = rulesToCss(this.findAtHostRules(cssToRules(cssText),
7211 this.makeScopeMatcher(name, typeExtension)));
7212 return cssText;
7213 },
7214 scopeHostCss: function(cssText, name, typeExtension) {
7215 var self = this;
7216 return cssText.replace(selectorRe, function(m, p1, p2) {
7217 return self.scopeHostSelector(p1, name, typeExtension) + ' ' + p2 + '\n\t' ;
7218 });
7219 },
7220 // supports scopig by name and [is=name] syntax
7221 scopeHostSelector: function(selector, name, typeExtension) {
7222 var r = [], parts = selector.split(','), is = '[is=' + name + ']';
7223 parts.forEach(function(p) {
7224 p = p.trim();
7225 // selector: *|:scope -> name
7226 if (p.match(hostElementRe)) {
7227 p = p.replace(hostElementRe, typeExtension ? is + '$1$3' :
7228 name + '$1$3');
7229 // selector: .foo -> name.foo (OR) [bar] -> name[bar]
7230 } else if (p.match(hostFixableRe)) {
7231 p = typeExtension ? is + p : name + p;
7232 }
7233 r.push(p);
7234 }, this);
7235 return r.join(', ');
7236 },
7237 // consider styles that do not include component name in the selector to be
7238 // unscoped and in need of promotion;
7239 // for convenience, also consider keyframe rules this way.
7240 findAtHostRules: function(cssRules, matcher) {
7241 return Array.prototype.filter.call(cssRules,
7242 this.isHostRule.bind(this, matcher));
7243 },
7244 isHostRule: function(matcher, cssRule) {
7245 return (cssRule.selectorText && cssRule.selectorText.match(matcher)) ||
7246 (cssRule.cssRules && this.findAtHostRules(cssRule.cssRules, matcher).lengt h) ||
7247 (cssRule.type == CSSRule.WEBKIT_KEYFRAMES_RULE);
7248 },
7249 /* Ensure styles are scoped. Pseudo-scoping takes a rule like:
7250 *
7251 * .foo {... }
7252 *
7253 * and converts this to
7254 *
7255 * scopeName .foo { ... }
7256 */
7257 shimScoping: function(styles, name, typeExtension) {
7258 if (styles) {
7259 return this.convertScopedStyles(styles, name, typeExtension);
7260 }
7261 },
7262 convertScopedStyles: function(styles, name, typeExtension) {
7263 var cssText = stylesToCssText(styles).replace(hostRuleRe, '');
7264 cssText = this.insertPolyfillHostInCssText(cssText);
7265 cssText = this.convertColonHost(cssText);
7266 cssText = this.convertColonAncestor(cssText);
7267 // TODO(sorvell): deprecated, remove
7268 cssText = this.convertPseudos(cssText);
7269 // TODO(sorvell): deprecated, remove
7270 cssText = this.convertParts(cssText);
7271 cssText = this.convertCombinators(cssText);
7272 var rules = cssToRules(cssText);
7273 if (name) {
7274 cssText = this.scopeRules(rules, name, typeExtension);
7275 }
7276 return cssText;
7277 },
7278 convertPseudos: function(cssText) {
7279 return cssText.replace(cssPseudoRe, ' [pseudo=$1]');
7280 },
7281 convertParts: function(cssText) {
7282 return cssText.replace(cssPartRe, ' [part=$1]');
7283 },
7284 /*
7285 * convert a rule like :host(.foo) > .bar { }
7286 *
7287 * to
7288 *
7289 * scopeName.foo > .bar
7290 */
7291 convertColonHost: function(cssText) {
7292 return this.convertColonRule(cssText, cssColonHostRe,
7293 this.colonHostPartReplacer);
7294 },
7295 /*
7296 * convert a rule like :ancestor(.foo) > .bar { }
7297 *
7298 * to
7299 *
7300 * scopeName.foo > .bar, .foo scopeName > .bar { }
7301 *
7302 * and
7303 *
7304 * :ancestor(.foo:host) .bar { ... }
7305 *
7306 * to
7307 *
7308 * scopeName.foo .bar { ... }
7309 */
7310 convertColonAncestor: function(cssText) {
7311 return this.convertColonRule(cssText, cssColonAncestorRe,
7312 this.colonAncestorPartReplacer);
7313 },
7314 convertColonRule: function(cssText, regExp, partReplacer) {
7315 // p1 = :host, p2 = contents of (), p3 rest of rule
7316 return cssText.replace(regExp, function(m, p1, p2, p3) {
7317 p1 = polyfillHostNoCombinator;
7318 if (p2) {
7319 var parts = p2.split(','), r = [];
7320 for (var i=0, l=parts.length, p; (i<l) && (p=parts[i]); i++) {
7321 p = p.trim();
7322 r.push(partReplacer(p1, p, p3));
7323 }
7324 return r.join(',');
7325 } else {
7326 return p1 + p3;
7327 }
7328 });
7329 },
7330 colonAncestorPartReplacer: function(host, part, suffix) {
7331 if (part.match(polyfillHost)) {
7332 return this.colonHostPartReplacer(host, part, suffix);
7333 } else {
7334 return host + part + suffix + ', ' + part + ' ' + host + suffix;
7335 }
7336 },
7337 colonHostPartReplacer: function(host, part, suffix) {
7338 return host + part.replace(polyfillHost, '') + suffix;
7339 },
7340 /*
7341 * Convert ^ and ^^ combinators by replacing with space.
7342 */
7343 convertCombinators: function(cssText) {
7344 return cssText.replace(/\^\^/g, ' ').replace(/\^/g, ' ');
7345 },
7346 // change a selector like 'div' to 'name div'
7347 scopeRules: function(cssRules, name, typeExtension) {
7348 var cssText = '';
7349 Array.prototype.forEach.call(cssRules, function(rule) {
7350 if (rule.selectorText && (rule.style && rule.style.cssText)) {
7351 cssText += this.scopeSelector(rule.selectorText, name, typeExtension,
7352 this.strictStyling) + ' {\n\t';
7353 cssText += this.propertiesFromRule(rule) + '\n}\n\n';
7354 } else if (rule.media) {
7355 cssText += '@media ' + rule.media.mediaText + ' {\n';
7356 cssText += this.scopeRules(rule.cssRules, name, typeExtension);
7357 cssText += '\n}\n\n';
7358 } else if (rule.cssText) {
7359 cssText += rule.cssText + '\n\n';
7360 }
7361 }, this);
7362 return cssText;
7363 },
7364 scopeSelector: function(selector, name, typeExtension, strict) {
7365 var r = [], parts = selector.split(',');
7366 parts.forEach(function(p) {
7367 p = p.trim();
7368 if (this.selectorNeedsScoping(p, name, typeExtension)) {
7369 p = (strict && !p.match(polyfillHostNoCombinator)) ?
7370 this.applyStrictSelectorScope(p, name) :
7371 this.applySimpleSelectorScope(p, name, typeExtension);
7372 }
7373 r.push(p);
7374 }, this);
7375 return r.join(', ');
7376 },
7377 selectorNeedsScoping: function(selector, name, typeExtension) {
7378 var re = this.makeScopeMatcher(name, typeExtension);
7379 return !selector.match(re);
7380 },
7381 makeScopeMatcher: function(name, typeExtension) {
7382 var matchScope = typeExtension ? '\\[is=[\'"]?' + name + '[\'"]?\\]' : name;
7383 return new RegExp('^(' + matchScope + ')' + selectorReSuffix, 'm');
7384 },
7385 // scope via name and [is=name]
7386 applySimpleSelectorScope: function(selector, name, typeExtension) {
7387 var scoper = typeExtension ? '[is=' + name + ']' : name;
7388 if (selector.match(polyfillHostRe)) {
7389 selector = selector.replace(polyfillHostNoCombinator, scoper);
7390 return selector.replace(polyfillHostRe, scoper + ' ');
7391 } else {
7392 return scoper + ' ' + selector;
7393 }
7394 },
7395 // return a selector with [name] suffix on each simple selector
7396 // e.g. .foo.bar > .zot becomes .foo[name].bar[name] > .zot[name]
7397 applyStrictSelectorScope: function(selector, name) {
7398 var splits = [' ', '>', '+', '~'],
7399 scoped = selector,
7400 attrName = '[' + name + ']';
7401 splits.forEach(function(sep) {
7402 var parts = scoped.split(sep);
7403 scoped = parts.map(function(p) {
7404 // remove :host since it should be unnecessary
7405 var t = p.trim().replace(polyfillHostRe, '');
7406 if (t && (splits.indexOf(t) < 0) && (t.indexOf(attrName) < 0)) {
7407 p = t.replace(/([^:]*)(:*)(.*)/, '$1' + attrName + '$2$3')
7408 }
7409 return p;
7410 }).join(sep);
7411 });
7412 return scoped;
7413 },
7414 insertPolyfillHostInCssText: function(selector) {
7415 return selector.replace(hostRe, polyfillHost).replace(colonHostRe,
7416 polyfillHost).replace(colonAncestorRe, polyfillAncestor);
7417 },
7418 propertiesFromRule: function(rule) {
7419 // TODO(sorvell): Safari cssom incorrectly removes quotes from the content
7420 // property. (https://bugs.webkit.org/show_bug.cgi?id=118045)
7421 if (rule.style.content && !rule.style.content.match(/['"]+/)) {
7422 return rule.style.cssText.replace(/content:[^;]*;/g, 'content: \'' +
7423 rule.style.content + '\';');
7424 }
7425 return rule.style.cssText;
7426 }
7427 };
7428
7429 var hostRuleRe = /@host[^{]*{(([^}]*?{[^{]*?}[\s\S]*?)+)}/gim,
7430 selectorRe = /([^{]*)({[\s\S]*?})/gim,
7431 hostElementRe = /(.*)((?:\*)|(?:\:scope))(.*)/,
7432 hostFixableRe = /^[.\[:]/,
7433 cssCommentRe = /\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim,
7434 cssPolyfillCommentRe = /\/\*\s*@polyfill ([^*]*\*+([^/*][^*]*\*+)*\/)([^{]*? ){/gim,
7435 cssPolyfillRuleCommentRe = /\/\*\s@polyfill-rule([^*]*\*+([^/*][^*]*\*+)*)\/ /gim,
7436 cssPolyfillUnscopedRuleCommentRe = /\/\*\s@polyfill-unscoped-rule([^*]*\*+([ ^/*][^*]*\*+)*)\//gim,
7437 cssPseudoRe = /::(x-[^\s{,(]*)/gim,
7438 cssPartRe = /::part\(([^)]*)\)/gim,
7439 // note: :host pre-processed to -shadowcsshost.
7440 polyfillHost = '-shadowcsshost',
7441 // note: :ancestor pre-processed to -shadowcssancestor.
7442 polyfillAncestor = '-shadowcssancestor',
7443 parenSuffix = ')(?:\\((' +
7444 '(?:\\([^)(]*\\)|[^)(]*)+?' +
7445 ')\\))?([^,{]*)';
7446 cssColonHostRe = new RegExp('(' + polyfillHost + parenSuffix, 'gim'),
7447 cssColonAncestorRe = new RegExp('(' + polyfillAncestor + parenSuffix, 'gim') ,
7448 selectorReSuffix = '([>\\s~+\[.,{:][\\s\\S]*)?$',
7449 hostRe = /@host/gim,
7450 colonHostRe = /\:host/gim,
7451 colonAncestorRe = /\:ancestor/gim,
7452 /* host name without combinator */
7453 polyfillHostNoCombinator = polyfillHost + '-no-combinator',
7454 polyfillHostRe = new RegExp(polyfillHost, 'gim');
7455 polyfillAncestorRe = new RegExp(polyfillAncestor, 'gim');
7456
7457 function stylesToCssText(styles, preserveComments) {
7458 var cssText = '';
7459 Array.prototype.forEach.call(styles, function(s) {
7460 cssText += s.textContent + '\n\n';
7461 });
7462 // strip comments for easier processing
7463 if (!preserveComments) {
7464 cssText = cssText.replace(cssCommentRe, '');
7465 }
7466 return cssText;
7467 }
7468
7469 function cssTextToStyle(cssText) {
7470 var style = document.createElement('style');
7471 style.textContent = cssText;
7472 return style;
7473 }
7474
7475 function cssToRules(cssText) {
7476 var style = cssTextToStyle(cssText);
7477 document.head.appendChild(style);
7478 var rules = style.sheet.cssRules;
7479 style.parentNode.removeChild(style);
7480 return rules;
7481 }
7482
7483 function rulesToCss(cssRules) {
7484 for (var i=0, css=[]; i < cssRules.length; i++) {
7485 css.push(cssRules[i].cssText);
7486 }
7487 return css.join('\n\n');
7488 }
7489
7490 function addCssToDocument(cssText) {
7491 if (cssText) {
7492 getSheet().appendChild(document.createTextNode(cssText));
7493 }
7494 }
7495
7496 var sheet;
7497 function getSheet() {
7498 if (!sheet) {
7499 sheet = document.createElement("style");
7500 sheet.setAttribute('ShadowCSSShim', '');
7501 sheet.shadowCssShim = true;
7502 }
7503 return sheet;
7504 }
7505
7506 // add polyfill stylesheet to document
7507 if (window.ShadowDOMPolyfill) {
7508 addCssToDocument('style { display: none !important; }\n');
7509 var doc = wrap(document);
7510 var head = doc.querySelector('head');
7511 head.insertBefore(getSheet(), head.childNodes[0]);
7512
7513 document.addEventListener('DOMContentLoaded', function() {
7514 if (window.HTMLImports && !HTMLImports.useNative) {
7515 HTMLImports.importer.preloadSelectors +=
7516 ', link[rel=stylesheet]:not([nopolyfill])';
7517 HTMLImports.parser.parseGeneric = function(elt) {
7518 if (elt.shadowCssShim) {
7519 return;
7520 }
7521 var style = elt;
7522 if (!elt.hasAttribute('nopolyfill')) {
7523 if (elt.__resource) {
7524 style = elt.ownerDocument.createElement('style');
7525 style.textContent = Platform.loader.resolveUrlsInCssText(
7526 elt.__resource, elt.href);
7527 // remove links from main document
7528 if (elt.ownerDocument === doc) {
7529 elt.parentNode.removeChild(elt);
7530 }
7531 } else {
7532 Platform.loader.resolveUrlsInStyle(style);
7533 }
7534 var styles = [style];
7535 style.textContent = ShadowCSS.stylesToShimmedCssText(styles, styles);
7536 style.shadowCssShim = true;
7537 }
7538 // place in document
7539 if (style.parentNode !== head) {
7540 head.appendChild(style);
7541 }
7542 }
7543 }
7544 });
7545 }
7546
7547 // exports
7548 scope.ShadowCSS = ShadowCSS;
7549
7550 })(window.Platform);
7551 }
OLDNEW
« no previous file with comments | « pkg/shadow_dom/REVISIONS ('k') | pkg/shadow_dom/lib/shadow_dom.min.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698