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

Side by Side Diff: src/site/samples/polymer_intl/example/packages/web_components/platform.concat.js

Issue 1387723002: Updating the samples page to reflect the examples that have been retired. (Closed) Base URL: https://github.com/dart-lang/www.dartlang.org.git@master
Patch Set: Created 5 years, 2 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
OLDNEW
(Empty)
1 /**
2 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
3 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
4 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
5 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
6 * Code distributed by Google as part of the polymer project is also
7 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
8 */
9
10 window.Platform = window.Platform || {};
11 // prepopulate window.logFlags if necessary
12 window.logFlags = window.logFlags || {};
13 // process flags
14 (function(scope){
15 // import
16 var flags = scope.flags || {};
17 // populate flags from location
18 location.search.slice(1).split('&').forEach(function(o) {
19 o = o.split('=');
20 o[0] && (flags[o[0]] = o[1] || true);
21 });
22 var entryPoint = document.currentScript ||
23 document.querySelector('script[src*="platform.js"]');
24 if (entryPoint) {
25 var a = entryPoint.attributes;
26 for (var i = 0, n; i < a.length; i++) {
27 n = a[i];
28 if (n.name !== 'src') {
29 flags[n.name] = n.value || true;
30 }
31 }
32 }
33 if (flags.log) {
34 flags.log.split(',').forEach(function(f) {
35 window.logFlags[f] = true;
36 });
37 }
38 // If any of these flags match 'native', then force native ShadowDOM; any
39 // other truthy value, or failure to detect native
40 // ShadowDOM, results in polyfill
41 flags.shadow = flags.shadow || flags.shadowdom || flags.polyfill;
42 if (flags.shadow === 'native') {
43 flags.shadow = false;
44 } else {
45 flags.shadow = flags.shadow || !HTMLElement.prototype.createShadowRoot;
46 }
47
48 if (flags.shadow && document.querySelectorAll('script').length > 1) {
49 console.log('Warning: platform.js is not the first script on the page. ' +
50 'See http://www.polymer-project.org/docs/start/platform.html#setup ' +
51 'for details.');
52 }
53
54 // CustomElements polyfill flag
55 if (flags.register) {
56 window.CustomElements = window.CustomElements || {flags: {}};
57 window.CustomElements.flags.register = flags.register;
58 }
59
60 if (flags.imports) {
61 window.HTMLImports = window.HTMLImports || {flags: {}};
62 window.HTMLImports.flags.imports = flags.imports;
63 }
64
65 // export
66 scope.flags = flags;
67 })(Platform);
68
69 /*
70 * Copyright 2012 The Polymer Authors. All rights reserved.
71 * Use of this source code is governed by a BSD-style
72 * license that can be found in the LICENSE file.
73 */
74
75 if (typeof WeakMap === 'undefined') {
76 (function() {
77 var defineProperty = Object.defineProperty;
78 var counter = Date.now() % 1e9;
79
80 var WeakMap = function() {
81 this.name = '__st' + (Math.random() * 1e9 >>> 0) + (counter++ + '__');
82 };
83
84 WeakMap.prototype = {
85 set: function(key, value) {
86 var entry = key[this.name];
87 if (entry && entry[0] === key)
88 entry[1] = value;
89 else
90 defineProperty(key, this.name, {value: [key, value], writable: true});
91 return this;
92 },
93 get: function(key) {
94 var entry;
95 return (entry = key[this.name]) && entry[0] === key ?
96 entry[1] : undefined;
97 },
98 delete: function(key) {
99 var entry = key[this.name];
100 if (!entry) return false;
101 var hasValue = entry[0] === key;
102 entry[0] = entry[1] = undefined;
103 return hasValue;
104 },
105 has: function(key) {
106 var entry = key[this.name];
107 if (!entry) return false;
108 return entry[0] === key;
109 }
110 };
111
112 window.WeakMap = WeakMap;
113 })();
114 }
115
116 // select ShadowDOM impl
117 if (Platform.flags.shadow) {
118
119 /*
120 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
121 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
122 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
123 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
124 * Code distributed by Google as part of the polymer project is also
125 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
126 */
127
128 (function(global) {
129 'use strict';
130
131 var testingExposeCycleCount = global.testingExposeCycleCount;
132
133 // Detect and do basic sanity checking on Object/Array.observe.
134 function detectObjectObserve() {
135 if (typeof Object.observe !== 'function' ||
136 typeof Array.observe !== 'function') {
137 return false;
138 }
139
140 var records = [];
141
142 function callback(recs) {
143 records = recs;
144 }
145
146 var test = {};
147 var arr = [];
148 Object.observe(test, callback);
149 Array.observe(arr, callback);
150 test.id = 1;
151 test.id = 2;
152 delete test.id;
153 arr.push(1, 2);
154 arr.length = 0;
155
156 Object.deliverChangeRecords(callback);
157 if (records.length !== 5)
158 return false;
159
160 if (records[0].type != 'add' ||
161 records[1].type != 'update' ||
162 records[2].type != 'delete' ||
163 records[3].type != 'splice' ||
164 records[4].type != 'splice') {
165 return false;
166 }
167
168 Object.unobserve(test, callback);
169 Array.unobserve(arr, callback);
170
171 return true;
172 }
173
174 var hasObserve = detectObjectObserve();
175
176 function detectEval() {
177 // Don't test for eval if we're running in a Chrome App environment.
178 // We check for APIs set that only exist in a Chrome App context.
179 if (typeof chrome !== 'undefined' && chrome.app && chrome.app.runtime) {
180 return false;
181 }
182
183 // Firefox OS Apps do not allow eval. This feature detection is very hacky
184 // but even if some other platform adds support for this function this code
185 // will continue to work.
186 if (typeof navigator != 'undefined' && navigator.getDeviceStorage) {
187 return false;
188 }
189
190 try {
191 var f = new Function('', 'return true;');
192 return f();
193 } catch (ex) {
194 return false;
195 }
196 }
197
198 var hasEval = detectEval();
199
200 function isIndex(s) {
201 return +s === s >>> 0 && s !== '';
202 }
203
204 function toNumber(s) {
205 return +s;
206 }
207
208 function isObject(obj) {
209 return obj === Object(obj);
210 }
211
212 var numberIsNaN = global.Number.isNaN || function(value) {
213 return typeof value === 'number' && global.isNaN(value);
214 }
215
216 function areSameValue(left, right) {
217 if (left === right)
218 return left !== 0 || 1 / left === 1 / right;
219 if (numberIsNaN(left) && numberIsNaN(right))
220 return true;
221
222 return left !== left && right !== right;
223 }
224
225 var createObject = ('__proto__' in {}) ?
226 function(obj) { return obj; } :
227 function(obj) {
228 var proto = obj.__proto__;
229 if (!proto)
230 return obj;
231 var newObject = Object.create(proto);
232 Object.getOwnPropertyNames(obj).forEach(function(name) {
233 Object.defineProperty(newObject, name,
234 Object.getOwnPropertyDescriptor(obj, name));
235 });
236 return newObject;
237 };
238
239 var identStart = '[\$_a-zA-Z]';
240 var identPart = '[\$_a-zA-Z0-9]';
241 var identRegExp = new RegExp('^' + identStart + '+' + identPart + '*' + '$');
242
243 function getPathCharType(char) {
244 if (char === undefined)
245 return 'eof';
246
247 var code = char.charCodeAt(0);
248
249 switch(code) {
250 case 0x5B: // [
251 case 0x5D: // ]
252 case 0x2E: // .
253 case 0x22: // "
254 case 0x27: // '
255 case 0x30: // 0
256 return char;
257
258 case 0x5F: // _
259 case 0x24: // $
260 return 'ident';
261
262 case 0x20: // Space
263 case 0x09: // Tab
264 case 0x0A: // Newline
265 case 0x0D: // Return
266 case 0xA0: // No-break space
267 case 0xFEFF: // Byte Order Mark
268 case 0x2028: // Line Separator
269 case 0x2029: // Paragraph Separator
270 return 'ws';
271 }
272
273 // a-z, A-Z
274 if ((0x61 <= code && code <= 0x7A) || (0x41 <= code && code <= 0x5A))
275 return 'ident';
276
277 // 1-9
278 if (0x31 <= code && code <= 0x39)
279 return 'number';
280
281 return 'else';
282 }
283
284 var pathStateMachine = {
285 'beforePath': {
286 'ws': ['beforePath'],
287 'ident': ['inIdent', 'append'],
288 '[': ['beforeElement'],
289 'eof': ['afterPath']
290 },
291
292 'inPath': {
293 'ws': ['inPath'],
294 '.': ['beforeIdent'],
295 '[': ['beforeElement'],
296 'eof': ['afterPath']
297 },
298
299 'beforeIdent': {
300 'ws': ['beforeIdent'],
301 'ident': ['inIdent', 'append']
302 },
303
304 'inIdent': {
305 'ident': ['inIdent', 'append'],
306 '0': ['inIdent', 'append'],
307 'number': ['inIdent', 'append'],
308 'ws': ['inPath', 'push'],
309 '.': ['beforeIdent', 'push'],
310 '[': ['beforeElement', 'push'],
311 'eof': ['afterPath', 'push']
312 },
313
314 'beforeElement': {
315 'ws': ['beforeElement'],
316 '0': ['afterZero', 'append'],
317 'number': ['inIndex', 'append'],
318 "'": ['inSingleQuote', 'append', ''],
319 '"': ['inDoubleQuote', 'append', '']
320 },
321
322 'afterZero': {
323 'ws': ['afterElement', 'push'],
324 ']': ['inPath', 'push']
325 },
326
327 'inIndex': {
328 '0': ['inIndex', 'append'],
329 'number': ['inIndex', 'append'],
330 'ws': ['afterElement'],
331 ']': ['inPath', 'push']
332 },
333
334 'inSingleQuote': {
335 "'": ['afterElement'],
336 'eof': ['error'],
337 'else': ['inSingleQuote', 'append']
338 },
339
340 'inDoubleQuote': {
341 '"': ['afterElement'],
342 'eof': ['error'],
343 'else': ['inDoubleQuote', 'append']
344 },
345
346 'afterElement': {
347 'ws': ['afterElement'],
348 ']': ['inPath', 'push']
349 }
350 }
351
352 function noop() {}
353
354 function parsePath(path) {
355 var keys = [];
356 var index = -1;
357 var c, newChar, key, type, transition, action, typeMap, mode = 'beforePath';
358
359 var actions = {
360 push: function() {
361 if (key === undefined)
362 return;
363
364 keys.push(key);
365 key = undefined;
366 },
367
368 append: function() {
369 if (key === undefined)
370 key = newChar
371 else
372 key += newChar;
373 }
374 };
375
376 function maybeUnescapeQuote() {
377 if (index >= path.length)
378 return;
379
380 var nextChar = path[index + 1];
381 if ((mode == 'inSingleQuote' && nextChar == "'") ||
382 (mode == 'inDoubleQuote' && nextChar == '"')) {
383 index++;
384 newChar = nextChar;
385 actions.append();
386 return true;
387 }
388 }
389
390 while (mode) {
391 index++;
392 c = path[index];
393
394 if (c == '\\' && maybeUnescapeQuote(mode))
395 continue;
396
397 type = getPathCharType(c);
398 typeMap = pathStateMachine[mode];
399 transition = typeMap[type] || typeMap['else'] || 'error';
400
401 if (transition == 'error')
402 return; // parse error;
403
404 mode = transition[0];
405 action = actions[transition[1]] || noop;
406 newChar = transition[2] === undefined ? c : transition[2];
407 action();
408
409 if (mode === 'afterPath') {
410 return keys;
411 }
412 }
413
414 return; // parse error
415 }
416
417 function isIdent(s) {
418 return identRegExp.test(s);
419 }
420
421 var constructorIsPrivate = {};
422
423 function Path(parts, privateToken) {
424 if (privateToken !== constructorIsPrivate)
425 throw Error('Use Path.get to retrieve path objects');
426
427 for (var i = 0; i < parts.length; i++) {
428 this.push(String(parts[i]));
429 }
430
431 if (hasEval && this.length) {
432 this.getValueFrom = this.compiledGetValueFromFn();
433 }
434 }
435
436 // TODO(rafaelw): Make simple LRU cache
437 var pathCache = {};
438
439 function getPath(pathString) {
440 if (pathString instanceof Path)
441 return pathString;
442
443 if (pathString == null || pathString.length == 0)
444 pathString = '';
445
446 if (typeof pathString != 'string') {
447 if (isIndex(pathString.length)) {
448 // Constructed with array-like (pre-parsed) keys
449 return new Path(pathString, constructorIsPrivate);
450 }
451
452 pathString = String(pathString);
453 }
454
455 var path = pathCache[pathString];
456 if (path)
457 return path;
458
459 var parts = parsePath(pathString);
460 if (!parts)
461 return invalidPath;
462
463 var path = new Path(parts, constructorIsPrivate);
464 pathCache[pathString] = path;
465 return path;
466 }
467
468 Path.get = getPath;
469
470 function formatAccessor(key) {
471 if (isIndex(key)) {
472 return '[' + key + ']';
473 } else {
474 return '["' + key.replace(/"/g, '\\"') + '"]';
475 }
476 }
477
478 Path.prototype = createObject({
479 __proto__: [],
480 valid: true,
481
482 toString: function() {
483 var pathString = '';
484 for (var i = 0; i < this.length; i++) {
485 var key = this[i];
486 if (isIdent(key)) {
487 pathString += i ? '.' + key : key;
488 } else {
489 pathString += formatAccessor(key);
490 }
491 }
492
493 return pathString;
494 },
495
496 getValueFrom: function(obj, directObserver) {
497 for (var i = 0; i < this.length; i++) {
498 if (obj == null)
499 return;
500 obj = obj[this[i]];
501 }
502 return obj;
503 },
504
505 iterateObjects: function(obj, observe) {
506 for (var i = 0; i < this.length; i++) {
507 if (i)
508 obj = obj[this[i - 1]];
509 if (!isObject(obj))
510 return;
511 observe(obj, this[0]);
512 }
513 },
514
515 compiledGetValueFromFn: function() {
516 var str = '';
517 var pathString = 'obj';
518 str += 'if (obj != null';
519 var i = 0;
520 var key;
521 for (; i < (this.length - 1); i++) {
522 key = this[i];
523 pathString += isIdent(key) ? '.' + key : formatAccessor(key);
524 str += ' &&\n ' + pathString + ' != null';
525 }
526 str += ')\n';
527
528 var key = this[i];
529 pathString += isIdent(key) ? '.' + key : formatAccessor(key);
530
531 str += ' return ' + pathString + ';\nelse\n return undefined;';
532 return new Function('obj', str);
533 },
534
535 setValueFrom: function(obj, value) {
536 if (!this.length)
537 return false;
538
539 for (var i = 0; i < this.length - 1; i++) {
540 if (!isObject(obj))
541 return false;
542 obj = obj[this[i]];
543 }
544
545 if (!isObject(obj))
546 return false;
547
548 obj[this[i]] = value;
549 return true;
550 }
551 });
552
553 var invalidPath = new Path('', constructorIsPrivate);
554 invalidPath.valid = false;
555 invalidPath.getValueFrom = invalidPath.setValueFrom = function() {};
556
557 var MAX_DIRTY_CHECK_CYCLES = 1000;
558
559 function dirtyCheck(observer) {
560 var cycles = 0;
561 while (cycles < MAX_DIRTY_CHECK_CYCLES && observer.check_()) {
562 cycles++;
563 }
564 if (testingExposeCycleCount)
565 global.dirtyCheckCycleCount = cycles;
566
567 return cycles > 0;
568 }
569
570 function objectIsEmpty(object) {
571 for (var prop in object)
572 return false;
573 return true;
574 }
575
576 function diffIsEmpty(diff) {
577 return objectIsEmpty(diff.added) &&
578 objectIsEmpty(diff.removed) &&
579 objectIsEmpty(diff.changed);
580 }
581
582 function diffObjectFromOldObject(object, oldObject) {
583 var added = {};
584 var removed = {};
585 var changed = {};
586
587 for (var prop in oldObject) {
588 var newValue = object[prop];
589
590 if (newValue !== undefined && newValue === oldObject[prop])
591 continue;
592
593 if (!(prop in object)) {
594 removed[prop] = undefined;
595 continue;
596 }
597
598 if (newValue !== oldObject[prop])
599 changed[prop] = newValue;
600 }
601
602 for (var prop in object) {
603 if (prop in oldObject)
604 continue;
605
606 added[prop] = object[prop];
607 }
608
609 if (Array.isArray(object) && object.length !== oldObject.length)
610 changed.length = object.length;
611
612 return {
613 added: added,
614 removed: removed,
615 changed: changed
616 };
617 }
618
619 var eomTasks = [];
620 function runEOMTasks() {
621 if (!eomTasks.length)
622 return false;
623
624 for (var i = 0; i < eomTasks.length; i++) {
625 eomTasks[i]();
626 }
627 eomTasks.length = 0;
628 return true;
629 }
630
631 var runEOM = hasObserve ? (function(){
632 var eomObj = { pingPong: true };
633 var eomRunScheduled = false;
634
635 Object.observe(eomObj, function() {
636 runEOMTasks();
637 eomRunScheduled = false;
638 });
639
640 return function(fn) {
641 eomTasks.push(fn);
642 if (!eomRunScheduled) {
643 eomRunScheduled = true;
644 eomObj.pingPong = !eomObj.pingPong;
645 }
646 };
647 })() :
648 (function() {
649 return function(fn) {
650 eomTasks.push(fn);
651 };
652 })();
653
654 var observedObjectCache = [];
655
656 function newObservedObject() {
657 var observer;
658 var object;
659 var discardRecords = false;
660 var first = true;
661
662 function callback(records) {
663 if (observer && observer.state_ === OPENED && !discardRecords)
664 observer.check_(records);
665 }
666
667 return {
668 open: function(obs) {
669 if (observer)
670 throw Error('ObservedObject in use');
671
672 if (!first)
673 Object.deliverChangeRecords(callback);
674
675 observer = obs;
676 first = false;
677 },
678 observe: function(obj, arrayObserve) {
679 object = obj;
680 if (arrayObserve)
681 Array.observe(object, callback);
682 else
683 Object.observe(object, callback);
684 },
685 deliver: function(discard) {
686 discardRecords = discard;
687 Object.deliverChangeRecords(callback);
688 discardRecords = false;
689 },
690 close: function() {
691 observer = undefined;
692 Object.unobserve(object, callback);
693 observedObjectCache.push(this);
694 }
695 };
696 }
697
698 /*
699 * The observedSet abstraction is a perf optimization which reduces the total
700 * number of Object.observe observations of a set of objects. The idea is that
701 * groups of Observers will have some object dependencies in common and this
702 * observed set ensures that each object in the transitive closure of
703 * dependencies is only observed once. The observedSet acts as a write barrier
704 * such that whenever any change comes through, all Observers are checked for
705 * changed values.
706 *
707 * Note that this optimization is explicitly moving work from setup-time to
708 * change-time.
709 *
710 * TODO(rafaelw): Implement "garbage collection". In order to move work off
711 * the critical path, when Observers are closed, their observed objects are
712 * not Object.unobserve(d). As a result, it's possible that if the observedSet
713 * is kept open, but some Observers have been closed, it could cause "leaks"
714 * (prevent otherwise collectable objects from being collected). At some
715 * point, we should implement incremental "gc" which keeps a list of
716 * observedSets which may need clean-up and does small amounts of cleanup on a
717 * timeout until all is clean.
718 */
719
720 function getObservedObject(observer, object, arrayObserve) {
721 var dir = observedObjectCache.pop() || newObservedObject();
722 dir.open(observer);
723 dir.observe(object, arrayObserve);
724 return dir;
725 }
726
727 var observedSetCache = [];
728
729 function newObservedSet() {
730 var observerCount = 0;
731 var observers = [];
732 var objects = [];
733 var rootObj;
734 var rootObjProps;
735
736 function observe(obj, prop) {
737 if (!obj)
738 return;
739
740 if (obj === rootObj)
741 rootObjProps[prop] = true;
742
743 if (objects.indexOf(obj) < 0) {
744 objects.push(obj);
745 Object.observe(obj, callback);
746 }
747
748 observe(Object.getPrototypeOf(obj), prop);
749 }
750
751 function allRootObjNonObservedProps(recs) {
752 for (var i = 0; i < recs.length; i++) {
753 var rec = recs[i];
754 if (rec.object !== rootObj ||
755 rootObjProps[rec.name] ||
756 rec.type === 'setPrototype') {
757 return false;
758 }
759 }
760 return true;
761 }
762
763 function callback(recs) {
764 if (allRootObjNonObservedProps(recs))
765 return;
766
767 var observer;
768 for (var i = 0; i < observers.length; i++) {
769 observer = observers[i];
770 if (observer.state_ == OPENED) {
771 observer.iterateObjects_(observe);
772 }
773 }
774
775 for (var i = 0; i < observers.length; i++) {
776 observer = observers[i];
777 if (observer.state_ == OPENED) {
778 observer.check_();
779 }
780 }
781 }
782
783 var record = {
784 object: undefined,
785 objects: objects,
786 open: function(obs, object) {
787 if (!rootObj) {
788 rootObj = object;
789 rootObjProps = {};
790 }
791
792 observers.push(obs);
793 observerCount++;
794 obs.iterateObjects_(observe);
795 },
796 close: function(obs) {
797 observerCount--;
798 if (observerCount > 0) {
799 return;
800 }
801
802 for (var i = 0; i < objects.length; i++) {
803 Object.unobserve(objects[i], callback);
804 Observer.unobservedCount++;
805 }
806
807 observers.length = 0;
808 objects.length = 0;
809 rootObj = undefined;
810 rootObjProps = undefined;
811 observedSetCache.push(this);
812 }
813 };
814
815 return record;
816 }
817
818 var lastObservedSet;
819
820 function getObservedSet(observer, obj) {
821 if (!lastObservedSet || lastObservedSet.object !== obj) {
822 lastObservedSet = observedSetCache.pop() || newObservedSet();
823 lastObservedSet.object = obj;
824 }
825 lastObservedSet.open(observer, obj);
826 return lastObservedSet;
827 }
828
829 var UNOPENED = 0;
830 var OPENED = 1;
831 var CLOSED = 2;
832 var RESETTING = 3;
833
834 var nextObserverId = 1;
835
836 function Observer() {
837 this.state_ = UNOPENED;
838 this.callback_ = undefined;
839 this.target_ = undefined; // TODO(rafaelw): Should be WeakRef
840 this.directObserver_ = undefined;
841 this.value_ = undefined;
842 this.id_ = nextObserverId++;
843 }
844
845 Observer.prototype = {
846 open: function(callback, target) {
847 if (this.state_ != UNOPENED)
848 throw Error('Observer has already been opened.');
849
850 addToAll(this);
851 this.callback_ = callback;
852 this.target_ = target;
853 this.connect_();
854 this.state_ = OPENED;
855 return this.value_;
856 },
857
858 close: function() {
859 if (this.state_ != OPENED)
860 return;
861
862 removeFromAll(this);
863 this.disconnect_();
864 this.value_ = undefined;
865 this.callback_ = undefined;
866 this.target_ = undefined;
867 this.state_ = CLOSED;
868 },
869
870 deliver: function() {
871 if (this.state_ != OPENED)
872 return;
873
874 dirtyCheck(this);
875 },
876
877 report_: function(changes) {
878 try {
879 this.callback_.apply(this.target_, changes);
880 } catch (ex) {
881 Observer._errorThrownDuringCallback = true;
882 console.error('Exception caught during observer callback: ' +
883 (ex.stack || ex));
884 }
885 },
886
887 discardChanges: function() {
888 this.check_(undefined, true);
889 return this.value_;
890 }
891 }
892
893 var collectObservers = !hasObserve;
894 var allObservers;
895 Observer._allObserversCount = 0;
896
897 if (collectObservers) {
898 allObservers = [];
899 }
900
901 function addToAll(observer) {
902 Observer._allObserversCount++;
903 if (!collectObservers)
904 return;
905
906 allObservers.push(observer);
907 }
908
909 function removeFromAll(observer) {
910 Observer._allObserversCount--;
911 }
912
913 var runningMicrotaskCheckpoint = false;
914
915 global.Platform = global.Platform || {};
916
917 global.Platform.performMicrotaskCheckpoint = function() {
918 if (runningMicrotaskCheckpoint)
919 return;
920
921 if (!collectObservers)
922 return;
923
924 runningMicrotaskCheckpoint = true;
925
926 var cycles = 0;
927 var anyChanged, toCheck;
928
929 do {
930 cycles++;
931 toCheck = allObservers;
932 allObservers = [];
933 anyChanged = false;
934
935 for (var i = 0; i < toCheck.length; i++) {
936 var observer = toCheck[i];
937 if (observer.state_ != OPENED)
938 continue;
939
940 if (observer.check_())
941 anyChanged = true;
942
943 allObservers.push(observer);
944 }
945 if (runEOMTasks())
946 anyChanged = true;
947 } while (cycles < MAX_DIRTY_CHECK_CYCLES && anyChanged);
948
949 if (testingExposeCycleCount)
950 global.dirtyCheckCycleCount = cycles;
951
952 runningMicrotaskCheckpoint = false;
953 };
954
955 if (collectObservers) {
956 global.Platform.clearObservers = function() {
957 allObservers = [];
958 };
959 }
960
961 function ObjectObserver(object) {
962 Observer.call(this);
963 this.value_ = object;
964 this.oldObject_ = undefined;
965 }
966
967 ObjectObserver.prototype = createObject({
968 __proto__: Observer.prototype,
969
970 arrayObserve: false,
971
972 connect_: function(callback, target) {
973 if (hasObserve) {
974 this.directObserver_ = getObservedObject(this, this.value_,
975 this.arrayObserve);
976 } else {
977 this.oldObject_ = this.copyObject(this.value_);
978 }
979
980 },
981
982 copyObject: function(object) {
983 var copy = Array.isArray(object) ? [] : {};
984 for (var prop in object) {
985 copy[prop] = object[prop];
986 };
987 if (Array.isArray(object))
988 copy.length = object.length;
989 return copy;
990 },
991
992 check_: function(changeRecords, skipChanges) {
993 var diff;
994 var oldValues;
995 if (hasObserve) {
996 if (!changeRecords)
997 return false;
998
999 oldValues = {};
1000 diff = diffObjectFromChangeRecords(this.value_, changeRecords,
1001 oldValues);
1002 } else {
1003 oldValues = this.oldObject_;
1004 diff = diffObjectFromOldObject(this.value_, this.oldObject_);
1005 }
1006
1007 if (diffIsEmpty(diff))
1008 return false;
1009
1010 if (!hasObserve)
1011 this.oldObject_ = this.copyObject(this.value_);
1012
1013 this.report_([
1014 diff.added || {},
1015 diff.removed || {},
1016 diff.changed || {},
1017 function(property) {
1018 return oldValues[property];
1019 }
1020 ]);
1021
1022 return true;
1023 },
1024
1025 disconnect_: function() {
1026 if (hasObserve) {
1027 this.directObserver_.close();
1028 this.directObserver_ = undefined;
1029 } else {
1030 this.oldObject_ = undefined;
1031 }
1032 },
1033
1034 deliver: function() {
1035 if (this.state_ != OPENED)
1036 return;
1037
1038 if (hasObserve)
1039 this.directObserver_.deliver(false);
1040 else
1041 dirtyCheck(this);
1042 },
1043
1044 discardChanges: function() {
1045 if (this.directObserver_)
1046 this.directObserver_.deliver(true);
1047 else
1048 this.oldObject_ = this.copyObject(this.value_);
1049
1050 return this.value_;
1051 }
1052 });
1053
1054 function ArrayObserver(array) {
1055 if (!Array.isArray(array))
1056 throw Error('Provided object is not an Array');
1057 ObjectObserver.call(this, array);
1058 }
1059
1060 ArrayObserver.prototype = createObject({
1061
1062 __proto__: ObjectObserver.prototype,
1063
1064 arrayObserve: true,
1065
1066 copyObject: function(arr) {
1067 return arr.slice();
1068 },
1069
1070 check_: function(changeRecords) {
1071 var splices;
1072 if (hasObserve) {
1073 if (!changeRecords)
1074 return false;
1075 splices = projectArraySplices(this.value_, changeRecords);
1076 } else {
1077 splices = calcSplices(this.value_, 0, this.value_.length,
1078 this.oldObject_, 0, this.oldObject_.length);
1079 }
1080
1081 if (!splices || !splices.length)
1082 return false;
1083
1084 if (!hasObserve)
1085 this.oldObject_ = this.copyObject(this.value_);
1086
1087 this.report_([splices]);
1088 return true;
1089 }
1090 });
1091
1092 ArrayObserver.applySplices = function(previous, current, splices) {
1093 splices.forEach(function(splice) {
1094 var spliceArgs = [splice.index, splice.removed.length];
1095 var addIndex = splice.index;
1096 while (addIndex < splice.index + splice.addedCount) {
1097 spliceArgs.push(current[addIndex]);
1098 addIndex++;
1099 }
1100
1101 Array.prototype.splice.apply(previous, spliceArgs);
1102 });
1103 };
1104
1105 function PathObserver(object, path) {
1106 Observer.call(this);
1107
1108 this.object_ = object;
1109 this.path_ = getPath(path);
1110 this.directObserver_ = undefined;
1111 }
1112
1113 PathObserver.prototype = createObject({
1114 __proto__: Observer.prototype,
1115
1116 get path() {
1117 return this.path_;
1118 },
1119
1120 connect_: function() {
1121 if (hasObserve)
1122 this.directObserver_ = getObservedSet(this, this.object_);
1123
1124 this.check_(undefined, true);
1125 },
1126
1127 disconnect_: function() {
1128 this.value_ = undefined;
1129
1130 if (this.directObserver_) {
1131 this.directObserver_.close(this);
1132 this.directObserver_ = undefined;
1133 }
1134 },
1135
1136 iterateObjects_: function(observe) {
1137 this.path_.iterateObjects(this.object_, observe);
1138 },
1139
1140 check_: function(changeRecords, skipChanges) {
1141 var oldValue = this.value_;
1142 this.value_ = this.path_.getValueFrom(this.object_);
1143 if (skipChanges || areSameValue(this.value_, oldValue))
1144 return false;
1145
1146 this.report_([this.value_, oldValue, this]);
1147 return true;
1148 },
1149
1150 setValue: function(newValue) {
1151 if (this.path_)
1152 this.path_.setValueFrom(this.object_, newValue);
1153 }
1154 });
1155
1156 function CompoundObserver(reportChangesOnOpen) {
1157 Observer.call(this);
1158
1159 this.reportChangesOnOpen_ = reportChangesOnOpen;
1160 this.value_ = [];
1161 this.directObserver_ = undefined;
1162 this.observed_ = [];
1163 }
1164
1165 var observerSentinel = {};
1166
1167 CompoundObserver.prototype = createObject({
1168 __proto__: Observer.prototype,
1169
1170 connect_: function() {
1171 if (hasObserve) {
1172 var object;
1173 var needsDirectObserver = false;
1174 for (var i = 0; i < this.observed_.length; i += 2) {
1175 object = this.observed_[i]
1176 if (object !== observerSentinel) {
1177 needsDirectObserver = true;
1178 break;
1179 }
1180 }
1181
1182 if (needsDirectObserver)
1183 this.directObserver_ = getObservedSet(this, object);
1184 }
1185
1186 this.check_(undefined, !this.reportChangesOnOpen_);
1187 },
1188
1189 disconnect_: function() {
1190 for (var i = 0; i < this.observed_.length; i += 2) {
1191 if (this.observed_[i] === observerSentinel)
1192 this.observed_[i + 1].close();
1193 }
1194 this.observed_.length = 0;
1195 this.value_.length = 0;
1196
1197 if (this.directObserver_) {
1198 this.directObserver_.close(this);
1199 this.directObserver_ = undefined;
1200 }
1201 },
1202
1203 addPath: function(object, path) {
1204 if (this.state_ != UNOPENED && this.state_ != RESETTING)
1205 throw Error('Cannot add paths once started.');
1206
1207 var path = getPath(path);
1208 this.observed_.push(object, path);
1209 if (!this.reportChangesOnOpen_)
1210 return;
1211 var index = this.observed_.length / 2 - 1;
1212 this.value_[index] = path.getValueFrom(object);
1213 },
1214
1215 addObserver: function(observer) {
1216 if (this.state_ != UNOPENED && this.state_ != RESETTING)
1217 throw Error('Cannot add observers once started.');
1218
1219 this.observed_.push(observerSentinel, observer);
1220 if (!this.reportChangesOnOpen_)
1221 return;
1222 var index = this.observed_.length / 2 - 1;
1223 this.value_[index] = observer.open(this.deliver, this);
1224 },
1225
1226 startReset: function() {
1227 if (this.state_ != OPENED)
1228 throw Error('Can only reset while open');
1229
1230 this.state_ = RESETTING;
1231 this.disconnect_();
1232 },
1233
1234 finishReset: function() {
1235 if (this.state_ != RESETTING)
1236 throw Error('Can only finishReset after startReset');
1237 this.state_ = OPENED;
1238 this.connect_();
1239
1240 return this.value_;
1241 },
1242
1243 iterateObjects_: function(observe) {
1244 var object;
1245 for (var i = 0; i < this.observed_.length; i += 2) {
1246 object = this.observed_[i]
1247 if (object !== observerSentinel)
1248 this.observed_[i + 1].iterateObjects(object, observe)
1249 }
1250 },
1251
1252 check_: function(changeRecords, skipChanges) {
1253 var oldValues;
1254 for (var i = 0; i < this.observed_.length; i += 2) {
1255 var object = this.observed_[i];
1256 var path = this.observed_[i+1];
1257 var value;
1258 if (object === observerSentinel) {
1259 var observable = path;
1260 value = this.state_ === UNOPENED ?
1261 observable.open(this.deliver, this) :
1262 observable.discardChanges();
1263 } else {
1264 value = path.getValueFrom(object);
1265 }
1266
1267 if (skipChanges) {
1268 this.value_[i / 2] = value;
1269 continue;
1270 }
1271
1272 if (areSameValue(value, this.value_[i / 2]))
1273 continue;
1274
1275 oldValues = oldValues || [];
1276 oldValues[i / 2] = this.value_[i / 2];
1277 this.value_[i / 2] = value;
1278 }
1279
1280 if (!oldValues)
1281 return false;
1282
1283 // TODO(rafaelw): Having observed_ as the third callback arg here is
1284 // pretty lame API. Fix.
1285 this.report_([this.value_, oldValues, this.observed_]);
1286 return true;
1287 }
1288 });
1289
1290 function identFn(value) { return value; }
1291
1292 function ObserverTransform(observable, getValueFn, setValueFn,
1293 dontPassThroughSet) {
1294 this.callback_ = undefined;
1295 this.target_ = undefined;
1296 this.value_ = undefined;
1297 this.observable_ = observable;
1298 this.getValueFn_ = getValueFn || identFn;
1299 this.setValueFn_ = setValueFn || identFn;
1300 // TODO(rafaelw): This is a temporary hack. PolymerExpressions needs this
1301 // at the moment because of a bug in it's dependency tracking.
1302 this.dontPassThroughSet_ = dontPassThroughSet;
1303 }
1304
1305 ObserverTransform.prototype = {
1306 open: function(callback, target) {
1307 this.callback_ = callback;
1308 this.target_ = target;
1309 this.value_ =
1310 this.getValueFn_(this.observable_.open(this.observedCallback_, this));
1311 return this.value_;
1312 },
1313
1314 observedCallback_: function(value) {
1315 value = this.getValueFn_(value);
1316 if (areSameValue(value, this.value_))
1317 return;
1318 var oldValue = this.value_;
1319 this.value_ = value;
1320 this.callback_.call(this.target_, this.value_, oldValue);
1321 },
1322
1323 discardChanges: function() {
1324 this.value_ = this.getValueFn_(this.observable_.discardChanges());
1325 return this.value_;
1326 },
1327
1328 deliver: function() {
1329 return this.observable_.deliver();
1330 },
1331
1332 setValue: function(value) {
1333 value = this.setValueFn_(value);
1334 if (!this.dontPassThroughSet_ && this.observable_.setValue)
1335 return this.observable_.setValue(value);
1336 },
1337
1338 close: function() {
1339 if (this.observable_)
1340 this.observable_.close();
1341 this.callback_ = undefined;
1342 this.target_ = undefined;
1343 this.observable_ = undefined;
1344 this.value_ = undefined;
1345 this.getValueFn_ = undefined;
1346 this.setValueFn_ = undefined;
1347 }
1348 }
1349
1350 var expectedRecordTypes = {
1351 add: true,
1352 update: true,
1353 delete: true
1354 };
1355
1356 function diffObjectFromChangeRecords(object, changeRecords, oldValues) {
1357 var added = {};
1358 var removed = {};
1359
1360 for (var i = 0; i < changeRecords.length; i++) {
1361 var record = changeRecords[i];
1362 if (!expectedRecordTypes[record.type]) {
1363 console.error('Unknown changeRecord type: ' + record.type);
1364 console.error(record);
1365 continue;
1366 }
1367
1368 if (!(record.name in oldValues))
1369 oldValues[record.name] = record.oldValue;
1370
1371 if (record.type == 'update')
1372 continue;
1373
1374 if (record.type == 'add') {
1375 if (record.name in removed)
1376 delete removed[record.name];
1377 else
1378 added[record.name] = true;
1379
1380 continue;
1381 }
1382
1383 // type = 'delete'
1384 if (record.name in added) {
1385 delete added[record.name];
1386 delete oldValues[record.name];
1387 } else {
1388 removed[record.name] = true;
1389 }
1390 }
1391
1392 for (var prop in added)
1393 added[prop] = object[prop];
1394
1395 for (var prop in removed)
1396 removed[prop] = undefined;
1397
1398 var changed = {};
1399 for (var prop in oldValues) {
1400 if (prop in added || prop in removed)
1401 continue;
1402
1403 var newValue = object[prop];
1404 if (oldValues[prop] !== newValue)
1405 changed[prop] = newValue;
1406 }
1407
1408 return {
1409 added: added,
1410 removed: removed,
1411 changed: changed
1412 };
1413 }
1414
1415 function newSplice(index, removed, addedCount) {
1416 return {
1417 index: index,
1418 removed: removed,
1419 addedCount: addedCount
1420 };
1421 }
1422
1423 var EDIT_LEAVE = 0;
1424 var EDIT_UPDATE = 1;
1425 var EDIT_ADD = 2;
1426 var EDIT_DELETE = 3;
1427
1428 function ArraySplice() {}
1429
1430 ArraySplice.prototype = {
1431
1432 // Note: This function is *based* on the computation of the Levenshtein
1433 // "edit" distance. The one change is that "updates" are treated as two
1434 // edits - not one. With Array splices, an update is really a delete
1435 // followed by an add. By retaining this, we optimize for "keeping" the
1436 // maximum array items in the original array. For example:
1437 //
1438 // 'xxxx123' -> '123yyyy'
1439 //
1440 // With 1-edit updates, the shortest path would be just to update all seven
1441 // characters. With 2-edit updates, we delete 4, leave 3, and add 4. This
1442 // leaves the substring '123' intact.
1443 calcEditDistances: function(current, currentStart, currentEnd,
1444 old, oldStart, oldEnd) {
1445 // "Deletion" columns
1446 var rowCount = oldEnd - oldStart + 1;
1447 var columnCount = currentEnd - currentStart + 1;
1448 var distances = new Array(rowCount);
1449
1450 // "Addition" rows. Initialize null column.
1451 for (var i = 0; i < rowCount; i++) {
1452 distances[i] = new Array(columnCount);
1453 distances[i][0] = i;
1454 }
1455
1456 // Initialize null row
1457 for (var j = 0; j < columnCount; j++)
1458 distances[0][j] = j;
1459
1460 for (var i = 1; i < rowCount; i++) {
1461 for (var j = 1; j < columnCount; j++) {
1462 if (this.equals(current[currentStart + j - 1], old[oldStart + i - 1]))
1463 distances[i][j] = distances[i - 1][j - 1];
1464 else {
1465 var north = distances[i - 1][j] + 1;
1466 var west = distances[i][j - 1] + 1;
1467 distances[i][j] = north < west ? north : west;
1468 }
1469 }
1470 }
1471
1472 return distances;
1473 },
1474
1475 // This starts at the final weight, and walks "backward" by finding
1476 // the minimum previous weight recursively until the origin of the weight
1477 // matrix.
1478 spliceOperationsFromEditDistances: function(distances) {
1479 var i = distances.length - 1;
1480 var j = distances[0].length - 1;
1481 var current = distances[i][j];
1482 var edits = [];
1483 while (i > 0 || j > 0) {
1484 if (i == 0) {
1485 edits.push(EDIT_ADD);
1486 j--;
1487 continue;
1488 }
1489 if (j == 0) {
1490 edits.push(EDIT_DELETE);
1491 i--;
1492 continue;
1493 }
1494 var northWest = distances[i - 1][j - 1];
1495 var west = distances[i - 1][j];
1496 var north = distances[i][j - 1];
1497
1498 var min;
1499 if (west < north)
1500 min = west < northWest ? west : northWest;
1501 else
1502 min = north < northWest ? north : northWest;
1503
1504 if (min == northWest) {
1505 if (northWest == current) {
1506 edits.push(EDIT_LEAVE);
1507 } else {
1508 edits.push(EDIT_UPDATE);
1509 current = northWest;
1510 }
1511 i--;
1512 j--;
1513 } else if (min == west) {
1514 edits.push(EDIT_DELETE);
1515 i--;
1516 current = west;
1517 } else {
1518 edits.push(EDIT_ADD);
1519 j--;
1520 current = north;
1521 }
1522 }
1523
1524 edits.reverse();
1525 return edits;
1526 },
1527
1528 /**
1529 * Splice Projection functions:
1530 *
1531 * A splice map is a representation of how a previous array of items
1532 * was transformed into a new array of items. Conceptually it is a list of
1533 * tuples of
1534 *
1535 * <index, removed, addedCount>
1536 *
1537 * which are kept in ascending index order of. The tuple represents that at
1538 * the |index|, |removed| sequence of items were removed, and counting forwa rd
1539 * from |index|, |addedCount| items were added.
1540 */
1541
1542 /**
1543 * Lacking individual splice mutation information, the minimal set of
1544 * splices can be synthesized given the previous state and final state of an
1545 * array. The basic approach is to calculate the edit distance matrix and
1546 * choose the shortest path through it.
1547 *
1548 * Complexity: O(l * p)
1549 * l: The length of the current array
1550 * p: The length of the old array
1551 */
1552 calcSplices: function(current, currentStart, currentEnd,
1553 old, oldStart, oldEnd) {
1554 var prefixCount = 0;
1555 var suffixCount = 0;
1556
1557 var minLength = Math.min(currentEnd - currentStart, oldEnd - oldStart);
1558 if (currentStart == 0 && oldStart == 0)
1559 prefixCount = this.sharedPrefix(current, old, minLength);
1560
1561 if (currentEnd == current.length && oldEnd == old.length)
1562 suffixCount = this.sharedSuffix(current, old, minLength - prefixCount);
1563
1564 currentStart += prefixCount;
1565 oldStart += prefixCount;
1566 currentEnd -= suffixCount;
1567 oldEnd -= suffixCount;
1568
1569 if (currentEnd - currentStart == 0 && oldEnd - oldStart == 0)
1570 return [];
1571
1572 if (currentStart == currentEnd) {
1573 var splice = newSplice(currentStart, [], 0);
1574 while (oldStart < oldEnd)
1575 splice.removed.push(old[oldStart++]);
1576
1577 return [ splice ];
1578 } else if (oldStart == oldEnd)
1579 return [ newSplice(currentStart, [], currentEnd - currentStart) ];
1580
1581 var ops = this.spliceOperationsFromEditDistances(
1582 this.calcEditDistances(current, currentStart, currentEnd,
1583 old, oldStart, oldEnd));
1584
1585 var splice = undefined;
1586 var splices = [];
1587 var index = currentStart;
1588 var oldIndex = oldStart;
1589 for (var i = 0; i < ops.length; i++) {
1590 switch(ops[i]) {
1591 case EDIT_LEAVE:
1592 if (splice) {
1593 splices.push(splice);
1594 splice = undefined;
1595 }
1596
1597 index++;
1598 oldIndex++;
1599 break;
1600 case EDIT_UPDATE:
1601 if (!splice)
1602 splice = newSplice(index, [], 0);
1603
1604 splice.addedCount++;
1605 index++;
1606
1607 splice.removed.push(old[oldIndex]);
1608 oldIndex++;
1609 break;
1610 case EDIT_ADD:
1611 if (!splice)
1612 splice = newSplice(index, [], 0);
1613
1614 splice.addedCount++;
1615 index++;
1616 break;
1617 case EDIT_DELETE:
1618 if (!splice)
1619 splice = newSplice(index, [], 0);
1620
1621 splice.removed.push(old[oldIndex]);
1622 oldIndex++;
1623 break;
1624 }
1625 }
1626
1627 if (splice) {
1628 splices.push(splice);
1629 }
1630 return splices;
1631 },
1632
1633 sharedPrefix: function(current, old, searchLength) {
1634 for (var i = 0; i < searchLength; i++)
1635 if (!this.equals(current[i], old[i]))
1636 return i;
1637 return searchLength;
1638 },
1639
1640 sharedSuffix: function(current, old, searchLength) {
1641 var index1 = current.length;
1642 var index2 = old.length;
1643 var count = 0;
1644 while (count < searchLength && this.equals(current[--index1], old[--index2 ]))
1645 count++;
1646
1647 return count;
1648 },
1649
1650 calculateSplices: function(current, previous) {
1651 return this.calcSplices(current, 0, current.length, previous, 0,
1652 previous.length);
1653 },
1654
1655 equals: function(currentValue, previousValue) {
1656 return currentValue === previousValue;
1657 }
1658 };
1659
1660 var arraySplice = new ArraySplice();
1661
1662 function calcSplices(current, currentStart, currentEnd,
1663 old, oldStart, oldEnd) {
1664 return arraySplice.calcSplices(current, currentStart, currentEnd,
1665 old, oldStart, oldEnd);
1666 }
1667
1668 function intersect(start1, end1, start2, end2) {
1669 // Disjoint
1670 if (end1 < start2 || end2 < start1)
1671 return -1;
1672
1673 // Adjacent
1674 if (end1 == start2 || end2 == start1)
1675 return 0;
1676
1677 // Non-zero intersect, span1 first
1678 if (start1 < start2) {
1679 if (end1 < end2)
1680 return end1 - start2; // Overlap
1681 else
1682 return end2 - start2; // Contained
1683 } else {
1684 // Non-zero intersect, span2 first
1685 if (end2 < end1)
1686 return end2 - start1; // Overlap
1687 else
1688 return end1 - start1; // Contained
1689 }
1690 }
1691
1692 function mergeSplice(splices, index, removed, addedCount) {
1693
1694 var splice = newSplice(index, removed, addedCount);
1695
1696 var inserted = false;
1697 var insertionOffset = 0;
1698
1699 for (var i = 0; i < splices.length; i++) {
1700 var current = splices[i];
1701 current.index += insertionOffset;
1702
1703 if (inserted)
1704 continue;
1705
1706 var intersectCount = intersect(splice.index,
1707 splice.index + splice.removed.length,
1708 current.index,
1709 current.index + current.addedCount);
1710
1711 if (intersectCount >= 0) {
1712 // Merge the two splices
1713
1714 splices.splice(i, 1);
1715 i--;
1716
1717 insertionOffset -= current.addedCount - current.removed.length;
1718
1719 splice.addedCount += current.addedCount - intersectCount;
1720 var deleteCount = splice.removed.length +
1721 current.removed.length - intersectCount;
1722
1723 if (!splice.addedCount && !deleteCount) {
1724 // merged splice is a noop. discard.
1725 inserted = true;
1726 } else {
1727 var removed = current.removed;
1728
1729 if (splice.index < current.index) {
1730 // some prefix of splice.removed is prepended to current.removed.
1731 var prepend = splice.removed.slice(0, current.index - splice.index);
1732 Array.prototype.push.apply(prepend, removed);
1733 removed = prepend;
1734 }
1735
1736 if (splice.index + splice.removed.length > current.index + current.add edCount) {
1737 // some suffix of splice.removed is appended to current.removed.
1738 var append = splice.removed.slice(current.index + current.addedCount - splice.index);
1739 Array.prototype.push.apply(removed, append);
1740 }
1741
1742 splice.removed = removed;
1743 if (current.index < splice.index) {
1744 splice.index = current.index;
1745 }
1746 }
1747 } else if (splice.index < current.index) {
1748 // Insert splice here.
1749
1750 inserted = true;
1751
1752 splices.splice(i, 0, splice);
1753 i++;
1754
1755 var offset = splice.addedCount - splice.removed.length
1756 current.index += offset;
1757 insertionOffset += offset;
1758 }
1759 }
1760
1761 if (!inserted)
1762 splices.push(splice);
1763 }
1764
1765 function createInitialSplices(array, changeRecords) {
1766 var splices = [];
1767
1768 for (var i = 0; i < changeRecords.length; i++) {
1769 var record = changeRecords[i];
1770 switch(record.type) {
1771 case 'splice':
1772 mergeSplice(splices, record.index, record.removed.slice(), record.adde dCount);
1773 break;
1774 case 'add':
1775 case 'update':
1776 case 'delete':
1777 if (!isIndex(record.name))
1778 continue;
1779 var index = toNumber(record.name);
1780 if (index < 0)
1781 continue;
1782 mergeSplice(splices, index, [record.oldValue], 1);
1783 break;
1784 default:
1785 console.error('Unexpected record type: ' + JSON.stringify(record));
1786 break;
1787 }
1788 }
1789
1790 return splices;
1791 }
1792
1793 function projectArraySplices(array, changeRecords) {
1794 var splices = [];
1795
1796 createInitialSplices(array, changeRecords).forEach(function(splice) {
1797 if (splice.addedCount == 1 && splice.removed.length == 1) {
1798 if (splice.removed[0] !== array[splice.index])
1799 splices.push(splice);
1800
1801 return
1802 };
1803
1804 splices = splices.concat(calcSplices(array, splice.index, splice.index + s plice.addedCount,
1805 splice.removed, 0, splice.removed.len gth));
1806 });
1807
1808 return splices;
1809 }
1810
1811 global.Observer = Observer;
1812 global.Observer.runEOM_ = runEOM;
1813 global.Observer.observerSentinel_ = observerSentinel; // for testing.
1814 global.Observer.hasObjectObserve = hasObserve;
1815 global.ArrayObserver = ArrayObserver;
1816 global.ArrayObserver.calculateSplices = function(current, previous) {
1817 return arraySplice.calculateSplices(current, previous);
1818 };
1819
1820 global.ArraySplice = ArraySplice;
1821 global.ObjectObserver = ObjectObserver;
1822 global.PathObserver = PathObserver;
1823 global.CompoundObserver = CompoundObserver;
1824 global.Path = Path;
1825 global.ObserverTransform = ObserverTransform;
1826 })(typeof global !== 'undefined' && global && typeof module !== 'undefined' && m odule ? global : this || window);
1827
1828 // Copyright 2012 The Polymer Authors. All rights reserved.
1829 // Use of this source code is goverened by a BSD-style
1830 // license that can be found in the LICENSE file.
1831
1832 window.ShadowDOMPolyfill = {};
1833
1834 (function(scope) {
1835 'use strict';
1836
1837 var constructorTable = new WeakMap();
1838 var nativePrototypeTable = new WeakMap();
1839 var wrappers = Object.create(null);
1840
1841 function detectEval() {
1842 // Don't test for eval if we're running in a Chrome App environment.
1843 // We check for APIs set that only exist in a Chrome App context.
1844 if (typeof chrome !== 'undefined' && chrome.app && chrome.app.runtime) {
1845 return false;
1846 }
1847
1848 // Firefox OS Apps do not allow eval. This feature detection is very hacky
1849 // but even if some other platform adds support for this function this code
1850 // will continue to work.
1851 if (navigator.getDeviceStorage) {
1852 return false;
1853 }
1854
1855 try {
1856 var f = new Function('return true;');
1857 return f();
1858 } catch (ex) {
1859 return false;
1860 }
1861 }
1862
1863 var hasEval = detectEval();
1864
1865 function assert(b) {
1866 if (!b)
1867 throw new Error('Assertion failed');
1868 };
1869
1870 var defineProperty = Object.defineProperty;
1871 var getOwnPropertyNames = Object.getOwnPropertyNames;
1872 var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
1873
1874 function mixin(to, from) {
1875 var names = getOwnPropertyNames(from);
1876 for (var i = 0; i < names.length; i++) {
1877 var name = names[i];
1878 defineProperty(to, name, getOwnPropertyDescriptor(from, name));
1879 }
1880 return to;
1881 };
1882
1883 function mixinStatics(to, from) {
1884 var names = getOwnPropertyNames(from);
1885 for (var i = 0; i < names.length; i++) {
1886 var name = names[i];
1887 switch (name) {
1888 case 'arguments':
1889 case 'caller':
1890 case 'length':
1891 case 'name':
1892 case 'prototype':
1893 case 'toString':
1894 continue;
1895 }
1896 defineProperty(to, name, getOwnPropertyDescriptor(from, name));
1897 }
1898 return to;
1899 };
1900
1901 function oneOf(object, propertyNames) {
1902 for (var i = 0; i < propertyNames.length; i++) {
1903 if (propertyNames[i] in object)
1904 return propertyNames[i];
1905 }
1906 }
1907
1908 var nonEnumerableDataDescriptor = {
1909 value: undefined,
1910 configurable: true,
1911 enumerable: false,
1912 writable: true
1913 };
1914
1915 function defineNonEnumerableDataProperty(object, name, value) {
1916 nonEnumerableDataDescriptor.value = value;
1917 defineProperty(object, name, nonEnumerableDataDescriptor);
1918 }
1919
1920 // Mozilla's old DOM bindings are bretty busted:
1921 // https://bugzilla.mozilla.org/show_bug.cgi?id=855844
1922 // Make sure they are create before we start modifying things.
1923 getOwnPropertyNames(window);
1924
1925 function getWrapperConstructor(node) {
1926 var nativePrototype = node.__proto__ || Object.getPrototypeOf(node);
1927 var wrapperConstructor = constructorTable.get(nativePrototype);
1928 if (wrapperConstructor)
1929 return wrapperConstructor;
1930
1931 var parentWrapperConstructor = getWrapperConstructor(nativePrototype);
1932
1933 var GeneratedWrapper = createWrapperConstructor(parentWrapperConstructor);
1934 registerInternal(nativePrototype, GeneratedWrapper, node);
1935
1936 return GeneratedWrapper;
1937 }
1938
1939 function addForwardingProperties(nativePrototype, wrapperPrototype) {
1940 installProperty(nativePrototype, wrapperPrototype, true);
1941 }
1942
1943 function registerInstanceProperties(wrapperPrototype, instanceObject) {
1944 installProperty(instanceObject, wrapperPrototype, false);
1945 }
1946
1947 var isFirefox = /Firefox/.test(navigator.userAgent);
1948
1949 // This is used as a fallback when getting the descriptor fails in
1950 // installProperty.
1951 var dummyDescriptor = {
1952 get: function() {},
1953 set: function(v) {},
1954 configurable: true,
1955 enumerable: true
1956 };
1957
1958 function isEventHandlerName(name) {
1959 return /^on[a-z]+$/.test(name);
1960 }
1961
1962 function isIdentifierName(name) {
1963 return /^\w[a-zA-Z_0-9]*$/.test(name);
1964 }
1965
1966 // The name of the implementation property is intentionally hard to
1967 // remember. Unfortunately, browsers are slower doing obj[expr] than
1968 // obj.foo so we resort to repeat this ugly name. This ugly name is never
1969 // used outside of this file though.
1970
1971 function getGetter(name) {
1972 return hasEval && isIdentifierName(name) ?
1973 new Function('return this.__impl4cf1e782hg__.' + name) :
1974 function() { return this.__impl4cf1e782hg__[name]; };
1975 }
1976
1977 function getSetter(name) {
1978 return hasEval && isIdentifierName(name) ?
1979 new Function('v', 'this.__impl4cf1e782hg__.' + name + ' = v') :
1980 function(v) { this.__impl4cf1e782hg__[name] = v; };
1981 }
1982
1983 function getMethod(name) {
1984 return hasEval && isIdentifierName(name) ?
1985 new Function('return this.__impl4cf1e782hg__.' + name +
1986 '.apply(this.__impl4cf1e782hg__, arguments)') :
1987 function() {
1988 return this.__impl4cf1e782hg__[name].apply(
1989 this.__impl4cf1e782hg__, arguments);
1990 };
1991 }
1992
1993 function getDescriptor(source, name) {
1994 try {
1995 return Object.getOwnPropertyDescriptor(source, name);
1996 } catch (ex) {
1997 // JSC and V8 both use data properties instead of accessors which can
1998 // cause getting the property desciptor to throw an exception.
1999 // https://bugs.webkit.org/show_bug.cgi?id=49739
2000 return dummyDescriptor;
2001 }
2002 }
2003
2004 // Safari 8 exposes WebIDL attributes as an invalid accessor property. Its
2005 // descriptor has {get: undefined, set: undefined}. We therefore ignore the
2006 // shape of the descriptor and make all properties read-write.
2007 // https://bugs.webkit.org/show_bug.cgi?id=49739
2008 var isBrokenSafari = function() {
2009 var descr = Object.getOwnPropertyDescriptor(Node.prototype, 'nodeType');
2010 return !!descr && 'set' in descr;
2011 }();
2012
2013 function installProperty(source, target, allowMethod, opt_blacklist) {
2014 var names = getOwnPropertyNames(source);
2015 for (var i = 0; i < names.length; i++) {
2016 var name = names[i];
2017 if (name === 'polymerBlackList_')
2018 continue;
2019
2020 if (name in target)
2021 continue;
2022
2023 if (source.polymerBlackList_ && source.polymerBlackList_[name])
2024 continue;
2025
2026 if (isFirefox) {
2027 // Tickle Firefox's old bindings.
2028 source.__lookupGetter__(name);
2029 }
2030 var descriptor = getDescriptor(source, name);
2031 var getter, setter;
2032 if (allowMethod && typeof descriptor.value === 'function') {
2033 target[name] = getMethod(name);
2034 continue;
2035 }
2036
2037 var isEvent = isEventHandlerName(name);
2038 if (isEvent)
2039 getter = scope.getEventHandlerGetter(name);
2040 else
2041 getter = getGetter(name);
2042
2043 if (descriptor.writable || descriptor.set || isBrokenSafari) {
2044 if (isEvent)
2045 setter = scope.getEventHandlerSetter(name);
2046 else
2047 setter = getSetter(name);
2048 }
2049
2050 defineProperty(target, name, {
2051 get: getter,
2052 set: setter,
2053 configurable: descriptor.configurable,
2054 enumerable: descriptor.enumerable
2055 });
2056 }
2057 }
2058
2059 /**
2060 * @param {Function} nativeConstructor
2061 * @param {Function} wrapperConstructor
2062 * @param {Object=} opt_instance If present, this is used to extract
2063 * properties from an instance object.
2064 */
2065 function register(nativeConstructor, wrapperConstructor, opt_instance) {
2066 var nativePrototype = nativeConstructor.prototype;
2067 registerInternal(nativePrototype, wrapperConstructor, opt_instance);
2068 mixinStatics(wrapperConstructor, nativeConstructor);
2069 }
2070
2071 function registerInternal(nativePrototype, wrapperConstructor, opt_instance) {
2072 var wrapperPrototype = wrapperConstructor.prototype;
2073 assert(constructorTable.get(nativePrototype) === undefined);
2074
2075 constructorTable.set(nativePrototype, wrapperConstructor);
2076 nativePrototypeTable.set(wrapperPrototype, nativePrototype);
2077
2078 addForwardingProperties(nativePrototype, wrapperPrototype);
2079 if (opt_instance)
2080 registerInstanceProperties(wrapperPrototype, opt_instance);
2081
2082 defineNonEnumerableDataProperty(
2083 wrapperPrototype, 'constructor', wrapperConstructor);
2084 // Set it again. Some VMs optimizes objects that are used as prototypes.
2085 wrapperConstructor.prototype = wrapperPrototype;
2086 }
2087
2088 function isWrapperFor(wrapperConstructor, nativeConstructor) {
2089 return constructorTable.get(nativeConstructor.prototype) ===
2090 wrapperConstructor;
2091 }
2092
2093 /**
2094 * Creates a generic wrapper constructor based on |object| and its
2095 * constructor.
2096 * @param {Node} object
2097 * @return {Function} The generated constructor.
2098 */
2099 function registerObject(object) {
2100 var nativePrototype = Object.getPrototypeOf(object);
2101
2102 var superWrapperConstructor = getWrapperConstructor(nativePrototype);
2103 var GeneratedWrapper = createWrapperConstructor(superWrapperConstructor);
2104 registerInternal(nativePrototype, GeneratedWrapper, object);
2105
2106 return GeneratedWrapper;
2107 }
2108
2109 function createWrapperConstructor(superWrapperConstructor) {
2110 function GeneratedWrapper(node) {
2111 superWrapperConstructor.call(this, node);
2112 }
2113 var p = Object.create(superWrapperConstructor.prototype);
2114 p.constructor = GeneratedWrapper;
2115 GeneratedWrapper.prototype = p;
2116
2117 return GeneratedWrapper;
2118 }
2119
2120 function isWrapper(object) {
2121 return object && object.__impl4cf1e782hg__;
2122 }
2123
2124 function isNative(object) {
2125 return !isWrapper(object);
2126 }
2127
2128 /**
2129 * Wraps a node in a WrapperNode. If there already exists a wrapper for the
2130 * |node| that wrapper is returned instead.
2131 * @param {Node} node
2132 * @return {WrapperNode}
2133 */
2134 function wrap(impl) {
2135 if (impl === null)
2136 return null;
2137
2138 assert(isNative(impl));
2139 return impl.__wrapper8e3dd93a60__ ||
2140 (impl.__wrapper8e3dd93a60__ = new (getWrapperConstructor(impl))(impl));
2141 }
2142
2143 /**
2144 * Unwraps a wrapper and returns the node it is wrapping.
2145 * @param {WrapperNode} wrapper
2146 * @return {Node}
2147 */
2148 function unwrap(wrapper) {
2149 if (wrapper === null)
2150 return null;
2151 assert(isWrapper(wrapper));
2152 return wrapper.__impl4cf1e782hg__;
2153 }
2154
2155 function unsafeUnwrap(wrapper) {
2156 return wrapper.__impl4cf1e782hg__;
2157 }
2158
2159 function setWrapper(impl, wrapper) {
2160 wrapper.__impl4cf1e782hg__ = impl;
2161 impl.__wrapper8e3dd93a60__ = wrapper;
2162 }
2163
2164 /**
2165 * Unwraps object if it is a wrapper.
2166 * @param {Object} object
2167 * @return {Object} The native implementation object.
2168 */
2169 function unwrapIfNeeded(object) {
2170 return object && isWrapper(object) ? unwrap(object) : object;
2171 }
2172
2173 /**
2174 * Wraps object if it is not a wrapper.
2175 * @param {Object} object
2176 * @return {Object} The wrapper for object.
2177 */
2178 function wrapIfNeeded(object) {
2179 return object && !isWrapper(object) ? wrap(object) : object;
2180 }
2181
2182 /**
2183 * Overrides the current wrapper (if any) for node.
2184 * @param {Node} node
2185 * @param {WrapperNode=} wrapper If left out the wrapper will be created as
2186 * needed next time someone wraps the node.
2187 */
2188 function rewrap(node, wrapper) {
2189 if (wrapper === null)
2190 return;
2191 assert(isNative(node));
2192 assert(wrapper === undefined || isWrapper(wrapper));
2193 node.__wrapper8e3dd93a60__ = wrapper;
2194 }
2195
2196 var getterDescriptor = {
2197 get: undefined,
2198 configurable: true,
2199 enumerable: true
2200 };
2201
2202 function defineGetter(constructor, name, getter) {
2203 getterDescriptor.get = getter;
2204 defineProperty(constructor.prototype, name, getterDescriptor);
2205 }
2206
2207 function defineWrapGetter(constructor, name) {
2208 defineGetter(constructor, name, function() {
2209 return wrap(this.__impl4cf1e782hg__[name]);
2210 });
2211 }
2212
2213 /**
2214 * Forwards existing methods on the native object to the wrapper methods.
2215 * This does not wrap any of the arguments or the return value since the
2216 * wrapper implementation already takes care of that.
2217 * @param {Array.<Function>} constructors
2218 * @parem {Array.<string>} names
2219 */
2220 function forwardMethodsToWrapper(constructors, names) {
2221 constructors.forEach(function(constructor) {
2222 names.forEach(function(name) {
2223 constructor.prototype[name] = function() {
2224 var w = wrapIfNeeded(this);
2225 return w[name].apply(w, arguments);
2226 };
2227 });
2228 });
2229 }
2230
2231 scope.assert = assert;
2232 scope.constructorTable = constructorTable;
2233 scope.defineGetter = defineGetter;
2234 scope.defineWrapGetter = defineWrapGetter;
2235 scope.forwardMethodsToWrapper = forwardMethodsToWrapper;
2236 scope.isWrapper = isWrapper;
2237 scope.isWrapperFor = isWrapperFor;
2238 scope.mixin = mixin;
2239 scope.nativePrototypeTable = nativePrototypeTable;
2240 scope.oneOf = oneOf;
2241 scope.registerObject = registerObject;
2242 scope.registerWrapper = register;
2243 scope.rewrap = rewrap;
2244 scope.setWrapper = setWrapper;
2245 scope.unsafeUnwrap = unsafeUnwrap;
2246 scope.unwrap = unwrap;
2247 scope.unwrapIfNeeded = unwrapIfNeeded;
2248 scope.wrap = wrap;
2249 scope.wrapIfNeeded = wrapIfNeeded;
2250 scope.wrappers = wrappers;
2251
2252 })(window.ShadowDOMPolyfill);
2253
2254 /*
2255 * Copyright 2013 The Polymer Authors. All rights reserved.
2256 * Use of this source code is goverened by a BSD-style
2257 * license that can be found in the LICENSE file.
2258 */
2259
2260 (function(context) {
2261 'use strict';
2262
2263 var OriginalMutationObserver = window.MutationObserver;
2264 var callbacks = [];
2265 var pending = false;
2266 var timerFunc;
2267
2268 function handle() {
2269 pending = false;
2270 var copies = callbacks.slice(0);
2271 callbacks = [];
2272 for (var i = 0; i < copies.length; i++) {
2273 (0, copies[i])();
2274 }
2275 }
2276
2277 if (OriginalMutationObserver) {
2278 var counter = 1;
2279 var observer = new OriginalMutationObserver(handle);
2280 var textNode = document.createTextNode(counter);
2281 observer.observe(textNode, {characterData: true});
2282
2283 timerFunc = function() {
2284 counter = (counter + 1) % 2;
2285 textNode.data = counter;
2286 };
2287
2288 } else {
2289 timerFunc = window.setImmediate || window.setTimeout;
2290 }
2291
2292 function setEndOfMicrotask(func) {
2293 callbacks.push(func);
2294 if (pending)
2295 return;
2296 pending = true;
2297 timerFunc(handle, 0);
2298 }
2299
2300 context.setEndOfMicrotask = setEndOfMicrotask;
2301
2302 })(window.ShadowDOMPolyfill);
2303
2304 /*
2305 * Copyright 2013 The Polymer Authors. All rights reserved.
2306 * Use of this source code is goverened by a BSD-style
2307 * license that can be found in the LICENSE file.
2308 */
2309
2310 (function(scope) {
2311 'use strict';
2312
2313 var setEndOfMicrotask = scope.setEndOfMicrotask
2314 var wrapIfNeeded = scope.wrapIfNeeded
2315 var wrappers = scope.wrappers;
2316
2317 var registrationsTable = new WeakMap();
2318 var globalMutationObservers = [];
2319 var isScheduled = false;
2320
2321 function scheduleCallback(observer) {
2322 if (observer.scheduled_)
2323 return;
2324
2325 observer.scheduled_ = true;
2326 globalMutationObservers.push(observer);
2327
2328 if (isScheduled)
2329 return;
2330 setEndOfMicrotask(notifyObservers);
2331 isScheduled = true;
2332 }
2333
2334 // http://dom.spec.whatwg.org/#mutation-observers
2335 function notifyObservers() {
2336 isScheduled = false;
2337
2338 while (globalMutationObservers.length) {
2339 var notifyList = globalMutationObservers;
2340 globalMutationObservers = [];
2341
2342 // Deliver changes in birth order of the MutationObservers.
2343 notifyList.sort(function(x, y) { return x.uid_ - y.uid_; });
2344
2345 for (var i = 0; i < notifyList.length; i++) {
2346 var mo = notifyList[i];
2347 mo.scheduled_ = false;
2348 var queue = mo.takeRecords();
2349 removeTransientObserversFor(mo);
2350 if (queue.length) {
2351 mo.callback_(queue, mo);
2352 }
2353 }
2354 }
2355 }
2356
2357
2358 /**
2359 * @param {string} type
2360 * @param {Node} target
2361 * @constructor
2362 */
2363 function MutationRecord(type, target) {
2364 this.type = type;
2365 this.target = target;
2366 this.addedNodes = new wrappers.NodeList();
2367 this.removedNodes = new wrappers.NodeList();
2368 this.previousSibling = null;
2369 this.nextSibling = null;
2370 this.attributeName = null;
2371 this.attributeNamespace = null;
2372 this.oldValue = null;
2373 }
2374
2375 /**
2376 * Registers transient observers to ancestor and its ancesors for the node
2377 * which was removed.
2378 * @param {!Node} ancestor
2379 * @param {!Node} node
2380 */
2381 function registerTransientObservers(ancestor, node) {
2382 for (; ancestor; ancestor = ancestor.parentNode) {
2383 var registrations = registrationsTable.get(ancestor);
2384 if (!registrations)
2385 continue;
2386 for (var i = 0; i < registrations.length; i++) {
2387 var registration = registrations[i];
2388 if (registration.options.subtree)
2389 registration.addTransientObserver(node);
2390 }
2391 }
2392 }
2393
2394 function removeTransientObserversFor(observer) {
2395 for (var i = 0; i < observer.nodes_.length; i++) {
2396 var node = observer.nodes_[i];
2397 var registrations = registrationsTable.get(node);
2398 if (!registrations)
2399 return;
2400 for (var j = 0; j < registrations.length; j++) {
2401 var registration = registrations[j];
2402 if (registration.observer === observer)
2403 registration.removeTransientObservers();
2404 }
2405 }
2406 }
2407
2408 // http://dom.spec.whatwg.org/#queue-a-mutation-record
2409 function enqueueMutation(target, type, data) {
2410 // 1.
2411 var interestedObservers = Object.create(null);
2412 var associatedStrings = Object.create(null);
2413
2414 // 2.
2415 for (var node = target; node; node = node.parentNode) {
2416 // 3.
2417 var registrations = registrationsTable.get(node);
2418 if (!registrations)
2419 continue;
2420 for (var j = 0; j < registrations.length; j++) {
2421 var registration = registrations[j];
2422 var options = registration.options;
2423 // 1.
2424 if (node !== target && !options.subtree)
2425 continue;
2426
2427 // 2.
2428 if (type === 'attributes' && !options.attributes)
2429 continue;
2430
2431 // 3. If type is "attributes", options's attributeFilter is present, and
2432 // either options's attributeFilter does not contain name or namespace
2433 // is non-null, continue.
2434 if (type === 'attributes' && options.attributeFilter &&
2435 (data.namespace !== null ||
2436 options.attributeFilter.indexOf(data.name) === -1)) {
2437 continue;
2438 }
2439
2440 // 4.
2441 if (type === 'characterData' && !options.characterData)
2442 continue;
2443
2444 // 5.
2445 if (type === 'childList' && !options.childList)
2446 continue;
2447
2448 // 6.
2449 var observer = registration.observer;
2450 interestedObservers[observer.uid_] = observer;
2451
2452 // 7. If either type is "attributes" and options's attributeOldValue is
2453 // true, or type is "characterData" and options's characterDataOldValue
2454 // is true, set the paired string of registered observer's observer in
2455 // interested observers to oldValue.
2456 if (type === 'attributes' && options.attributeOldValue ||
2457 type === 'characterData' && options.characterDataOldValue) {
2458 associatedStrings[observer.uid_] = data.oldValue;
2459 }
2460 }
2461 }
2462
2463 // 4.
2464 for (var uid in interestedObservers) {
2465 var observer = interestedObservers[uid];
2466 var record = new MutationRecord(type, target);
2467
2468 // 2.
2469 if ('name' in data && 'namespace' in data) {
2470 record.attributeName = data.name;
2471 record.attributeNamespace = data.namespace;
2472 }
2473
2474 // 3.
2475 if (data.addedNodes)
2476 record.addedNodes = data.addedNodes;
2477
2478 // 4.
2479 if (data.removedNodes)
2480 record.removedNodes = data.removedNodes;
2481
2482 // 5.
2483 if (data.previousSibling)
2484 record.previousSibling = data.previousSibling;
2485
2486 // 6.
2487 if (data.nextSibling)
2488 record.nextSibling = data.nextSibling;
2489
2490 // 7.
2491 if (associatedStrings[uid] !== undefined)
2492 record.oldValue = associatedStrings[uid];
2493
2494 // 8.
2495 scheduleCallback(observer);
2496 observer.records_.push(record);
2497 }
2498 }
2499
2500 var slice = Array.prototype.slice;
2501
2502 /**
2503 * @param {!Object} options
2504 * @constructor
2505 */
2506 function MutationObserverOptions(options) {
2507 this.childList = !!options.childList;
2508 this.subtree = !!options.subtree;
2509
2510 // 1. If either options' attributeOldValue or attributeFilter is present
2511 // and options' attributes is omitted, set options' attributes to true.
2512 if (!('attributes' in options) &&
2513 ('attributeOldValue' in options || 'attributeFilter' in options)) {
2514 this.attributes = true;
2515 } else {
2516 this.attributes = !!options.attributes;
2517 }
2518
2519 // 2. If options' characterDataOldValue is present and options'
2520 // characterData is omitted, set options' characterData to true.
2521 if ('characterDataOldValue' in options && !('characterData' in options))
2522 this.characterData = true;
2523 else
2524 this.characterData = !!options.characterData;
2525
2526 // 3. & 4.
2527 if (!this.attributes &&
2528 (options.attributeOldValue || 'attributeFilter' in options) ||
2529 // 5.
2530 !this.characterData && options.characterDataOldValue) {
2531 throw new TypeError();
2532 }
2533
2534 this.characterData = !!options.characterData;
2535 this.attributeOldValue = !!options.attributeOldValue;
2536 this.characterDataOldValue = !!options.characterDataOldValue;
2537 if ('attributeFilter' in options) {
2538 if (options.attributeFilter == null ||
2539 typeof options.attributeFilter !== 'object') {
2540 throw new TypeError();
2541 }
2542 this.attributeFilter = slice.call(options.attributeFilter);
2543 } else {
2544 this.attributeFilter = null;
2545 }
2546 }
2547
2548 var uidCounter = 0;
2549
2550 /**
2551 * The class that maps to the DOM MutationObserver interface.
2552 * @param {Function} callback.
2553 * @constructor
2554 */
2555 function MutationObserver(callback) {
2556 this.callback_ = callback;
2557 this.nodes_ = [];
2558 this.records_ = [];
2559 this.uid_ = ++uidCounter;
2560 this.scheduled_ = false;
2561 }
2562
2563 MutationObserver.prototype = {
2564 constructor: MutationObserver,
2565
2566 // http://dom.spec.whatwg.org/#dom-mutationobserver-observe
2567 observe: function(target, options) {
2568 target = wrapIfNeeded(target);
2569
2570 var newOptions = new MutationObserverOptions(options);
2571
2572 // 6.
2573 var registration;
2574 var registrations = registrationsTable.get(target);
2575 if (!registrations)
2576 registrationsTable.set(target, registrations = []);
2577
2578 for (var i = 0; i < registrations.length; i++) {
2579 if (registrations[i].observer === this) {
2580 registration = registrations[i];
2581 // 6.1.
2582 registration.removeTransientObservers();
2583 // 6.2.
2584 registration.options = newOptions;
2585 }
2586 }
2587
2588 // 7.
2589 if (!registration) {
2590 registration = new Registration(this, target, newOptions);
2591 registrations.push(registration);
2592 this.nodes_.push(target);
2593 }
2594 },
2595
2596 // http://dom.spec.whatwg.org/#dom-mutationobserver-disconnect
2597 disconnect: function() {
2598 this.nodes_.forEach(function(node) {
2599 var registrations = registrationsTable.get(node);
2600 for (var i = 0; i < registrations.length; i++) {
2601 var registration = registrations[i];
2602 if (registration.observer === this) {
2603 registrations.splice(i, 1);
2604 // Each node can only have one registered observer associated with
2605 // this observer.
2606 break;
2607 }
2608 }
2609 }, this);
2610 this.records_ = [];
2611 },
2612
2613 takeRecords: function() {
2614 var copyOfRecords = this.records_;
2615 this.records_ = [];
2616 return copyOfRecords;
2617 }
2618 };
2619
2620 /**
2621 * Class used to represent a registered observer.
2622 * @param {MutationObserver} observer
2623 * @param {Node} target
2624 * @param {MutationObserverOptions} options
2625 * @constructor
2626 */
2627 function Registration(observer, target, options) {
2628 this.observer = observer;
2629 this.target = target;
2630 this.options = options;
2631 this.transientObservedNodes = [];
2632 }
2633
2634 Registration.prototype = {
2635 /**
2636 * Adds a transient observer on node. The transient observer gets removed
2637 * next time we deliver the change records.
2638 * @param {Node} node
2639 */
2640 addTransientObserver: function(node) {
2641 // Don't add transient observers on the target itself. We already have all
2642 // the required listeners set up on the target.
2643 if (node === this.target)
2644 return;
2645
2646 // Make sure we remove transient observers at the end of microtask, even
2647 // if we didn't get any change records.
2648 scheduleCallback(this.observer);
2649
2650 this.transientObservedNodes.push(node);
2651 var registrations = registrationsTable.get(node);
2652 if (!registrations)
2653 registrationsTable.set(node, registrations = []);
2654
2655 // We know that registrations does not contain this because we already
2656 // checked if node === this.target.
2657 registrations.push(this);
2658 },
2659
2660 removeTransientObservers: function() {
2661 var transientObservedNodes = this.transientObservedNodes;
2662 this.transientObservedNodes = [];
2663
2664 for (var i = 0; i < transientObservedNodes.length; i++) {
2665 var node = transientObservedNodes[i];
2666 var registrations = registrationsTable.get(node);
2667 for (var j = 0; j < registrations.length; j++) {
2668 if (registrations[j] === this) {
2669 registrations.splice(j, 1);
2670 // Each node can only have one registered observer associated with
2671 // this observer.
2672 break;
2673 }
2674 }
2675 }
2676 }
2677 };
2678
2679 scope.enqueueMutation = enqueueMutation;
2680 scope.registerTransientObservers = registerTransientObservers;
2681 scope.wrappers.MutationObserver = MutationObserver;
2682 scope.wrappers.MutationRecord = MutationRecord;
2683
2684 })(window.ShadowDOMPolyfill);
2685
2686 /**
2687 * Copyright 2014 The Polymer Authors. All rights reserved.
2688 * Use of this source code is goverened by a BSD-style
2689 * license that can be found in the LICENSE file.
2690 */
2691
2692 (function(scope) {
2693 'use strict';
2694
2695 /**
2696 * A tree scope represents the root of a tree. All nodes in a tree point to
2697 * the same TreeScope object. The tree scope of a node get set the first time
2698 * it is accessed or when a node is added or remove to a tree.
2699 *
2700 * The root is a Node that has no parent.
2701 *
2702 * The parent is another TreeScope. For ShadowRoots, it is the TreeScope of
2703 * the host of the ShadowRoot.
2704 *
2705 * @param {!Node} root
2706 * @param {TreeScope} parent
2707 * @constructor
2708 */
2709 function TreeScope(root, parent) {
2710 /** @type {!Node} */
2711 this.root = root;
2712
2713 /** @type {TreeScope} */
2714 this.parent = parent;
2715 }
2716
2717 TreeScope.prototype = {
2718 get renderer() {
2719 if (this.root instanceof scope.wrappers.ShadowRoot) {
2720 return scope.getRendererForHost(this.root.host);
2721 }
2722 return null;
2723 },
2724
2725 contains: function(treeScope) {
2726 for (; treeScope; treeScope = treeScope.parent) {
2727 if (treeScope === this)
2728 return true;
2729 }
2730 return false;
2731 }
2732 };
2733
2734 function setTreeScope(node, treeScope) {
2735 if (node.treeScope_ !== treeScope) {
2736 node.treeScope_ = treeScope;
2737 for (var sr = node.shadowRoot; sr; sr = sr.olderShadowRoot) {
2738 sr.treeScope_.parent = treeScope;
2739 }
2740 for (var child = node.firstChild; child; child = child.nextSibling) {
2741 setTreeScope(child, treeScope);
2742 }
2743 }
2744 }
2745
2746 function getTreeScope(node) {
2747 if (node instanceof scope.wrappers.Window) {
2748 debugger;
2749 }
2750
2751 if (node.treeScope_)
2752 return node.treeScope_;
2753 var parent = node.parentNode;
2754 var treeScope;
2755 if (parent)
2756 treeScope = getTreeScope(parent);
2757 else
2758 treeScope = new TreeScope(node, null);
2759 return node.treeScope_ = treeScope;
2760 }
2761
2762 scope.TreeScope = TreeScope;
2763 scope.getTreeScope = getTreeScope;
2764 scope.setTreeScope = setTreeScope;
2765
2766 })(window.ShadowDOMPolyfill);
2767
2768 // Copyright 2013 The Polymer Authors. All rights reserved.
2769 // Use of this source code is goverened by a BSD-style
2770 // license that can be found in the LICENSE file.
2771
2772 (function(scope) {
2773 'use strict';
2774
2775 var forwardMethodsToWrapper = scope.forwardMethodsToWrapper;
2776 var getTreeScope = scope.getTreeScope;
2777 var mixin = scope.mixin;
2778 var registerWrapper = scope.registerWrapper;
2779 var setWrapper = scope.setWrapper;
2780 var unsafeUnwrap = scope.unsafeUnwrap;
2781 var unwrap = scope.unwrap;
2782 var wrap = scope.wrap;
2783 var wrappers = scope.wrappers;
2784
2785 var wrappedFuns = new WeakMap();
2786 var listenersTable = new WeakMap();
2787 var handledEventsTable = new WeakMap();
2788 var currentlyDispatchingEvents = new WeakMap();
2789 var targetTable = new WeakMap();
2790 var currentTargetTable = new WeakMap();
2791 var relatedTargetTable = new WeakMap();
2792 var eventPhaseTable = new WeakMap();
2793 var stopPropagationTable = new WeakMap();
2794 var stopImmediatePropagationTable = new WeakMap();
2795 var eventHandlersTable = new WeakMap();
2796 var eventPathTable = new WeakMap();
2797
2798 function isShadowRoot(node) {
2799 return node instanceof wrappers.ShadowRoot;
2800 }
2801
2802 function rootOfNode(node) {
2803 return getTreeScope(node).root;
2804 }
2805
2806 // http://w3c.github.io/webcomponents/spec/shadow/#event-paths
2807 function getEventPath(node, event) {
2808 var path = [];
2809 var current = node;
2810 path.push(current);
2811 while (current) {
2812 // 4.1.
2813 var destinationInsertionPoints = getDestinationInsertionPoints(current);
2814 if (destinationInsertionPoints && destinationInsertionPoints.length > 0) {
2815 // 4.1.1
2816 for (var i = 0; i < destinationInsertionPoints.length; i++) {
2817 var insertionPoint = destinationInsertionPoints[i];
2818 // 4.1.1.1
2819 if (isShadowInsertionPoint(insertionPoint)) {
2820 var shadowRoot = rootOfNode(insertionPoint);
2821 // 4.1.1.1.2
2822 var olderShadowRoot = shadowRoot.olderShadowRoot;
2823 if (olderShadowRoot)
2824 path.push(olderShadowRoot);
2825 }
2826
2827 // 4.1.1.2
2828 path.push(insertionPoint);
2829 }
2830
2831 // 4.1.2
2832 current = destinationInsertionPoints[
2833 destinationInsertionPoints.length - 1];
2834
2835 // 4.2
2836 } else {
2837 if (isShadowRoot(current)) {
2838 if (inSameTree(node, current) && eventMustBeStopped(event)) {
2839 // Stop this algorithm
2840 break;
2841 }
2842 current = current.host;
2843 path.push(current);
2844
2845 // 4.2.2
2846 } else {
2847 current = current.parentNode;
2848 if (current)
2849 path.push(current);
2850 }
2851 }
2852 }
2853
2854 return path;
2855 }
2856
2857 // http://w3c.github.io/webcomponents/spec/shadow/#dfn-events-always-stopped
2858 function eventMustBeStopped(event) {
2859 if (!event)
2860 return false;
2861
2862 switch (event.type) {
2863 case 'abort':
2864 case 'error':
2865 case 'select':
2866 case 'change':
2867 case 'load':
2868 case 'reset':
2869 case 'resize':
2870 case 'scroll':
2871 case 'selectstart':
2872 return true;
2873 }
2874 return false;
2875 }
2876
2877 // http://w3c.github.io/webcomponents/spec/shadow/#dfn-shadow-insertion-point
2878 function isShadowInsertionPoint(node) {
2879 return node instanceof HTMLShadowElement;
2880 // and make sure that there are no shadow precing this?
2881 // and that there is no content ancestor?
2882 }
2883
2884 function getDestinationInsertionPoints(node) {
2885 return scope.getDestinationInsertionPoints(node);
2886 }
2887
2888 // http://w3c.github.io/webcomponents/spec/shadow/#event-retargeting
2889 function eventRetargetting(path, currentTarget) {
2890 if (path.length === 0)
2891 return currentTarget;
2892
2893 // The currentTarget might be the window object. Use its document for the
2894 // purpose of finding the retargetted node.
2895 if (currentTarget instanceof wrappers.Window)
2896 currentTarget = currentTarget.document;
2897
2898 var currentTargetTree = getTreeScope(currentTarget);
2899 var originalTarget = path[0];
2900 var originalTargetTree = getTreeScope(originalTarget);
2901 var relativeTargetTree =
2902 lowestCommonInclusiveAncestor(currentTargetTree, originalTargetTree);
2903
2904 for (var i = 0; i < path.length; i++) {
2905 var node = path[i];
2906 if (getTreeScope(node) === relativeTargetTree)
2907 return node;
2908 }
2909
2910 return path[path.length - 1];
2911 }
2912
2913 function getTreeScopeAncestors(treeScope) {
2914 var ancestors = [];
2915 for (;treeScope; treeScope = treeScope.parent) {
2916 ancestors.push(treeScope);
2917 }
2918 return ancestors;
2919 }
2920
2921 function lowestCommonInclusiveAncestor(tsA, tsB) {
2922 var ancestorsA = getTreeScopeAncestors(tsA);
2923 var ancestorsB = getTreeScopeAncestors(tsB);
2924
2925 var result = null;
2926 while (ancestorsA.length > 0 && ancestorsB.length > 0) {
2927 var a = ancestorsA.pop();
2928 var b = ancestorsB.pop();
2929 if (a === b)
2930 result = a;
2931 else
2932 break;
2933 }
2934 return result;
2935 }
2936
2937 function getTreeScopeRoot(ts) {
2938 if (!ts.parent)
2939 return ts;
2940 return getTreeScopeRoot(ts.parent);
2941 }
2942
2943 function relatedTargetResolution(event, currentTarget, relatedTarget) {
2944 // In case the current target is a window use its document for the purpose
2945 // of retargetting the related target.
2946 if (currentTarget instanceof wrappers.Window)
2947 currentTarget = currentTarget.document;
2948
2949 var currentTargetTree = getTreeScope(currentTarget);
2950 var relatedTargetTree = getTreeScope(relatedTarget);
2951
2952 var relatedTargetEventPath = getEventPath(relatedTarget, event);
2953
2954 var lowestCommonAncestorTree;
2955
2956 // 4
2957 var lowestCommonAncestorTree =
2958 lowestCommonInclusiveAncestor(currentTargetTree, relatedTargetTree);
2959
2960 // 5
2961 if (!lowestCommonAncestorTree)
2962 lowestCommonAncestorTree = relatedTargetTree.root;
2963
2964 // 6
2965 for (var commonAncestorTree = lowestCommonAncestorTree;
2966 commonAncestorTree;
2967 commonAncestorTree = commonAncestorTree.parent) {
2968 // 6.1
2969 var adjustedRelatedTarget;
2970 for (var i = 0; i < relatedTargetEventPath.length; i++) {
2971 var node = relatedTargetEventPath[i];
2972 if (getTreeScope(node) === commonAncestorTree)
2973 return node;
2974 }
2975 }
2976
2977 return null;
2978 }
2979
2980 function inSameTree(a, b) {
2981 return getTreeScope(a) === getTreeScope(b);
2982 }
2983
2984 var NONE = 0;
2985 var CAPTURING_PHASE = 1;
2986 var AT_TARGET = 2;
2987 var BUBBLING_PHASE = 3;
2988
2989 // pendingError is used to rethrow the first error we got during an event
2990 // dispatch. The browser actually reports all errors but to do that we would
2991 // need to rethrow the error asynchronously.
2992 var pendingError;
2993
2994 function dispatchOriginalEvent(originalEvent) {
2995 // Make sure this event is only dispatched once.
2996 if (handledEventsTable.get(originalEvent))
2997 return;
2998 handledEventsTable.set(originalEvent, true);
2999 dispatchEvent(wrap(originalEvent), wrap(originalEvent.target));
3000 if (pendingError) {
3001 var err = pendingError;
3002 pendingError = null;
3003 throw err;
3004 }
3005 }
3006
3007
3008 function isLoadLikeEvent(event) {
3009 switch (event.type) {
3010 // http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis. html#events-and-the-window-object
3011 case 'load':
3012 // http://www.whatwg.org/specs/web-apps/current-work/multipage/browsers.ht ml#unloading-documents
3013 case 'beforeunload':
3014 case 'unload':
3015 return true;
3016 }
3017 return false;
3018 }
3019
3020 function dispatchEvent(event, originalWrapperTarget) {
3021 if (currentlyDispatchingEvents.get(event))
3022 throw new Error('InvalidStateError');
3023
3024 currentlyDispatchingEvents.set(event, true);
3025
3026 // Render to ensure that the event path is correct.
3027 scope.renderAllPending();
3028 var eventPath;
3029
3030 // http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.ht ml#events-and-the-window-object
3031 // All events dispatched on Nodes with a default view, except load events,
3032 // should propagate to the Window.
3033
3034 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html# the-end
3035 var overrideTarget;
3036 var win;
3037
3038 // Should really be not cancelable too but since Firefox has a bug there
3039 // we skip that check.
3040 // https://bugzilla.mozilla.org/show_bug.cgi?id=999456
3041 if (isLoadLikeEvent(event) && !event.bubbles) {
3042 var doc = originalWrapperTarget;
3043 if (doc instanceof wrappers.Document && (win = doc.defaultView)) {
3044 overrideTarget = doc;
3045 eventPath = [];
3046 }
3047 }
3048
3049 if (!eventPath) {
3050 if (originalWrapperTarget instanceof wrappers.Window) {
3051 win = originalWrapperTarget;
3052 eventPath = [];
3053 } else {
3054 eventPath = getEventPath(originalWrapperTarget, event);
3055
3056 if (!isLoadLikeEvent(event)) {
3057 var doc = eventPath[eventPath.length - 1];
3058 if (doc instanceof wrappers.Document)
3059 win = doc.defaultView;
3060 }
3061 }
3062 }
3063
3064 eventPathTable.set(event, eventPath);
3065
3066 if (dispatchCapturing(event, eventPath, win, overrideTarget)) {
3067 if (dispatchAtTarget(event, eventPath, win, overrideTarget)) {
3068 dispatchBubbling(event, eventPath, win, overrideTarget);
3069 }
3070 }
3071
3072 eventPhaseTable.set(event, NONE);
3073 currentTargetTable.delete(event, null);
3074 currentlyDispatchingEvents.delete(event);
3075
3076 return event.defaultPrevented;
3077 }
3078
3079 function dispatchCapturing(event, eventPath, win, overrideTarget) {
3080 var phase = CAPTURING_PHASE;
3081
3082 if (win) {
3083 if (!invoke(win, event, phase, eventPath, overrideTarget))
3084 return false;
3085 }
3086
3087 for (var i = eventPath.length - 1; i > 0; i--) {
3088 if (!invoke(eventPath[i], event, phase, eventPath, overrideTarget))
3089 return false;
3090 }
3091
3092 return true;
3093 }
3094
3095 function dispatchAtTarget(event, eventPath, win, overrideTarget) {
3096 var phase = AT_TARGET;
3097 var currentTarget = eventPath[0] || win;
3098 return invoke(currentTarget, event, phase, eventPath, overrideTarget);
3099 }
3100
3101 function dispatchBubbling(event, eventPath, win, overrideTarget) {
3102 var phase = BUBBLING_PHASE;
3103 for (var i = 1; i < eventPath.length; i++) {
3104 if (!invoke(eventPath[i], event, phase, eventPath, overrideTarget))
3105 return;
3106 }
3107
3108 if (win && eventPath.length > 0) {
3109 invoke(win, event, phase, eventPath, overrideTarget);
3110 }
3111 }
3112
3113 function invoke(currentTarget, event, phase, eventPath, overrideTarget) {
3114 var listeners = listenersTable.get(currentTarget);
3115 if (!listeners)
3116 return true;
3117
3118 var target = overrideTarget || eventRetargetting(eventPath, currentTarget);
3119
3120 if (target === currentTarget) {
3121 if (phase === CAPTURING_PHASE)
3122 return true;
3123
3124 if (phase === BUBBLING_PHASE)
3125 phase = AT_TARGET;
3126
3127 } else if (phase === BUBBLING_PHASE && !event.bubbles) {
3128 return true;
3129 }
3130
3131 if ('relatedTarget' in event) {
3132 var originalEvent = unwrap(event);
3133 var unwrappedRelatedTarget = originalEvent.relatedTarget;
3134
3135 // X-Tag sets relatedTarget on a CustomEvent. If they do that there is no
3136 // way to have relatedTarget return the adjusted target but worse is that
3137 // the originalEvent might not have a relatedTarget so we hit an assert
3138 // when we try to wrap it.
3139 if (unwrappedRelatedTarget) {
3140 // In IE we can get objects that are not EventTargets at this point.
3141 // Safari does not have an EventTarget interface so revert to checking
3142 // for addEventListener as an approximation.
3143 if (unwrappedRelatedTarget instanceof Object &&
3144 unwrappedRelatedTarget.addEventListener) {
3145 var relatedTarget = wrap(unwrappedRelatedTarget);
3146
3147 var adjusted =
3148 relatedTargetResolution(event, currentTarget, relatedTarget);
3149 if (adjusted === target)
3150 return true;
3151 } else {
3152 adjusted = null;
3153 }
3154 relatedTargetTable.set(event, adjusted);
3155 }
3156 }
3157
3158 eventPhaseTable.set(event, phase);
3159 var type = event.type;
3160
3161 var anyRemoved = false;
3162 targetTable.set(event, target);
3163 currentTargetTable.set(event, currentTarget);
3164
3165 // Keep track of the invoke depth so that we only clean up the removed
3166 // listeners if we are in the outermost invoke.
3167 listeners.depth++;
3168
3169 for (var i = 0, len = listeners.length; i < len; i++) {
3170 var listener = listeners[i];
3171 if (listener.removed) {
3172 anyRemoved = true;
3173 continue;
3174 }
3175
3176 if (listener.type !== type ||
3177 !listener.capture && phase === CAPTURING_PHASE ||
3178 listener.capture && phase === BUBBLING_PHASE) {
3179 continue;
3180 }
3181
3182 try {
3183 if (typeof listener.handler === 'function')
3184 listener.handler.call(currentTarget, event);
3185 else
3186 listener.handler.handleEvent(event);
3187
3188 if (stopImmediatePropagationTable.get(event))
3189 return false;
3190
3191 } catch (ex) {
3192 if (!pendingError)
3193 pendingError = ex;
3194 }
3195 }
3196
3197 listeners.depth--;
3198
3199 if (anyRemoved && listeners.depth === 0) {
3200 var copy = listeners.slice();
3201 listeners.length = 0;
3202 for (var i = 0; i < copy.length; i++) {
3203 if (!copy[i].removed)
3204 listeners.push(copy[i]);
3205 }
3206 }
3207
3208 return !stopPropagationTable.get(event);
3209 }
3210
3211 function Listener(type, handler, capture) {
3212 this.type = type;
3213 this.handler = handler;
3214 this.capture = Boolean(capture);
3215 }
3216 Listener.prototype = {
3217 equals: function(that) {
3218 return this.handler === that.handler && this.type === that.type &&
3219 this.capture === that.capture;
3220 },
3221 get removed() {
3222 return this.handler === null;
3223 },
3224 remove: function() {
3225 this.handler = null;
3226 }
3227 };
3228
3229 var OriginalEvent = window.Event;
3230 OriginalEvent.prototype.polymerBlackList_ = {
3231 returnValue: true,
3232 // TODO(arv): keyLocation is part of KeyboardEvent but Firefox does not
3233 // support constructable KeyboardEvent so we keep it here for now.
3234 keyLocation: true
3235 };
3236
3237 /**
3238 * Creates a new Event wrapper or wraps an existin native Event object.
3239 * @param {string|Event} type
3240 * @param {Object=} options
3241 * @constructor
3242 */
3243 function Event(type, options) {
3244 if (type instanceof OriginalEvent) {
3245 var impl = type;
3246 // In browsers that do not correctly support BeforeUnloadEvent we get to
3247 // the generic Event wrapper but we still want to ensure we create a
3248 // BeforeUnloadEvent. Since BeforeUnloadEvent calls super, we need to
3249 // prevent reentrancty.
3250 if (!OriginalBeforeUnloadEvent && impl.type === 'beforeunload' &&
3251 !(this instanceof BeforeUnloadEvent)) {
3252 return new BeforeUnloadEvent(impl);
3253 }
3254 setWrapper(impl, this);
3255 } else {
3256 return wrap(constructEvent(OriginalEvent, 'Event', type, options));
3257 }
3258 }
3259 Event.prototype = {
3260 get target() {
3261 return targetTable.get(this);
3262 },
3263 get currentTarget() {
3264 return currentTargetTable.get(this);
3265 },
3266 get eventPhase() {
3267 return eventPhaseTable.get(this);
3268 },
3269 get path() {
3270 var eventPath = eventPathTable.get(this);
3271 if (!eventPath)
3272 return [];
3273 // TODO(arv): Event path should contain window.
3274 return eventPath.slice();
3275 },
3276 stopPropagation: function() {
3277 stopPropagationTable.set(this, true);
3278 },
3279 stopImmediatePropagation: function() {
3280 stopPropagationTable.set(this, true);
3281 stopImmediatePropagationTable.set(this, true);
3282 }
3283 };
3284 registerWrapper(OriginalEvent, Event, document.createEvent('Event'));
3285
3286 function unwrapOptions(options) {
3287 if (!options || !options.relatedTarget)
3288 return options;
3289 return Object.create(options, {
3290 relatedTarget: {value: unwrap(options.relatedTarget)}
3291 });
3292 }
3293
3294 function registerGenericEvent(name, SuperEvent, prototype) {
3295 var OriginalEvent = window[name];
3296 var GenericEvent = function(type, options) {
3297 if (type instanceof OriginalEvent)
3298 setWrapper(type, this);
3299 else
3300 return wrap(constructEvent(OriginalEvent, name, type, options));
3301 };
3302 GenericEvent.prototype = Object.create(SuperEvent.prototype);
3303 if (prototype)
3304 mixin(GenericEvent.prototype, prototype);
3305 if (OriginalEvent) {
3306 // - Old versions of Safari fails on new FocusEvent (and others?).
3307 // - IE does not support event constructors.
3308 // - createEvent('FocusEvent') throws in Firefox.
3309 // => Try the best practice solution first and fallback to the old way
3310 // if needed.
3311 try {
3312 registerWrapper(OriginalEvent, GenericEvent, new OriginalEvent('temp'));
3313 } catch (ex) {
3314 registerWrapper(OriginalEvent, GenericEvent,
3315 document.createEvent(name));
3316 }
3317 }
3318 return GenericEvent;
3319 }
3320
3321 var UIEvent = registerGenericEvent('UIEvent', Event);
3322 var CustomEvent = registerGenericEvent('CustomEvent', Event);
3323
3324 var relatedTargetProto = {
3325 get relatedTarget() {
3326 var relatedTarget = relatedTargetTable.get(this);
3327 // relatedTarget can be null.
3328 if (relatedTarget !== undefined)
3329 return relatedTarget;
3330 return wrap(unwrap(this).relatedTarget);
3331 }
3332 };
3333
3334 function getInitFunction(name, relatedTargetIndex) {
3335 return function() {
3336 arguments[relatedTargetIndex] = unwrap(arguments[relatedTargetIndex]);
3337 var impl = unwrap(this);
3338 impl[name].apply(impl, arguments);
3339 };
3340 }
3341
3342 var mouseEventProto = mixin({
3343 initMouseEvent: getInitFunction('initMouseEvent', 14)
3344 }, relatedTargetProto);
3345
3346 var focusEventProto = mixin({
3347 initFocusEvent: getInitFunction('initFocusEvent', 5)
3348 }, relatedTargetProto);
3349
3350 var MouseEvent = registerGenericEvent('MouseEvent', UIEvent, mouseEventProto);
3351 var FocusEvent = registerGenericEvent('FocusEvent', UIEvent, focusEventProto);
3352
3353 // In case the browser does not support event constructors we polyfill that
3354 // by calling `createEvent('Foo')` and `initFooEvent` where the arguments to
3355 // `initFooEvent` are derived from the registered default event init dict.
3356 var defaultInitDicts = Object.create(null);
3357
3358 var supportsEventConstructors = (function() {
3359 try {
3360 new window.FocusEvent('focus');
3361 } catch (ex) {
3362 return false;
3363 }
3364 return true;
3365 })();
3366
3367 /**
3368 * Constructs a new native event.
3369 */
3370 function constructEvent(OriginalEvent, name, type, options) {
3371 if (supportsEventConstructors)
3372 return new OriginalEvent(type, unwrapOptions(options));
3373
3374 // Create the arguments from the default dictionary.
3375 var event = unwrap(document.createEvent(name));
3376 var defaultDict = defaultInitDicts[name];
3377 var args = [type];
3378 Object.keys(defaultDict).forEach(function(key) {
3379 var v = options != null && key in options ?
3380 options[key] : defaultDict[key];
3381 if (key === 'relatedTarget')
3382 v = unwrap(v);
3383 args.push(v);
3384 });
3385 event['init' + name].apply(event, args);
3386 return event;
3387 }
3388
3389 if (!supportsEventConstructors) {
3390 var configureEventConstructor = function(name, initDict, superName) {
3391 if (superName) {
3392 var superDict = defaultInitDicts[superName];
3393 initDict = mixin(mixin({}, superDict), initDict);
3394 }
3395
3396 defaultInitDicts[name] = initDict;
3397 };
3398
3399 // The order of the default event init dictionary keys is important, the
3400 // arguments to initFooEvent is derived from that.
3401 configureEventConstructor('Event', {bubbles: false, cancelable: false});
3402 configureEventConstructor('CustomEvent', {detail: null}, 'Event');
3403 configureEventConstructor('UIEvent', {view: null, detail: 0}, 'Event');
3404 configureEventConstructor('MouseEvent', {
3405 screenX: 0,
3406 screenY: 0,
3407 clientX: 0,
3408 clientY: 0,
3409 ctrlKey: false,
3410 altKey: false,
3411 shiftKey: false,
3412 metaKey: false,
3413 button: 0,
3414 relatedTarget: null
3415 }, 'UIEvent');
3416 configureEventConstructor('FocusEvent', {relatedTarget: null}, 'UIEvent');
3417 }
3418
3419 // Safari 7 does not yet have BeforeUnloadEvent.
3420 // https://bugs.webkit.org/show_bug.cgi?id=120849
3421 var OriginalBeforeUnloadEvent = window.BeforeUnloadEvent;
3422
3423 function BeforeUnloadEvent(impl) {
3424 Event.call(this, impl);
3425 }
3426 BeforeUnloadEvent.prototype = Object.create(Event.prototype);
3427 mixin(BeforeUnloadEvent.prototype, {
3428 get returnValue() {
3429 return unsafeUnwrap(this).returnValue;
3430 },
3431 set returnValue(v) {
3432 unsafeUnwrap(this).returnValue = v;
3433 }
3434 });
3435
3436 if (OriginalBeforeUnloadEvent)
3437 registerWrapper(OriginalBeforeUnloadEvent, BeforeUnloadEvent);
3438
3439 function isValidListener(fun) {
3440 if (typeof fun === 'function')
3441 return true;
3442 return fun && fun.handleEvent;
3443 }
3444
3445 function isMutationEvent(type) {
3446 switch (type) {
3447 case 'DOMAttrModified':
3448 case 'DOMAttributeNameChanged':
3449 case 'DOMCharacterDataModified':
3450 case 'DOMElementNameChanged':
3451 case 'DOMNodeInserted':
3452 case 'DOMNodeInsertedIntoDocument':
3453 case 'DOMNodeRemoved':
3454 case 'DOMNodeRemovedFromDocument':
3455 case 'DOMSubtreeModified':
3456 return true;
3457 }
3458 return false;
3459 }
3460
3461 var OriginalEventTarget = window.EventTarget;
3462
3463 /**
3464 * This represents a wrapper for an EventTarget.
3465 * @param {!EventTarget} impl The original event target.
3466 * @constructor
3467 */
3468 function EventTarget(impl) {
3469 setWrapper(impl, this);
3470 }
3471
3472 // Node and Window have different internal type checks in WebKit so we cannot
3473 // use the same method as the original function.
3474 var methodNames = [
3475 'addEventListener',
3476 'removeEventListener',
3477 'dispatchEvent'
3478 ];
3479
3480 [Node, Window].forEach(function(constructor) {
3481 var p = constructor.prototype;
3482 methodNames.forEach(function(name) {
3483 Object.defineProperty(p, name + '_', {value: p[name]});
3484 });
3485 });
3486
3487 function getTargetToListenAt(wrapper) {
3488 if (wrapper instanceof wrappers.ShadowRoot)
3489 wrapper = wrapper.host;
3490 return unwrap(wrapper);
3491 }
3492
3493 EventTarget.prototype = {
3494 addEventListener: function(type, fun, capture) {
3495 if (!isValidListener(fun) || isMutationEvent(type))
3496 return;
3497
3498 var listener = new Listener(type, fun, capture);
3499 var listeners = listenersTable.get(this);
3500 if (!listeners) {
3501 listeners = [];
3502 listeners.depth = 0;
3503 listenersTable.set(this, listeners);
3504 } else {
3505 // Might have a duplicate.
3506 for (var i = 0; i < listeners.length; i++) {
3507 if (listener.equals(listeners[i]))
3508 return;
3509 }
3510 }
3511
3512 listeners.push(listener);
3513
3514 var target = getTargetToListenAt(this);
3515 target.addEventListener_(type, dispatchOriginalEvent, true);
3516 },
3517 removeEventListener: function(type, fun, capture) {
3518 capture = Boolean(capture);
3519 var listeners = listenersTable.get(this);
3520 if (!listeners)
3521 return;
3522 var count = 0, found = false;
3523 for (var i = 0; i < listeners.length; i++) {
3524 if (listeners[i].type === type && listeners[i].capture === capture) {
3525 count++;
3526 if (listeners[i].handler === fun) {
3527 found = true;
3528 listeners[i].remove();
3529 }
3530 }
3531 }
3532
3533 if (found && count === 1) {
3534 var target = getTargetToListenAt(this);
3535 target.removeEventListener_(type, dispatchOriginalEvent, true);
3536 }
3537 },
3538 dispatchEvent: function(event) {
3539 // We want to use the native dispatchEvent because it triggers the default
3540 // actions (like checking a checkbox). However, if there are no listeners
3541 // in the composed tree then there are no events that will trigger and
3542 // listeners in the non composed tree that are part of the event path are
3543 // not notified.
3544 //
3545 // If we find out that there are no listeners in the composed tree we add
3546 // a temporary listener to the target which makes us get called back even
3547 // in that case.
3548
3549 var nativeEvent = unwrap(event);
3550 var eventType = nativeEvent.type;
3551
3552 // Allow dispatching the same event again. This is safe because if user
3553 // code calls this during an existing dispatch of the same event the
3554 // native dispatchEvent throws (that is required by the spec).
3555 handledEventsTable.set(nativeEvent, false);
3556
3557 // Force rendering since we prefer native dispatch and that works on the
3558 // composed tree.
3559 scope.renderAllPending();
3560
3561 var tempListener;
3562 if (!hasListenerInAncestors(this, eventType)) {
3563 tempListener = function() {};
3564 this.addEventListener(eventType, tempListener, true);
3565 }
3566
3567 try {
3568 return unwrap(this).dispatchEvent_(nativeEvent);
3569 } finally {
3570 if (tempListener)
3571 this.removeEventListener(eventType, tempListener, true);
3572 }
3573 }
3574 };
3575
3576 function hasListener(node, type) {
3577 var listeners = listenersTable.get(node);
3578 if (listeners) {
3579 for (var i = 0; i < listeners.length; i++) {
3580 if (!listeners[i].removed && listeners[i].type === type)
3581 return true;
3582 }
3583 }
3584 return false;
3585 }
3586
3587 function hasListenerInAncestors(target, type) {
3588 for (var node = unwrap(target); node; node = node.parentNode) {
3589 if (hasListener(wrap(node), type))
3590 return true;
3591 }
3592 return false;
3593 }
3594
3595 if (OriginalEventTarget)
3596 registerWrapper(OriginalEventTarget, EventTarget);
3597
3598 function wrapEventTargetMethods(constructors) {
3599 forwardMethodsToWrapper(constructors, methodNames);
3600 }
3601
3602 var originalElementFromPoint = document.elementFromPoint;
3603
3604 function elementFromPoint(self, document, x, y) {
3605 scope.renderAllPending();
3606
3607 var element =
3608 wrap(originalElementFromPoint.call(unsafeUnwrap(document), x, y));
3609 if (!element)
3610 return null;
3611 var path = getEventPath(element, null);
3612
3613 // scope the path to this TreeScope
3614 var idx = path.lastIndexOf(self);
3615 if (idx == -1)
3616 return null;
3617 else
3618 path = path.slice(0, idx);
3619
3620 // TODO(dfreedm): pass idx to eventRetargetting to avoid array copy
3621 return eventRetargetting(path, self);
3622 }
3623
3624 /**
3625 * Returns a function that is to be used as a getter for `onfoo` properties.
3626 * @param {string} name
3627 * @return {Function}
3628 */
3629 function getEventHandlerGetter(name) {
3630 return function() {
3631 var inlineEventHandlers = eventHandlersTable.get(this);
3632 return inlineEventHandlers && inlineEventHandlers[name] &&
3633 inlineEventHandlers[name].value || null;
3634 };
3635 }
3636
3637 /**
3638 * Returns a function that is to be used as a setter for `onfoo` properties.
3639 * @param {string} name
3640 * @return {Function}
3641 */
3642 function getEventHandlerSetter(name) {
3643 var eventType = name.slice(2);
3644 return function(value) {
3645 var inlineEventHandlers = eventHandlersTable.get(this);
3646 if (!inlineEventHandlers) {
3647 inlineEventHandlers = Object.create(null);
3648 eventHandlersTable.set(this, inlineEventHandlers);
3649 }
3650
3651 var old = inlineEventHandlers[name];
3652 if (old)
3653 this.removeEventListener(eventType, old.wrapped, false);
3654
3655 if (typeof value === 'function') {
3656 var wrapped = function(e) {
3657 var rv = value.call(this, e);
3658 if (rv === false)
3659 e.preventDefault();
3660 else if (name === 'onbeforeunload' && typeof rv === 'string')
3661 e.returnValue = rv;
3662 // mouseover uses true for preventDefault but preventDefault for
3663 // mouseover is ignored by browsers these day.
3664 };
3665
3666 this.addEventListener(eventType, wrapped, false);
3667 inlineEventHandlers[name] = {
3668 value: value,
3669 wrapped: wrapped
3670 };
3671 }
3672 };
3673 }
3674
3675 scope.elementFromPoint = elementFromPoint;
3676 scope.getEventHandlerGetter = getEventHandlerGetter;
3677 scope.getEventHandlerSetter = getEventHandlerSetter;
3678 scope.wrapEventTargetMethods = wrapEventTargetMethods;
3679 scope.wrappers.BeforeUnloadEvent = BeforeUnloadEvent;
3680 scope.wrappers.CustomEvent = CustomEvent;
3681 scope.wrappers.Event = Event;
3682 scope.wrappers.EventTarget = EventTarget;
3683 scope.wrappers.FocusEvent = FocusEvent;
3684 scope.wrappers.MouseEvent = MouseEvent;
3685 scope.wrappers.UIEvent = UIEvent;
3686
3687 })(window.ShadowDOMPolyfill);
3688
3689 /*
3690 * Copyright 2014 The Polymer Authors. All rights reserved.
3691 * Use of this source code is goverened by a BSD-style
3692 * license that can be found in the LICENSE file.
3693 */
3694
3695 (function(scope) {
3696 'use strict';
3697
3698 var UIEvent = scope.wrappers.UIEvent;
3699 var mixin = scope.mixin;
3700 var registerWrapper = scope.registerWrapper;
3701 var setWrapper = scope.setWrapper;
3702 var unsafeUnwrap = scope.unsafeUnwrap;
3703 var wrap = scope.wrap;
3704
3705 // TouchEvent is WebKit/Blink only.
3706 var OriginalTouchEvent = window.TouchEvent;
3707 if (!OriginalTouchEvent)
3708 return;
3709
3710 var nativeEvent;
3711 try {
3712 nativeEvent = document.createEvent('TouchEvent');
3713 } catch (ex) {
3714 // In Chrome creating a TouchEvent fails if the feature is not turned on
3715 // which it isn't on desktop Chrome.
3716 return;
3717 }
3718
3719 var nonEnumDescriptor = {enumerable: false};
3720
3721 function nonEnum(obj, prop) {
3722 Object.defineProperty(obj, prop, nonEnumDescriptor);
3723 }
3724
3725 function Touch(impl) {
3726 setWrapper(impl, this);
3727 }
3728
3729 Touch.prototype = {
3730 get target() {
3731 return wrap(unsafeUnwrap(this).target);
3732 }
3733 };
3734
3735 var descr = {
3736 configurable: true,
3737 enumerable: true,
3738 get: null
3739 };
3740
3741 [
3742 'clientX',
3743 'clientY',
3744 'screenX',
3745 'screenY',
3746 'pageX',
3747 'pageY',
3748 'identifier',
3749 'webkitRadiusX',
3750 'webkitRadiusY',
3751 'webkitRotationAngle',
3752 'webkitForce'
3753 ].forEach(function(name) {
3754 descr.get = function() {
3755 return unsafeUnwrap(this)[name];
3756 };
3757 Object.defineProperty(Touch.prototype, name, descr);
3758 });
3759
3760 function TouchList() {
3761 this.length = 0;
3762 nonEnum(this, 'length');
3763 }
3764
3765 TouchList.prototype = {
3766 item: function(index) {
3767 return this[index];
3768 }
3769 };
3770
3771 function wrapTouchList(nativeTouchList) {
3772 var list = new TouchList();
3773 for (var i = 0; i < nativeTouchList.length; i++) {
3774 list[i] = new Touch(nativeTouchList[i]);
3775 }
3776 list.length = i;
3777 return list;
3778 }
3779
3780 function TouchEvent(impl) {
3781 UIEvent.call(this, impl);
3782 }
3783
3784 TouchEvent.prototype = Object.create(UIEvent.prototype);
3785
3786 mixin(TouchEvent.prototype, {
3787 get touches() {
3788 return wrapTouchList(unsafeUnwrap(this).touches);
3789 },
3790
3791 get targetTouches() {
3792 return wrapTouchList(unsafeUnwrap(this).targetTouches);
3793 },
3794
3795 get changedTouches() {
3796 return wrapTouchList(unsafeUnwrap(this).changedTouches);
3797 },
3798
3799 initTouchEvent: function() {
3800 // The only way to use this is to reuse the TouchList from an existing
3801 // TouchEvent. Since this is WebKit/Blink proprietary API we will not
3802 // implement this until someone screams.
3803 throw new Error('Not implemented');
3804 }
3805 });
3806
3807 registerWrapper(OriginalTouchEvent, TouchEvent, nativeEvent);
3808
3809 scope.wrappers.Touch = Touch;
3810 scope.wrappers.TouchEvent = TouchEvent;
3811 scope.wrappers.TouchList = TouchList;
3812
3813 })(window.ShadowDOMPolyfill);
3814
3815
3816 // Copyright 2012 The Polymer Authors. All rights reserved.
3817 // Use of this source code is goverened by a BSD-style
3818 // license that can be found in the LICENSE file.
3819
3820 (function(scope) {
3821 'use strict';
3822
3823 var unsafeUnwrap = scope.unsafeUnwrap;
3824 var wrap = scope.wrap;
3825
3826 var nonEnumDescriptor = {enumerable: false};
3827
3828 function nonEnum(obj, prop) {
3829 Object.defineProperty(obj, prop, nonEnumDescriptor);
3830 }
3831
3832 function NodeList() {
3833 this.length = 0;
3834 nonEnum(this, 'length');
3835 }
3836 NodeList.prototype = {
3837 item: function(index) {
3838 return this[index];
3839 }
3840 };
3841 nonEnum(NodeList.prototype, 'item');
3842
3843 function wrapNodeList(list) {
3844 if (list == null)
3845 return list;
3846 var wrapperList = new NodeList();
3847 for (var i = 0, length = list.length; i < length; i++) {
3848 wrapperList[i] = wrap(list[i]);
3849 }
3850 wrapperList.length = length;
3851 return wrapperList;
3852 }
3853
3854 function addWrapNodeListMethod(wrapperConstructor, name) {
3855 wrapperConstructor.prototype[name] = function() {
3856 return wrapNodeList(
3857 unsafeUnwrap(this)[name].apply(unsafeUnwrap(this), arguments));
3858 };
3859 }
3860
3861 scope.wrappers.NodeList = NodeList;
3862 scope.addWrapNodeListMethod = addWrapNodeListMethod;
3863 scope.wrapNodeList = wrapNodeList;
3864
3865 })(window.ShadowDOMPolyfill);
3866
3867 /*
3868 * Copyright 2014 The Polymer Authors. All rights reserved.
3869 * Use of this source code is goverened by a BSD-style
3870 * license that can be found in the LICENSE file.
3871 */
3872
3873 (function(scope) {
3874 'use strict';
3875
3876 // TODO(arv): Implement.
3877
3878 scope.wrapHTMLCollection = scope.wrapNodeList;
3879 scope.wrappers.HTMLCollection = scope.wrappers.NodeList;
3880
3881 })(window.ShadowDOMPolyfill);
3882
3883 /**
3884 * Copyright 2012 The Polymer Authors. All rights reserved.
3885 * Use of this source code is goverened by a BSD-style
3886 * license that can be found in the LICENSE file.
3887 */
3888
3889 (function(scope) {
3890 'use strict';
3891
3892 var EventTarget = scope.wrappers.EventTarget;
3893 var NodeList = scope.wrappers.NodeList;
3894 var TreeScope = scope.TreeScope;
3895 var assert = scope.assert;
3896 var defineWrapGetter = scope.defineWrapGetter;
3897 var enqueueMutation = scope.enqueueMutation;
3898 var getTreeScope = scope.getTreeScope;
3899 var isWrapper = scope.isWrapper;
3900 var mixin = scope.mixin;
3901 var registerTransientObservers = scope.registerTransientObservers;
3902 var registerWrapper = scope.registerWrapper;
3903 var setTreeScope = scope.setTreeScope;
3904 var unsafeUnwrap = scope.unsafeUnwrap;
3905 var unwrap = scope.unwrap;
3906 var unwrapIfNeeded = scope.unwrapIfNeeded;
3907 var wrap = scope.wrap;
3908 var wrapIfNeeded = scope.wrapIfNeeded;
3909 var wrappers = scope.wrappers;
3910
3911 function assertIsNodeWrapper(node) {
3912 assert(node instanceof Node);
3913 }
3914
3915 function createOneElementNodeList(node) {
3916 var nodes = new NodeList();
3917 nodes[0] = node;
3918 nodes.length = 1;
3919 return nodes;
3920 }
3921
3922 var surpressMutations = false;
3923
3924 /**
3925 * Called before node is inserted into a node to enqueue its removal from its
3926 * old parent.
3927 * @param {!Node} node The node that is about to be removed.
3928 * @param {!Node} parent The parent node that the node is being removed from.
3929 * @param {!NodeList} nodes The collected nodes.
3930 */
3931 function enqueueRemovalForInsertedNodes(node, parent, nodes) {
3932 enqueueMutation(parent, 'childList', {
3933 removedNodes: nodes,
3934 previousSibling: node.previousSibling,
3935 nextSibling: node.nextSibling
3936 });
3937 }
3938
3939 function enqueueRemovalForInsertedDocumentFragment(df, nodes) {
3940 enqueueMutation(df, 'childList', {
3941 removedNodes: nodes
3942 });
3943 }
3944
3945 /**
3946 * Collects nodes from a DocumentFragment or a Node for removal followed
3947 * by an insertion.
3948 *
3949 * This updates the internal pointers for node, previousNode and nextNode.
3950 */
3951 function collectNodes(node, parentNode, previousNode, nextNode) {
3952 if (node instanceof DocumentFragment) {
3953 var nodes = collectNodesForDocumentFragment(node);
3954
3955 // The extra loop is to work around bugs with DocumentFragments in IE.
3956 surpressMutations = true;
3957 for (var i = nodes.length - 1; i >= 0; i--) {
3958 node.removeChild(nodes[i]);
3959 nodes[i].parentNode_ = parentNode;
3960 }
3961 surpressMutations = false;
3962
3963 for (var i = 0; i < nodes.length; i++) {
3964 nodes[i].previousSibling_ = nodes[i - 1] || previousNode;
3965 nodes[i].nextSibling_ = nodes[i + 1] || nextNode;
3966 }
3967
3968 if (previousNode)
3969 previousNode.nextSibling_ = nodes[0];
3970 if (nextNode)
3971 nextNode.previousSibling_ = nodes[nodes.length - 1];
3972
3973 return nodes;
3974 }
3975
3976 var nodes = createOneElementNodeList(node);
3977 var oldParent = node.parentNode;
3978 if (oldParent) {
3979 // This will enqueue the mutation record for the removal as needed.
3980 oldParent.removeChild(node);
3981 }
3982
3983 node.parentNode_ = parentNode;
3984 node.previousSibling_ = previousNode;
3985 node.nextSibling_ = nextNode;
3986 if (previousNode)
3987 previousNode.nextSibling_ = node;
3988 if (nextNode)
3989 nextNode.previousSibling_ = node;
3990
3991 return nodes;
3992 }
3993
3994 function collectNodesNative(node) {
3995 if (node instanceof DocumentFragment)
3996 return collectNodesForDocumentFragment(node);
3997
3998 var nodes = createOneElementNodeList(node);
3999 var oldParent = node.parentNode;
4000 if (oldParent)
4001 enqueueRemovalForInsertedNodes(node, oldParent, nodes);
4002 return nodes;
4003 }
4004
4005 function collectNodesForDocumentFragment(node) {
4006 var nodes = new NodeList();
4007 var i = 0;
4008 for (var child = node.firstChild; child; child = child.nextSibling) {
4009 nodes[i++] = child;
4010 }
4011 nodes.length = i;
4012 enqueueRemovalForInsertedDocumentFragment(node, nodes);
4013 return nodes;
4014 }
4015
4016 function snapshotNodeList(nodeList) {
4017 // NodeLists are not live at the moment so just return the same object.
4018 return nodeList;
4019 }
4020
4021 // http://dom.spec.whatwg.org/#node-is-inserted
4022 function nodeWasAdded(node, treeScope) {
4023 setTreeScope(node, treeScope);
4024 node.nodeIsInserted_();
4025 }
4026
4027 function nodesWereAdded(nodes, parent) {
4028 var treeScope = getTreeScope(parent);
4029 for (var i = 0; i < nodes.length; i++) {
4030 nodeWasAdded(nodes[i], treeScope);
4031 }
4032 }
4033
4034 // http://dom.spec.whatwg.org/#node-is-removed
4035 function nodeWasRemoved(node) {
4036 setTreeScope(node, new TreeScope(node, null));
4037 }
4038
4039 function nodesWereRemoved(nodes) {
4040 for (var i = 0; i < nodes.length; i++) {
4041 nodeWasRemoved(nodes[i]);
4042 }
4043 }
4044
4045 function ensureSameOwnerDocument(parent, child) {
4046 var ownerDoc = parent.nodeType === Node.DOCUMENT_NODE ?
4047 parent : parent.ownerDocument;
4048 if (ownerDoc !== child.ownerDocument)
4049 ownerDoc.adoptNode(child);
4050 }
4051
4052 function adoptNodesIfNeeded(owner, nodes) {
4053 if (!nodes.length)
4054 return;
4055
4056 var ownerDoc = owner.ownerDocument;
4057
4058 // All nodes have the same ownerDocument when we get here.
4059 if (ownerDoc === nodes[0].ownerDocument)
4060 return;
4061
4062 for (var i = 0; i < nodes.length; i++) {
4063 scope.adoptNodeNoRemove(nodes[i], ownerDoc);
4064 }
4065 }
4066
4067 function unwrapNodesForInsertion(owner, nodes) {
4068 adoptNodesIfNeeded(owner, nodes);
4069 var length = nodes.length;
4070
4071 if (length === 1)
4072 return unwrap(nodes[0]);
4073
4074 var df = unwrap(owner.ownerDocument.createDocumentFragment());
4075 for (var i = 0; i < length; i++) {
4076 df.appendChild(unwrap(nodes[i]));
4077 }
4078 return df;
4079 }
4080
4081 function clearChildNodes(wrapper) {
4082 if (wrapper.firstChild_ !== undefined) {
4083 var child = wrapper.firstChild_;
4084 while (child) {
4085 var tmp = child;
4086 child = child.nextSibling_;
4087 tmp.parentNode_ = tmp.previousSibling_ = tmp.nextSibling_ = undefined;
4088 }
4089 }
4090 wrapper.firstChild_ = wrapper.lastChild_ = undefined;
4091 }
4092
4093 function removeAllChildNodes(wrapper) {
4094 if (wrapper.invalidateShadowRenderer()) {
4095 var childWrapper = wrapper.firstChild;
4096 while (childWrapper) {
4097 assert(childWrapper.parentNode === wrapper);
4098 var nextSibling = childWrapper.nextSibling;
4099 var childNode = unwrap(childWrapper);
4100 var parentNode = childNode.parentNode;
4101 if (parentNode)
4102 originalRemoveChild.call(parentNode, childNode);
4103 childWrapper.previousSibling_ = childWrapper.nextSibling_ =
4104 childWrapper.parentNode_ = null;
4105 childWrapper = nextSibling;
4106 }
4107 wrapper.firstChild_ = wrapper.lastChild_ = null;
4108 } else {
4109 var node = unwrap(wrapper);
4110 var child = node.firstChild;
4111 var nextSibling;
4112 while (child) {
4113 nextSibling = child.nextSibling;
4114 originalRemoveChild.call(node, child);
4115 child = nextSibling;
4116 }
4117 }
4118 }
4119
4120 function invalidateParent(node) {
4121 var p = node.parentNode;
4122 return p && p.invalidateShadowRenderer();
4123 }
4124
4125 function cleanupNodes(nodes) {
4126 for (var i = 0, n; i < nodes.length; i++) {
4127 n = nodes[i];
4128 n.parentNode.removeChild(n);
4129 }
4130 }
4131
4132 var originalImportNode = document.importNode;
4133 var originalCloneNode = window.Node.prototype.cloneNode;
4134
4135 function cloneNode(node, deep, opt_doc) {
4136 var clone;
4137 if (opt_doc)
4138 clone = wrap(originalImportNode.call(opt_doc, unsafeUnwrap(node), false));
4139 else
4140 clone = wrap(originalCloneNode.call(unsafeUnwrap(node), false));
4141
4142 if (deep) {
4143 for (var child = node.firstChild; child; child = child.nextSibling) {
4144 clone.appendChild(cloneNode(child, true, opt_doc));
4145 }
4146
4147 if (node instanceof wrappers.HTMLTemplateElement) {
4148 var cloneContent = clone.content;
4149 for (var child = node.content.firstChild;
4150 child;
4151 child = child.nextSibling) {
4152 cloneContent.appendChild(cloneNode(child, true, opt_doc));
4153 }
4154 }
4155 }
4156 // TODO(arv): Some HTML elements also clone other data like value.
4157 return clone;
4158 }
4159
4160 function contains(self, child) {
4161 if (!child || getTreeScope(self) !== getTreeScope(child))
4162 return false;
4163
4164 for (var node = child; node; node = node.parentNode) {
4165 if (node === self)
4166 return true;
4167 }
4168 return false;
4169 }
4170
4171 var OriginalNode = window.Node;
4172
4173 /**
4174 * This represents a wrapper of a native DOM node.
4175 * @param {!Node} original The original DOM node, aka, the visual DOM node.
4176 * @constructor
4177 * @extends {EventTarget}
4178 */
4179 function Node(original) {
4180 assert(original instanceof OriginalNode);
4181
4182 EventTarget.call(this, original);
4183
4184 // These properties are used to override the visual references with the
4185 // logical ones. If the value is undefined it means that the logical is the
4186 // same as the visual.
4187
4188 /**
4189 * @type {Node|undefined}
4190 * @private
4191 */
4192 this.parentNode_ = undefined;
4193
4194 /**
4195 * @type {Node|undefined}
4196 * @private
4197 */
4198 this.firstChild_ = undefined;
4199
4200 /**
4201 * @type {Node|undefined}
4202 * @private
4203 */
4204 this.lastChild_ = undefined;
4205
4206 /**
4207 * @type {Node|undefined}
4208 * @private
4209 */
4210 this.nextSibling_ = undefined;
4211
4212 /**
4213 * @type {Node|undefined}
4214 * @private
4215 */
4216 this.previousSibling_ = undefined;
4217
4218 this.treeScope_ = undefined;
4219 }
4220
4221 var OriginalDocumentFragment = window.DocumentFragment;
4222 var originalAppendChild = OriginalNode.prototype.appendChild;
4223 var originalCompareDocumentPosition =
4224 OriginalNode.prototype.compareDocumentPosition;
4225 var originalInsertBefore = OriginalNode.prototype.insertBefore;
4226 var originalRemoveChild = OriginalNode.prototype.removeChild;
4227 var originalReplaceChild = OriginalNode.prototype.replaceChild;
4228
4229 var isIe = /Trident/.test(navigator.userAgent);
4230
4231 var removeChildOriginalHelper = isIe ?
4232 function(parent, child) {
4233 try {
4234 originalRemoveChild.call(parent, child);
4235 } catch (ex) {
4236 if (!(parent instanceof OriginalDocumentFragment))
4237 throw ex;
4238 }
4239 } :
4240 function(parent, child) {
4241 originalRemoveChild.call(parent, child);
4242 };
4243
4244 Node.prototype = Object.create(EventTarget.prototype);
4245 mixin(Node.prototype, {
4246 appendChild: function(childWrapper) {
4247 return this.insertBefore(childWrapper, null);
4248 },
4249
4250 insertBefore: function(childWrapper, refWrapper) {
4251 assertIsNodeWrapper(childWrapper);
4252
4253 var refNode;
4254 if (refWrapper) {
4255 if (isWrapper(refWrapper)) {
4256 refNode = unwrap(refWrapper);
4257 } else {
4258 refNode = refWrapper;
4259 refWrapper = wrap(refNode);
4260 }
4261 } else {
4262 refWrapper = null;
4263 refNode = null;
4264 }
4265
4266 refWrapper && assert(refWrapper.parentNode === this);
4267
4268 var nodes;
4269 var previousNode =
4270 refWrapper ? refWrapper.previousSibling : this.lastChild;
4271
4272 var useNative = !this.invalidateShadowRenderer() &&
4273 !invalidateParent(childWrapper);
4274
4275 if (useNative)
4276 nodes = collectNodesNative(childWrapper);
4277 else
4278 nodes = collectNodes(childWrapper, this, previousNode, refWrapper);
4279
4280 if (useNative) {
4281 ensureSameOwnerDocument(this, childWrapper);
4282 clearChildNodes(this);
4283 originalInsertBefore.call(unsafeUnwrap(this), unwrap(childWrapper), refN ode);
4284 } else {
4285 if (!previousNode)
4286 this.firstChild_ = nodes[0];
4287 if (!refWrapper) {
4288 this.lastChild_ = nodes[nodes.length - 1];
4289 if (this.firstChild_ === undefined)
4290 this.firstChild_ = this.firstChild;
4291 }
4292
4293 var parentNode = refNode ? refNode.parentNode : unsafeUnwrap(this);
4294
4295 // insertBefore refWrapper no matter what the parent is?
4296 if (parentNode) {
4297 originalInsertBefore.call(parentNode,
4298 unwrapNodesForInsertion(this, nodes), refNode);
4299 } else {
4300 adoptNodesIfNeeded(this, nodes);
4301 }
4302 }
4303
4304 enqueueMutation(this, 'childList', {
4305 addedNodes: nodes,
4306 nextSibling: refWrapper,
4307 previousSibling: previousNode
4308 });
4309
4310 nodesWereAdded(nodes, this);
4311
4312 return childWrapper;
4313 },
4314
4315 removeChild: function(childWrapper) {
4316 assertIsNodeWrapper(childWrapper);
4317 if (childWrapper.parentNode !== this) {
4318 // IE has invalid DOM trees at times.
4319 var found = false;
4320 var childNodes = this.childNodes;
4321 for (var ieChild = this.firstChild; ieChild;
4322 ieChild = ieChild.nextSibling) {
4323 if (ieChild === childWrapper) {
4324 found = true;
4325 break;
4326 }
4327 }
4328 if (!found) {
4329 // TODO(arv): DOMException
4330 throw new Error('NotFoundError');
4331 }
4332 }
4333
4334 var childNode = unwrap(childWrapper);
4335 var childWrapperNextSibling = childWrapper.nextSibling;
4336 var childWrapperPreviousSibling = childWrapper.previousSibling;
4337
4338 if (this.invalidateShadowRenderer()) {
4339 // We need to remove the real node from the DOM before updating the
4340 // pointers. This is so that that mutation event is dispatched before
4341 // the pointers have changed.
4342 var thisFirstChild = this.firstChild;
4343 var thisLastChild = this.lastChild;
4344
4345 var parentNode = childNode.parentNode;
4346 if (parentNode)
4347 removeChildOriginalHelper(parentNode, childNode);
4348
4349 if (thisFirstChild === childWrapper)
4350 this.firstChild_ = childWrapperNextSibling;
4351 if (thisLastChild === childWrapper)
4352 this.lastChild_ = childWrapperPreviousSibling;
4353 if (childWrapperPreviousSibling)
4354 childWrapperPreviousSibling.nextSibling_ = childWrapperNextSibling;
4355 if (childWrapperNextSibling) {
4356 childWrapperNextSibling.previousSibling_ =
4357 childWrapperPreviousSibling;
4358 }
4359
4360 childWrapper.previousSibling_ = childWrapper.nextSibling_ =
4361 childWrapper.parentNode_ = undefined;
4362 } else {
4363 clearChildNodes(this);
4364 removeChildOriginalHelper(unsafeUnwrap(this), childNode);
4365 }
4366
4367 if (!surpressMutations) {
4368 enqueueMutation(this, 'childList', {
4369 removedNodes: createOneElementNodeList(childWrapper),
4370 nextSibling: childWrapperNextSibling,
4371 previousSibling: childWrapperPreviousSibling
4372 });
4373 }
4374
4375 registerTransientObservers(this, childWrapper);
4376
4377 return childWrapper;
4378 },
4379
4380 replaceChild: function(newChildWrapper, oldChildWrapper) {
4381 assertIsNodeWrapper(newChildWrapper);
4382
4383 var oldChildNode;
4384 if (isWrapper(oldChildWrapper)) {
4385 oldChildNode = unwrap(oldChildWrapper);
4386 } else {
4387 oldChildNode = oldChildWrapper;
4388 oldChildWrapper = wrap(oldChildNode);
4389 }
4390
4391 if (oldChildWrapper.parentNode !== this) {
4392 // TODO(arv): DOMException
4393 throw new Error('NotFoundError');
4394 }
4395
4396 var nextNode = oldChildWrapper.nextSibling;
4397 var previousNode = oldChildWrapper.previousSibling;
4398 var nodes;
4399
4400 var useNative = !this.invalidateShadowRenderer() &&
4401 !invalidateParent(newChildWrapper);
4402
4403 if (useNative) {
4404 nodes = collectNodesNative(newChildWrapper);
4405 } else {
4406 if (nextNode === newChildWrapper)
4407 nextNode = newChildWrapper.nextSibling;
4408 nodes = collectNodes(newChildWrapper, this, previousNode, nextNode);
4409 }
4410
4411 if (!useNative) {
4412 if (this.firstChild === oldChildWrapper)
4413 this.firstChild_ = nodes[0];
4414 if (this.lastChild === oldChildWrapper)
4415 this.lastChild_ = nodes[nodes.length - 1];
4416
4417 oldChildWrapper.previousSibling_ = oldChildWrapper.nextSibling_ =
4418 oldChildWrapper.parentNode_ = undefined;
4419
4420 // replaceChild no matter what the parent is?
4421 if (oldChildNode.parentNode) {
4422 originalReplaceChild.call(
4423 oldChildNode.parentNode,
4424 unwrapNodesForInsertion(this, nodes),
4425 oldChildNode);
4426 }
4427 } else {
4428 ensureSameOwnerDocument(this, newChildWrapper);
4429 clearChildNodes(this);
4430 originalReplaceChild.call(unsafeUnwrap(this), unwrap(newChildWrapper),
4431 oldChildNode);
4432 }
4433
4434 enqueueMutation(this, 'childList', {
4435 addedNodes: nodes,
4436 removedNodes: createOneElementNodeList(oldChildWrapper),
4437 nextSibling: nextNode,
4438 previousSibling: previousNode
4439 });
4440
4441 nodeWasRemoved(oldChildWrapper);
4442 nodesWereAdded(nodes, this);
4443
4444 return oldChildWrapper;
4445 },
4446
4447 /**
4448 * Called after a node was inserted. Subclasses override this to invalidate
4449 * the renderer as needed.
4450 * @private
4451 */
4452 nodeIsInserted_: function() {
4453 for (var child = this.firstChild; child; child = child.nextSibling) {
4454 child.nodeIsInserted_();
4455 }
4456 },
4457
4458 hasChildNodes: function() {
4459 return this.firstChild !== null;
4460 },
4461
4462 /** @type {Node} */
4463 get parentNode() {
4464 // If the parentNode has not been overridden, use the original parentNode.
4465 return this.parentNode_ !== undefined ?
4466 this.parentNode_ : wrap(unsafeUnwrap(this).parentNode);
4467 },
4468
4469 /** @type {Node} */
4470 get firstChild() {
4471 return this.firstChild_ !== undefined ?
4472 this.firstChild_ : wrap(unsafeUnwrap(this).firstChild);
4473 },
4474
4475 /** @type {Node} */
4476 get lastChild() {
4477 return this.lastChild_ !== undefined ?
4478 this.lastChild_ : wrap(unsafeUnwrap(this).lastChild);
4479 },
4480
4481 /** @type {Node} */
4482 get nextSibling() {
4483 return this.nextSibling_ !== undefined ?
4484 this.nextSibling_ : wrap(unsafeUnwrap(this).nextSibling);
4485 },
4486
4487 /** @type {Node} */
4488 get previousSibling() {
4489 return this.previousSibling_ !== undefined ?
4490 this.previousSibling_ : wrap(unsafeUnwrap(this).previousSibling);
4491 },
4492
4493 get parentElement() {
4494 var p = this.parentNode;
4495 while (p && p.nodeType !== Node.ELEMENT_NODE) {
4496 p = p.parentNode;
4497 }
4498 return p;
4499 },
4500
4501 get textContent() {
4502 // TODO(arv): This should fallback to unsafeUnwrap(this).textContent if th ere
4503 // are no shadow trees below or above the context node.
4504 var s = '';
4505 for (var child = this.firstChild; child; child = child.nextSibling) {
4506 if (child.nodeType != Node.COMMENT_NODE) {
4507 s += child.textContent;
4508 }
4509 }
4510 return s;
4511 },
4512 set textContent(textContent) {
4513 if (textContent == null) textContent = '';
4514 var removedNodes = snapshotNodeList(this.childNodes);
4515
4516 if (this.invalidateShadowRenderer()) {
4517 removeAllChildNodes(this);
4518 if (textContent !== '') {
4519 var textNode = unsafeUnwrap(this).ownerDocument.createTextNode(textCon tent);
4520 this.appendChild(textNode);
4521 }
4522 } else {
4523 clearChildNodes(this);
4524 unsafeUnwrap(this).textContent = textContent;
4525 }
4526
4527 var addedNodes = snapshotNodeList(this.childNodes);
4528
4529 enqueueMutation(this, 'childList', {
4530 addedNodes: addedNodes,
4531 removedNodes: removedNodes
4532 });
4533
4534 nodesWereRemoved(removedNodes);
4535 nodesWereAdded(addedNodes, this);
4536 },
4537
4538 get childNodes() {
4539 var wrapperList = new NodeList();
4540 var i = 0;
4541 for (var child = this.firstChild; child; child = child.nextSibling) {
4542 wrapperList[i++] = child;
4543 }
4544 wrapperList.length = i;
4545 return wrapperList;
4546 },
4547
4548 cloneNode: function(deep) {
4549 return cloneNode(this, deep);
4550 },
4551
4552 contains: function(child) {
4553 return contains(this, wrapIfNeeded(child));
4554 },
4555
4556 compareDocumentPosition: function(otherNode) {
4557 // This only wraps, it therefore only operates on the composed DOM and not
4558 // the logical DOM.
4559 return originalCompareDocumentPosition.call(unsafeUnwrap(this),
4560 unwrapIfNeeded(otherNode));
4561 },
4562
4563 normalize: function() {
4564 var nodes = snapshotNodeList(this.childNodes);
4565 var remNodes = [];
4566 var s = '';
4567 var modNode;
4568
4569 for (var i = 0, n; i < nodes.length; i++) {
4570 n = nodes[i];
4571 if (n.nodeType === Node.TEXT_NODE) {
4572 if (!modNode && !n.data.length)
4573 this.removeNode(n);
4574 else if (!modNode)
4575 modNode = n;
4576 else {
4577 s += n.data;
4578 remNodes.push(n);
4579 }
4580 } else {
4581 if (modNode && remNodes.length) {
4582 modNode.data += s;
4583 cleanupNodes(remNodes);
4584 }
4585 remNodes = [];
4586 s = '';
4587 modNode = null;
4588 if (n.childNodes.length)
4589 n.normalize();
4590 }
4591 }
4592
4593 // handle case where >1 text nodes are the last children
4594 if (modNode && remNodes.length) {
4595 modNode.data += s;
4596 cleanupNodes(remNodes);
4597 }
4598 }
4599 });
4600
4601 defineWrapGetter(Node, 'ownerDocument');
4602
4603 // We use a DocumentFragment as a base and then delete the properties of
4604 // DocumentFragment.prototype from the wrapper Node. Since delete makes
4605 // objects slow in some JS engines we recreate the prototype object.
4606 registerWrapper(OriginalNode, Node, document.createDocumentFragment());
4607 delete Node.prototype.querySelector;
4608 delete Node.prototype.querySelectorAll;
4609 Node.prototype = mixin(Object.create(EventTarget.prototype), Node.prototype);
4610
4611 scope.cloneNode = cloneNode;
4612 scope.nodeWasAdded = nodeWasAdded;
4613 scope.nodeWasRemoved = nodeWasRemoved;
4614 scope.nodesWereAdded = nodesWereAdded;
4615 scope.nodesWereRemoved = nodesWereRemoved;
4616 scope.originalInsertBefore = originalInsertBefore;
4617 scope.originalRemoveChild = originalRemoveChild;
4618 scope.snapshotNodeList = snapshotNodeList;
4619 scope.wrappers.Node = Node;
4620
4621 })(window.ShadowDOMPolyfill);
4622
4623 // Copyright 2013 The Polymer Authors. All rights reserved.
4624 // Use of this source code is governed by a BSD-style
4625 // license that can be found in the LICENSE file.
4626
4627 (function(scope) {
4628 'use strict';
4629
4630 var HTMLCollection = scope.wrappers.HTMLCollection;
4631 var NodeList = scope.wrappers.NodeList;
4632 var getTreeScope = scope.getTreeScope;
4633 var unsafeUnwrap = scope.unsafeUnwrap;
4634 var wrap = scope.wrap;
4635
4636 var originalDocumentQuerySelector = document.querySelector;
4637 var originalElementQuerySelector = document.documentElement.querySelector;
4638
4639 var originalDocumentQuerySelectorAll = document.querySelectorAll;
4640 var originalElementQuerySelectorAll = document.documentElement.querySelectorAl l;
4641
4642 var originalDocumentGetElementsByTagName = document.getElementsByTagName;
4643 var originalElementGetElementsByTagName = document.documentElement.getElements ByTagName;
4644
4645 var originalDocumentGetElementsByTagNameNS = document.getElementsByTagNameNS;
4646 var originalElementGetElementsByTagNameNS = document.documentElement.getElemen tsByTagNameNS;
4647
4648 var OriginalElement = window.Element;
4649 var OriginalDocument = window.HTMLDocument || window.Document;
4650
4651 function filterNodeList(list, index, result, deep) {
4652 var wrappedItem = null;
4653 var root = null;
4654 for (var i = 0, length = list.length; i < length; i++) {
4655 wrappedItem = wrap(list[i]);
4656 if (!deep && (root = getTreeScope(wrappedItem).root)) {
4657 if (root instanceof scope.wrappers.ShadowRoot) {
4658 continue;
4659 }
4660 }
4661 result[index++] = wrappedItem;
4662 }
4663
4664 return index;
4665 }
4666
4667 function shimSelector(selector) {
4668 return String(selector).replace(/\/deep\//g, ' ');
4669 }
4670
4671 function findOne(node, selector) {
4672 var m, el = node.firstElementChild;
4673 while (el) {
4674 if (el.matches(selector))
4675 return el;
4676 m = findOne(el, selector);
4677 if (m)
4678 return m;
4679 el = el.nextElementSibling;
4680 }
4681 return null;
4682 }
4683
4684 function matchesSelector(el, selector) {
4685 return el.matches(selector);
4686 }
4687
4688 var XHTML_NS = 'http://www.w3.org/1999/xhtml';
4689
4690 function matchesTagName(el, localName, localNameLowerCase) {
4691 var ln = el.localName;
4692 return ln === localName ||
4693 ln === localNameLowerCase && el.namespaceURI === XHTML_NS;
4694 }
4695
4696 function matchesEveryThing() {
4697 return true;
4698 }
4699
4700 function matchesLocalNameOnly(el, ns, localName) {
4701 return el.localName === localName;
4702 }
4703
4704 function matchesNameSpace(el, ns) {
4705 return el.namespaceURI === ns;
4706 }
4707
4708 function matchesLocalNameNS(el, ns, localName) {
4709 return el.namespaceURI === ns && el.localName === localName;
4710 }
4711
4712 function findElements(node, index, result, p, arg0, arg1) {
4713 var el = node.firstElementChild;
4714 while (el) {
4715 if (p(el, arg0, arg1))
4716 result[index++] = el;
4717 index = findElements(el, index, result, p, arg0, arg1);
4718 el = el.nextElementSibling;
4719 }
4720 return index;
4721 }
4722
4723 // find and findAll will only match Simple Selectors,
4724 // Structural Pseudo Classes are not guarenteed to be correct
4725 // http://www.w3.org/TR/css3-selectors/#simple-selectors
4726
4727 function querySelectorAllFiltered(p, index, result, selector, deep) {
4728 var target = unsafeUnwrap(this);
4729 var list;
4730 var root = getTreeScope(this).root;
4731 if (root instanceof scope.wrappers.ShadowRoot) {
4732 // We are in the shadow tree and the logical tree is
4733 // going to be disconnected so we do a manual tree traversal
4734 return findElements(this, index, result, p, selector, null);
4735 } else if (target instanceof OriginalElement) {
4736 list = originalElementQuerySelectorAll.call(target, selector);
4737 } else if (target instanceof OriginalDocument) {
4738 list = originalDocumentQuerySelectorAll.call(target, selector);
4739 } else {
4740 // When we get a ShadowRoot the logical tree is going to be disconnected
4741 // so we do a manual tree traversal
4742 return findElements(this, index, result, p, selector, null);
4743 }
4744
4745 return filterNodeList(list, index, result, deep);
4746 }
4747
4748 var SelectorsInterface = {
4749 querySelector: function(selector) {
4750 var shimmed = shimSelector(selector);
4751 var deep = shimmed !== selector;
4752 selector = shimmed;
4753
4754 var target = unsafeUnwrap(this);
4755 var wrappedItem;
4756 var root = getTreeScope(this).root;
4757 if (root instanceof scope.wrappers.ShadowRoot) {
4758 // We are in the shadow tree and the logical tree is
4759 // going to be disconnected so we do a manual tree traversal
4760 return findOne(this, selector);
4761 } else if (target instanceof OriginalElement) {
4762 wrappedItem = wrap(originalElementQuerySelector.call(target, selector));
4763 } else if (target instanceof OriginalDocument) {
4764 wrappedItem = wrap(originalDocumentQuerySelector.call(target, selector)) ;
4765 } else {
4766 // When we get a ShadowRoot the logical tree is going to be disconnected
4767 // so we do a manual tree traversal
4768 return findOne(this, selector);
4769 }
4770
4771 if (!wrappedItem) {
4772 // When the original query returns nothing
4773 // we return nothing (to be consistent with the other wrapped calls)
4774 return wrappedItem;
4775 } else if (!deep && (root = getTreeScope(wrappedItem).root)) {
4776 if (root instanceof scope.wrappers.ShadowRoot) {
4777 // When the original query returns an element in the ShadowDOM
4778 // we must do a manual tree traversal
4779 return findOne(this, selector);
4780 }
4781 }
4782
4783 return wrappedItem;
4784 },
4785 querySelectorAll: function(selector) {
4786 var shimmed = shimSelector(selector);
4787 var deep = shimmed !== selector;
4788 selector = shimmed;
4789
4790 var result = new NodeList();
4791
4792 result.length = querySelectorAllFiltered.call(this,
4793 matchesSelector,
4794 0,
4795 result,
4796 selector,
4797 deep);
4798
4799 return result;
4800 }
4801 };
4802
4803 function getElementsByTagNameFiltered(p, index, result, localName,
4804 lowercase) {
4805 var target = unsafeUnwrap(this);
4806 var list;
4807 var root = getTreeScope(this).root;
4808 if (root instanceof scope.wrappers.ShadowRoot) {
4809 // We are in the shadow tree and the logical tree is
4810 // going to be disconnected so we do a manual tree traversal
4811 return findElements(this, index, result, p, localName, lowercase);
4812 } else if (target instanceof OriginalElement) {
4813 list = originalElementGetElementsByTagName.call(target, localName,
4814 lowercase);
4815 } else if (target instanceof OriginalDocument) {
4816 list = originalDocumentGetElementsByTagName.call(target, localName,
4817 lowercase);
4818 } else {
4819 // When we get a ShadowRoot the logical tree is going to be disconnected
4820 // so we do a manual tree traversal
4821 return findElements(this, index, result, p, localName, lowercase);
4822 }
4823
4824 return filterNodeList(list, index, result, false);
4825 }
4826
4827 function getElementsByTagNameNSFiltered(p, index, result, ns, localName) {
4828 var target = unsafeUnwrap(this);
4829 var list;
4830 var root = getTreeScope(this).root;
4831 if (root instanceof scope.wrappers.ShadowRoot) {
4832 // We are in the shadow tree and the logical tree is
4833 // going to be disconnected so we do a manual tree traversal
4834 return findElements(this, index, result, p, ns, localName);
4835 } else if (target instanceof OriginalElement) {
4836 list = originalElementGetElementsByTagNameNS.call(target, ns, localName);
4837 } else if (target instanceof OriginalDocument) {
4838 list = originalDocumentGetElementsByTagNameNS.call(target, ns, localName);
4839 } else {
4840 // When we get a ShadowRoot the logical tree is going to be disconnected
4841 // so we do a manual tree traversal
4842 return findElements(this, index, result, p, ns, localName);
4843 }
4844
4845 return filterNodeList(list, index, result, false);
4846 }
4847
4848 var GetElementsByInterface = {
4849 getElementsByTagName: function(localName) {
4850 var result = new HTMLCollection();
4851 var match = localName === '*' ? matchesEveryThing : matchesTagName;
4852
4853 result.length = getElementsByTagNameFiltered.call(this,
4854 match,
4855 0,
4856 result,
4857 localName,
4858 localName.toLowerCase());
4859
4860 return result;
4861 },
4862
4863 getElementsByClassName: function(className) {
4864 // TODO(arv): Check className?
4865 return this.querySelectorAll('.' + className);
4866 },
4867
4868 getElementsByTagNameNS: function(ns, localName) {
4869 var result = new HTMLCollection();
4870 var match = null;
4871
4872 if (ns === '*') {
4873 match = localName === '*' ? matchesEveryThing : matchesLocalNameOnly;
4874 } else {
4875 match = localName === '*' ? matchesNameSpace : matchesLocalNameNS;
4876 }
4877
4878 result.length = getElementsByTagNameNSFiltered.call(this,
4879 match,
4880 0,
4881 result,
4882 ns || null,
4883 localName);
4884
4885 return result;
4886 }
4887 };
4888
4889 scope.GetElementsByInterface = GetElementsByInterface;
4890 scope.SelectorsInterface = SelectorsInterface;
4891
4892 })(window.ShadowDOMPolyfill);
4893
4894 // Copyright 2013 The Polymer Authors. All rights reserved.
4895 // Use of this source code is goverened by a BSD-style
4896 // license that can be found in the LICENSE file.
4897
4898 (function(scope) {
4899 'use strict';
4900
4901 var NodeList = scope.wrappers.NodeList;
4902
4903 function forwardElement(node) {
4904 while (node && node.nodeType !== Node.ELEMENT_NODE) {
4905 node = node.nextSibling;
4906 }
4907 return node;
4908 }
4909
4910 function backwardsElement(node) {
4911 while (node && node.nodeType !== Node.ELEMENT_NODE) {
4912 node = node.previousSibling;
4913 }
4914 return node;
4915 }
4916
4917 var ParentNodeInterface = {
4918 get firstElementChild() {
4919 return forwardElement(this.firstChild);
4920 },
4921
4922 get lastElementChild() {
4923 return backwardsElement(this.lastChild);
4924 },
4925
4926 get childElementCount() {
4927 var count = 0;
4928 for (var child = this.firstElementChild;
4929 child;
4930 child = child.nextElementSibling) {
4931 count++;
4932 }
4933 return count;
4934 },
4935
4936 get children() {
4937 var wrapperList = new NodeList();
4938 var i = 0;
4939 for (var child = this.firstElementChild;
4940 child;
4941 child = child.nextElementSibling) {
4942 wrapperList[i++] = child;
4943 }
4944 wrapperList.length = i;
4945 return wrapperList;
4946 },
4947
4948 remove: function() {
4949 var p = this.parentNode;
4950 if (p)
4951 p.removeChild(this);
4952 }
4953 };
4954
4955 var ChildNodeInterface = {
4956 get nextElementSibling() {
4957 return forwardElement(this.nextSibling);
4958 },
4959
4960 get previousElementSibling() {
4961 return backwardsElement(this.previousSibling);
4962 }
4963 };
4964
4965 scope.ChildNodeInterface = ChildNodeInterface;
4966 scope.ParentNodeInterface = ParentNodeInterface;
4967
4968 })(window.ShadowDOMPolyfill);
4969
4970 // Copyright 2013 The Polymer Authors. All rights reserved.
4971 // Use of this source code is goverened by a BSD-style
4972 // license that can be found in the LICENSE file.
4973
4974 (function(scope) {
4975 'use strict';
4976
4977 var ChildNodeInterface = scope.ChildNodeInterface;
4978 var Node = scope.wrappers.Node;
4979 var enqueueMutation = scope.enqueueMutation;
4980 var mixin = scope.mixin;
4981 var registerWrapper = scope.registerWrapper;
4982 var unsafeUnwrap = scope.unsafeUnwrap;
4983
4984 var OriginalCharacterData = window.CharacterData;
4985
4986 function CharacterData(node) {
4987 Node.call(this, node);
4988 }
4989 CharacterData.prototype = Object.create(Node.prototype);
4990 mixin(CharacterData.prototype, {
4991 get textContent() {
4992 return this.data;
4993 },
4994 set textContent(value) {
4995 this.data = value;
4996 },
4997 get data() {
4998 return unsafeUnwrap(this).data;
4999 },
5000 set data(value) {
5001 var oldValue = unsafeUnwrap(this).data;
5002 enqueueMutation(this, 'characterData', {
5003 oldValue: oldValue
5004 });
5005 unsafeUnwrap(this).data = value;
5006 }
5007 });
5008
5009 mixin(CharacterData.prototype, ChildNodeInterface);
5010
5011 registerWrapper(OriginalCharacterData, CharacterData,
5012 document.createTextNode(''));
5013
5014 scope.wrappers.CharacterData = CharacterData;
5015 })(window.ShadowDOMPolyfill);
5016
5017 // Copyright 2014 The Polymer Authors. All rights reserved.
5018 // Use of this source code is goverened by a BSD-style
5019 // license that can be found in the LICENSE file.
5020
5021 (function(scope) {
5022 'use strict';
5023
5024 var CharacterData = scope.wrappers.CharacterData;
5025 var enqueueMutation = scope.enqueueMutation;
5026 var mixin = scope.mixin;
5027 var registerWrapper = scope.registerWrapper;
5028
5029 function toUInt32(x) {
5030 return x >>> 0;
5031 }
5032
5033 var OriginalText = window.Text;
5034
5035 function Text(node) {
5036 CharacterData.call(this, node);
5037 }
5038 Text.prototype = Object.create(CharacterData.prototype);
5039 mixin(Text.prototype, {
5040 splitText: function(offset) {
5041 offset = toUInt32(offset);
5042 var s = this.data;
5043 if (offset > s.length)
5044 throw new Error('IndexSizeError');
5045 var head = s.slice(0, offset);
5046 var tail = s.slice(offset);
5047 this.data = head;
5048 var newTextNode = this.ownerDocument.createTextNode(tail);
5049 if (this.parentNode)
5050 this.parentNode.insertBefore(newTextNode, this.nextSibling);
5051 return newTextNode;
5052 }
5053 });
5054
5055 registerWrapper(OriginalText, Text, document.createTextNode(''));
5056
5057 scope.wrappers.Text = Text;
5058 })(window.ShadowDOMPolyfill);
5059
5060 // Copyright 2014 The Polymer Authors. All rights reserved.
5061 // Use of this source code is goverened by a BSD-style
5062 // license that can be found in the LICENSE file.
5063
5064 (function(scope) {
5065 'use strict';
5066
5067 var setWrapper = scope.setWrapper;
5068 var unsafeUnwrap = scope.unsafeUnwrap;
5069
5070 function invalidateClass(el) {
5071 scope.invalidateRendererBasedOnAttribute(el, 'class');
5072 }
5073
5074 function DOMTokenList(impl, ownerElement) {
5075 setWrapper(impl, this);
5076 this.ownerElement_ = ownerElement;
5077 }
5078
5079 DOMTokenList.prototype = {
5080 constructor: DOMTokenList,
5081 get length() {
5082 return unsafeUnwrap(this).length;
5083 },
5084 item: function(index) {
5085 return unsafeUnwrap(this).item(index);
5086 },
5087 contains: function(token) {
5088 return unsafeUnwrap(this).contains(token);
5089 },
5090 add: function() {
5091 unsafeUnwrap(this).add.apply(unsafeUnwrap(this), arguments);
5092 invalidateClass(this.ownerElement_);
5093 },
5094 remove: function() {
5095 unsafeUnwrap(this).remove.apply(unsafeUnwrap(this), arguments);
5096 invalidateClass(this.ownerElement_);
5097 },
5098 toggle: function(token) {
5099 var rv = unsafeUnwrap(this).toggle.apply(unsafeUnwrap(this), arguments);
5100 invalidateClass(this.ownerElement_);
5101 return rv;
5102 },
5103 toString: function() {
5104 return unsafeUnwrap(this).toString();
5105 }
5106 };
5107
5108 scope.wrappers.DOMTokenList = DOMTokenList;
5109 })(window.ShadowDOMPolyfill);
5110
5111 // Copyright 2013 The Polymer Authors. All rights reserved.
5112 // Use of this source code is goverened by a BSD-style
5113 // license that can be found in the LICENSE file.
5114
5115 (function(scope) {
5116 'use strict';
5117
5118 var ChildNodeInterface = scope.ChildNodeInterface;
5119 var GetElementsByInterface = scope.GetElementsByInterface;
5120 var Node = scope.wrappers.Node;
5121 var DOMTokenList = scope.wrappers.DOMTokenList;
5122 var ParentNodeInterface = scope.ParentNodeInterface;
5123 var SelectorsInterface = scope.SelectorsInterface;
5124 var addWrapNodeListMethod = scope.addWrapNodeListMethod;
5125 var enqueueMutation = scope.enqueueMutation;
5126 var mixin = scope.mixin;
5127 var oneOf = scope.oneOf;
5128 var registerWrapper = scope.registerWrapper;
5129 var unsafeUnwrap = scope.unsafeUnwrap;
5130 var wrappers = scope.wrappers;
5131
5132 var OriginalElement = window.Element;
5133
5134 var matchesNames = [
5135 'matches', // needs to come first.
5136 'mozMatchesSelector',
5137 'msMatchesSelector',
5138 'webkitMatchesSelector',
5139 ].filter(function(name) {
5140 return OriginalElement.prototype[name];
5141 });
5142
5143 var matchesName = matchesNames[0];
5144
5145 var originalMatches = OriginalElement.prototype[matchesName];
5146
5147 function invalidateRendererBasedOnAttribute(element, name) {
5148 // Only invalidate if parent node is a shadow host.
5149 var p = element.parentNode;
5150 if (!p || !p.shadowRoot)
5151 return;
5152
5153 var renderer = scope.getRendererForHost(p);
5154 if (renderer.dependsOnAttribute(name))
5155 renderer.invalidate();
5156 }
5157
5158 function enqueAttributeChange(element, name, oldValue) {
5159 // This is not fully spec compliant. We should use localName (which might
5160 // have a different case than name) and the namespace (which requires us
5161 // to get the Attr object).
5162 enqueueMutation(element, 'attributes', {
5163 name: name,
5164 namespace: null,
5165 oldValue: oldValue
5166 });
5167 }
5168
5169 var classListTable = new WeakMap();
5170
5171 function Element(node) {
5172 Node.call(this, node);
5173 }
5174 Element.prototype = Object.create(Node.prototype);
5175 mixin(Element.prototype, {
5176 createShadowRoot: function() {
5177 var newShadowRoot = new wrappers.ShadowRoot(this);
5178 unsafeUnwrap(this).polymerShadowRoot_ = newShadowRoot;
5179
5180 var renderer = scope.getRendererForHost(this);
5181 renderer.invalidate();
5182
5183 return newShadowRoot;
5184 },
5185
5186 get shadowRoot() {
5187 return unsafeUnwrap(this).polymerShadowRoot_ || null;
5188 },
5189
5190 // getDestinationInsertionPoints added in ShadowRenderer.js
5191
5192 setAttribute: function(name, value) {
5193 var oldValue = unsafeUnwrap(this).getAttribute(name);
5194 unsafeUnwrap(this).setAttribute(name, value);
5195 enqueAttributeChange(this, name, oldValue);
5196 invalidateRendererBasedOnAttribute(this, name);
5197 },
5198
5199 removeAttribute: function(name) {
5200 var oldValue = unsafeUnwrap(this).getAttribute(name);
5201 unsafeUnwrap(this).removeAttribute(name);
5202 enqueAttributeChange(this, name, oldValue);
5203 invalidateRendererBasedOnAttribute(this, name);
5204 },
5205
5206 matches: function(selector) {
5207 return originalMatches.call(unsafeUnwrap(this), selector);
5208 },
5209
5210 get classList() {
5211 var list = classListTable.get(this);
5212 if (!list) {
5213 classListTable.set(this,
5214 list = new DOMTokenList(unsafeUnwrap(this).classList, this));
5215 }
5216 return list;
5217 },
5218
5219 get className() {
5220 return unsafeUnwrap(this).className;
5221 },
5222
5223 set className(v) {
5224 this.setAttribute('class', v);
5225 },
5226
5227 get id() {
5228 return unsafeUnwrap(this).id;
5229 },
5230
5231 set id(v) {
5232 this.setAttribute('id', v);
5233 }
5234 });
5235
5236 matchesNames.forEach(function(name) {
5237 if (name !== 'matches') {
5238 Element.prototype[name] = function(selector) {
5239 return this.matches(selector);
5240 };
5241 }
5242 });
5243
5244 if (OriginalElement.prototype.webkitCreateShadowRoot) {
5245 Element.prototype.webkitCreateShadowRoot =
5246 Element.prototype.createShadowRoot;
5247 }
5248
5249 mixin(Element.prototype, ChildNodeInterface);
5250 mixin(Element.prototype, GetElementsByInterface);
5251 mixin(Element.prototype, ParentNodeInterface);
5252 mixin(Element.prototype, SelectorsInterface);
5253
5254 registerWrapper(OriginalElement, Element,
5255 document.createElementNS(null, 'x'));
5256
5257 scope.invalidateRendererBasedOnAttribute = invalidateRendererBasedOnAttribute;
5258 scope.matchesNames = matchesNames;
5259 scope.wrappers.Element = Element;
5260 })(window.ShadowDOMPolyfill);
5261
5262 // Copyright 2013 The Polymer Authors. All rights reserved.
5263 // Use of this source code is goverened by a BSD-style
5264 // license that can be found in the LICENSE file.
5265
5266 (function(scope) {
5267 'use strict';
5268
5269 var Element = scope.wrappers.Element;
5270 var defineGetter = scope.defineGetter;
5271 var enqueueMutation = scope.enqueueMutation;
5272 var mixin = scope.mixin;
5273 var nodesWereAdded = scope.nodesWereAdded;
5274 var nodesWereRemoved = scope.nodesWereRemoved;
5275 var registerWrapper = scope.registerWrapper;
5276 var snapshotNodeList = scope.snapshotNodeList;
5277 var unsafeUnwrap = scope.unsafeUnwrap;
5278 var unwrap = scope.unwrap;
5279 var wrap = scope.wrap;
5280 var wrappers = scope.wrappers;
5281
5282 /////////////////////////////////////////////////////////////////////////////
5283 // innerHTML and outerHTML
5284
5285 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#es capingString
5286 var escapeAttrRegExp = /[&\u00A0"]/g;
5287 var escapeDataRegExp = /[&\u00A0<>]/g;
5288
5289 function escapeReplace(c) {
5290 switch (c) {
5291 case '&':
5292 return '&amp;';
5293 case '<':
5294 return '&lt;';
5295 case '>':
5296 return '&gt;';
5297 case '"':
5298 return '&quot;'
5299 case '\u00A0':
5300 return '&nbsp;';
5301 }
5302 }
5303
5304 function escapeAttr(s) {
5305 return s.replace(escapeAttrRegExp, escapeReplace);
5306 }
5307
5308 function escapeData(s) {
5309 return s.replace(escapeDataRegExp, escapeReplace);
5310 }
5311
5312 function makeSet(arr) {
5313 var set = {};
5314 for (var i = 0; i < arr.length; i++) {
5315 set[arr[i]] = true;
5316 }
5317 return set;
5318 }
5319
5320 // http://www.whatwg.org/specs/web-apps/current-work/#void-elements
5321 var voidElements = makeSet([
5322 'area',
5323 'base',
5324 'br',
5325 'col',
5326 'command',
5327 'embed',
5328 'hr',
5329 'img',
5330 'input',
5331 'keygen',
5332 'link',
5333 'meta',
5334 'param',
5335 'source',
5336 'track',
5337 'wbr'
5338 ]);
5339
5340 var plaintextParents = makeSet([
5341 'style',
5342 'script',
5343 'xmp',
5344 'iframe',
5345 'noembed',
5346 'noframes',
5347 'plaintext',
5348 'noscript'
5349 ]);
5350
5351 function getOuterHTML(node, parentNode) {
5352 switch (node.nodeType) {
5353 case Node.ELEMENT_NODE:
5354 var tagName = node.tagName.toLowerCase();
5355 var s = '<' + tagName;
5356 var attrs = node.attributes;
5357 for (var i = 0, attr; attr = attrs[i]; i++) {
5358 s += ' ' + attr.name + '="' + escapeAttr(attr.value) + '"';
5359 }
5360 s += '>';
5361 if (voidElements[tagName])
5362 return s;
5363
5364 return s + getInnerHTML(node) + '</' + tagName + '>';
5365
5366 case Node.TEXT_NODE:
5367 var data = node.data;
5368 if (parentNode && plaintextParents[parentNode.localName])
5369 return data;
5370 return escapeData(data);
5371
5372 case Node.COMMENT_NODE:
5373 return '<!--' + node.data + '-->';
5374
5375 default:
5376 console.error(node);
5377 throw new Error('not implemented');
5378 }
5379 }
5380
5381 function getInnerHTML(node) {
5382 if (node instanceof wrappers.HTMLTemplateElement)
5383 node = node.content;
5384
5385 var s = '';
5386 for (var child = node.firstChild; child; child = child.nextSibling) {
5387 s += getOuterHTML(child, node);
5388 }
5389 return s;
5390 }
5391
5392 function setInnerHTML(node, value, opt_tagName) {
5393 var tagName = opt_tagName || 'div';
5394 node.textContent = '';
5395 var tempElement = unwrap(node.ownerDocument.createElement(tagName));
5396 tempElement.innerHTML = value;
5397 var firstChild;
5398 while (firstChild = tempElement.firstChild) {
5399 node.appendChild(wrap(firstChild));
5400 }
5401 }
5402
5403 // IE11 does not have MSIE in the user agent string.
5404 var oldIe = /MSIE/.test(navigator.userAgent);
5405
5406 var OriginalHTMLElement = window.HTMLElement;
5407 var OriginalHTMLTemplateElement = window.HTMLTemplateElement;
5408
5409 function HTMLElement(node) {
5410 Element.call(this, node);
5411 }
5412 HTMLElement.prototype = Object.create(Element.prototype);
5413 mixin(HTMLElement.prototype, {
5414 get innerHTML() {
5415 return getInnerHTML(this);
5416 },
5417 set innerHTML(value) {
5418 // IE9 does not handle set innerHTML correctly on plaintextParents. It
5419 // creates element children. For example
5420 //
5421 // scriptElement.innerHTML = '<a>test</a>'
5422 //
5423 // Creates a single HTMLAnchorElement child.
5424 if (oldIe && plaintextParents[this.localName]) {
5425 this.textContent = value;
5426 return;
5427 }
5428
5429 var removedNodes = snapshotNodeList(this.childNodes);
5430
5431 if (this.invalidateShadowRenderer()) {
5432 if (this instanceof wrappers.HTMLTemplateElement)
5433 setInnerHTML(this.content, value);
5434 else
5435 setInnerHTML(this, value, this.tagName);
5436
5437 // If we have a non native template element we need to handle this
5438 // manually since setting impl.innerHTML would add the html as direct
5439 // children and not be moved over to the content fragment.
5440 } else if (!OriginalHTMLTemplateElement &&
5441 this instanceof wrappers.HTMLTemplateElement) {
5442 setInnerHTML(this.content, value);
5443 } else {
5444 unsafeUnwrap(this).innerHTML = value;
5445 }
5446
5447 var addedNodes = snapshotNodeList(this.childNodes);
5448
5449 enqueueMutation(this, 'childList', {
5450 addedNodes: addedNodes,
5451 removedNodes: removedNodes
5452 });
5453
5454 nodesWereRemoved(removedNodes);
5455 nodesWereAdded(addedNodes, this);
5456 },
5457
5458 get outerHTML() {
5459 return getOuterHTML(this, this.parentNode);
5460 },
5461 set outerHTML(value) {
5462 var p = this.parentNode;
5463 if (p) {
5464 p.invalidateShadowRenderer();
5465 var df = frag(p, value);
5466 p.replaceChild(df, this);
5467 }
5468 },
5469
5470 insertAdjacentHTML: function(position, text) {
5471 var contextElement, refNode;
5472 switch (String(position).toLowerCase()) {
5473 case 'beforebegin':
5474 contextElement = this.parentNode;
5475 refNode = this;
5476 break;
5477 case 'afterend':
5478 contextElement = this.parentNode;
5479 refNode = this.nextSibling;
5480 break;
5481 case 'afterbegin':
5482 contextElement = this;
5483 refNode = this.firstChild;
5484 break;
5485 case 'beforeend':
5486 contextElement = this;
5487 refNode = null;
5488 break;
5489 default:
5490 return;
5491 }
5492
5493 var df = frag(contextElement, text);
5494 contextElement.insertBefore(df, refNode);
5495 },
5496
5497 get hidden() {
5498 return this.hasAttribute('hidden');
5499 },
5500 set hidden(v) {
5501 if (v) {
5502 this.setAttribute('hidden', '');
5503 } else {
5504 this.removeAttribute('hidden');
5505 }
5506 }
5507 });
5508
5509 function frag(contextElement, html) {
5510 // TODO(arv): This does not work with SVG and other non HTML elements.
5511 var p = unwrap(contextElement.cloneNode(false));
5512 p.innerHTML = html;
5513 var df = unwrap(document.createDocumentFragment());
5514 var c;
5515 while (c = p.firstChild) {
5516 df.appendChild(c);
5517 }
5518 return wrap(df);
5519 }
5520
5521 function getter(name) {
5522 return function() {
5523 scope.renderAllPending();
5524 return unsafeUnwrap(this)[name];
5525 };
5526 }
5527
5528 function getterRequiresRendering(name) {
5529 defineGetter(HTMLElement, name, getter(name));
5530 }
5531
5532 [
5533 'clientHeight',
5534 'clientLeft',
5535 'clientTop',
5536 'clientWidth',
5537 'offsetHeight',
5538 'offsetLeft',
5539 'offsetTop',
5540 'offsetWidth',
5541 'scrollHeight',
5542 'scrollWidth',
5543 ].forEach(getterRequiresRendering);
5544
5545 function getterAndSetterRequiresRendering(name) {
5546 Object.defineProperty(HTMLElement.prototype, name, {
5547 get: getter(name),
5548 set: function(v) {
5549 scope.renderAllPending();
5550 unsafeUnwrap(this)[name] = v;
5551 },
5552 configurable: true,
5553 enumerable: true
5554 });
5555 }
5556
5557 [
5558 'scrollLeft',
5559 'scrollTop',
5560 ].forEach(getterAndSetterRequiresRendering);
5561
5562 function methodRequiresRendering(name) {
5563 Object.defineProperty(HTMLElement.prototype, name, {
5564 value: function() {
5565 scope.renderAllPending();
5566 return unsafeUnwrap(this)[name].apply(unsafeUnwrap(this), arguments);
5567 },
5568 configurable: true,
5569 enumerable: true
5570 });
5571 }
5572
5573 [
5574 'getBoundingClientRect',
5575 'getClientRects',
5576 'scrollIntoView'
5577 ].forEach(methodRequiresRendering);
5578
5579 // HTMLElement is abstract so we use a subclass that has no members.
5580 registerWrapper(OriginalHTMLElement, HTMLElement,
5581 document.createElement('b'));
5582
5583 scope.wrappers.HTMLElement = HTMLElement;
5584
5585 // TODO: Find a better way to share these two with WrapperShadowRoot.
5586 scope.getInnerHTML = getInnerHTML;
5587 scope.setInnerHTML = setInnerHTML
5588 })(window.ShadowDOMPolyfill);
5589
5590 // Copyright 2013 The Polymer Authors. All rights reserved.
5591 // Use of this source code is goverened by a BSD-style
5592 // license that can be found in the LICENSE file.
5593
5594 (function(scope) {
5595 'use strict';
5596
5597 var HTMLElement = scope.wrappers.HTMLElement;
5598 var mixin = scope.mixin;
5599 var registerWrapper = scope.registerWrapper;
5600 var unsafeUnwrap = scope.unsafeUnwrap;
5601 var wrap = scope.wrap;
5602
5603 var OriginalHTMLCanvasElement = window.HTMLCanvasElement;
5604
5605 function HTMLCanvasElement(node) {
5606 HTMLElement.call(this, node);
5607 }
5608 HTMLCanvasElement.prototype = Object.create(HTMLElement.prototype);
5609
5610 mixin(HTMLCanvasElement.prototype, {
5611 getContext: function() {
5612 var context = unsafeUnwrap(this).getContext.apply(unsafeUnwrap(this), argu ments);
5613 return context && wrap(context);
5614 }
5615 });
5616
5617 registerWrapper(OriginalHTMLCanvasElement, HTMLCanvasElement,
5618 document.createElement('canvas'));
5619
5620 scope.wrappers.HTMLCanvasElement = HTMLCanvasElement;
5621 })(window.ShadowDOMPolyfill);
5622
5623 // Copyright 2013 The Polymer Authors. All rights reserved.
5624 // Use of this source code is goverened by a BSD-style
5625 // license that can be found in the LICENSE file.
5626
5627 (function(scope) {
5628 'use strict';
5629
5630 var HTMLElement = scope.wrappers.HTMLElement;
5631 var mixin = scope.mixin;
5632 var registerWrapper = scope.registerWrapper;
5633
5634 var OriginalHTMLContentElement = window.HTMLContentElement;
5635
5636 function HTMLContentElement(node) {
5637 HTMLElement.call(this, node);
5638 }
5639 HTMLContentElement.prototype = Object.create(HTMLElement.prototype);
5640 mixin(HTMLContentElement.prototype, {
5641 constructor: HTMLContentElement,
5642
5643 get select() {
5644 return this.getAttribute('select');
5645 },
5646 set select(value) {
5647 this.setAttribute('select', value);
5648 },
5649
5650 setAttribute: function(n, v) {
5651 HTMLElement.prototype.setAttribute.call(this, n, v);
5652 if (String(n).toLowerCase() === 'select')
5653 this.invalidateShadowRenderer(true);
5654 }
5655
5656 // getDistributedNodes is added in ShadowRenderer
5657 });
5658
5659 if (OriginalHTMLContentElement)
5660 registerWrapper(OriginalHTMLContentElement, HTMLContentElement);
5661
5662 scope.wrappers.HTMLContentElement = HTMLContentElement;
5663 })(window.ShadowDOMPolyfill);
5664
5665 /*
5666 * Copyright 2014 The Polymer Authors. All rights reserved.
5667 * Use of this source code is governed by a BSD-style
5668 * license that can be found in the LICENSE file.
5669 */
5670
5671 (function(scope) {
5672 'use strict';
5673
5674 var HTMLElement = scope.wrappers.HTMLElement;
5675 var mixin = scope.mixin;
5676 var registerWrapper = scope.registerWrapper;
5677 var wrapHTMLCollection = scope.wrapHTMLCollection;
5678 var unwrap = scope.unwrap;
5679
5680 var OriginalHTMLFormElement = window.HTMLFormElement;
5681
5682 function HTMLFormElement(node) {
5683 HTMLElement.call(this, node);
5684 }
5685 HTMLFormElement.prototype = Object.create(HTMLElement.prototype);
5686 mixin(HTMLFormElement.prototype, {
5687 get elements() {
5688 // Note: technically this should be an HTMLFormControlsCollection, but
5689 // that inherits from HTMLCollection, so should be good enough. Spec:
5690 // http://www.whatwg.org/specs/web-apps/current-work/multipage/common-dom- interfaces.html#htmlformcontrolscollection
5691 return wrapHTMLCollection(unwrap(this).elements);
5692 }
5693 });
5694
5695 registerWrapper(OriginalHTMLFormElement, HTMLFormElement,
5696 document.createElement('form'));
5697
5698 scope.wrappers.HTMLFormElement = HTMLFormElement;
5699 })(window.ShadowDOMPolyfill);
5700
5701 // Copyright 2013 The Polymer Authors. All rights reserved.
5702 // Use of this source code is goverened by a BSD-style
5703 // license that can be found in the LICENSE file.
5704
5705 (function(scope) {
5706 'use strict';
5707
5708 var HTMLElement = scope.wrappers.HTMLElement;
5709 var registerWrapper = scope.registerWrapper;
5710 var unwrap = scope.unwrap;
5711 var rewrap = scope.rewrap;
5712
5713 var OriginalHTMLImageElement = window.HTMLImageElement;
5714
5715 function HTMLImageElement(node) {
5716 HTMLElement.call(this, node);
5717 }
5718 HTMLImageElement.prototype = Object.create(HTMLElement.prototype);
5719
5720 registerWrapper(OriginalHTMLImageElement, HTMLImageElement,
5721 document.createElement('img'));
5722
5723 function Image(width, height) {
5724 if (!(this instanceof Image)) {
5725 throw new TypeError(
5726 'DOM object constructor cannot be called as a function.');
5727 }
5728
5729 var node = unwrap(document.createElement('img'));
5730 HTMLElement.call(this, node);
5731 rewrap(node, this);
5732
5733 if (width !== undefined)
5734 node.width = width;
5735 if (height !== undefined)
5736 node.height = height;
5737 }
5738
5739 Image.prototype = HTMLImageElement.prototype;
5740
5741 scope.wrappers.HTMLImageElement = HTMLImageElement;
5742 scope.wrappers.Image = Image;
5743 })(window.ShadowDOMPolyfill);
5744
5745 // Copyright 2013 The Polymer Authors. All rights reserved.
5746 // Use of this source code is goverened by a BSD-style
5747 // license that can be found in the LICENSE file.
5748
5749 (function(scope) {
5750 'use strict';
5751
5752 var HTMLElement = scope.wrappers.HTMLElement;
5753 var mixin = scope.mixin;
5754 var NodeList = scope.wrappers.NodeList;
5755 var registerWrapper = scope.registerWrapper;
5756
5757 var OriginalHTMLShadowElement = window.HTMLShadowElement;
5758
5759 function HTMLShadowElement(node) {
5760 HTMLElement.call(this, node);
5761 }
5762 HTMLShadowElement.prototype = Object.create(HTMLElement.prototype);
5763 HTMLShadowElement.prototype.constructor = HTMLShadowElement;
5764
5765 // getDistributedNodes is added in ShadowRenderer
5766
5767 if (OriginalHTMLShadowElement)
5768 registerWrapper(OriginalHTMLShadowElement, HTMLShadowElement);
5769
5770 scope.wrappers.HTMLShadowElement = HTMLShadowElement;
5771 })(window.ShadowDOMPolyfill);
5772
5773 // Copyright 2013 The Polymer Authors. All rights reserved.
5774 // Use of this source code is goverened by a BSD-style
5775 // license that can be found in the LICENSE file.
5776
5777 (function(scope) {
5778 'use strict';
5779
5780 var HTMLElement = scope.wrappers.HTMLElement;
5781 var mixin = scope.mixin;
5782 var registerWrapper = scope.registerWrapper;
5783 var unsafeUnwrap = scope.unsafeUnwrap;
5784 var unwrap = scope.unwrap;
5785 var wrap = scope.wrap;
5786
5787 var contentTable = new WeakMap();
5788 var templateContentsOwnerTable = new WeakMap();
5789
5790 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html# dfn-template-contents-owner
5791 function getTemplateContentsOwner(doc) {
5792 if (!doc.defaultView)
5793 return doc;
5794 var d = templateContentsOwnerTable.get(doc);
5795 if (!d) {
5796 // TODO(arv): This should either be a Document or HTMLDocument depending
5797 // on doc.
5798 d = doc.implementation.createHTMLDocument('');
5799 while (d.lastChild) {
5800 d.removeChild(d.lastChild);
5801 }
5802 templateContentsOwnerTable.set(doc, d);
5803 }
5804 return d;
5805 }
5806
5807 function extractContent(templateElement) {
5808 // templateElement is not a wrapper here.
5809 var doc = getTemplateContentsOwner(templateElement.ownerDocument);
5810 var df = unwrap(doc.createDocumentFragment());
5811 var child;
5812 while (child = templateElement.firstChild) {
5813 df.appendChild(child);
5814 }
5815 return df;
5816 }
5817
5818 var OriginalHTMLTemplateElement = window.HTMLTemplateElement;
5819
5820 function HTMLTemplateElement(node) {
5821 HTMLElement.call(this, node);
5822 if (!OriginalHTMLTemplateElement) {
5823 var content = extractContent(node);
5824 contentTable.set(this, wrap(content));
5825 }
5826 }
5827 HTMLTemplateElement.prototype = Object.create(HTMLElement.prototype);
5828
5829 mixin(HTMLTemplateElement.prototype, {
5830 constructor: HTMLTemplateElement,
5831 get content() {
5832 if (OriginalHTMLTemplateElement)
5833 return wrap(unsafeUnwrap(this).content);
5834 return contentTable.get(this);
5835 },
5836
5837 // TODO(arv): cloneNode needs to clone content.
5838
5839 });
5840
5841 if (OriginalHTMLTemplateElement)
5842 registerWrapper(OriginalHTMLTemplateElement, HTMLTemplateElement);
5843
5844 scope.wrappers.HTMLTemplateElement = HTMLTemplateElement;
5845 })(window.ShadowDOMPolyfill);
5846
5847 // Copyright 2013 The Polymer Authors. All rights reserved.
5848 // Use of this source code is goverened by a BSD-style
5849 // license that can be found in the LICENSE file.
5850
5851 (function(scope) {
5852 'use strict';
5853
5854 var HTMLElement = scope.wrappers.HTMLElement;
5855 var registerWrapper = scope.registerWrapper;
5856
5857 var OriginalHTMLMediaElement = window.HTMLMediaElement;
5858
5859 if (!OriginalHTMLMediaElement) return;
5860
5861 function HTMLMediaElement(node) {
5862 HTMLElement.call(this, node);
5863 }
5864 HTMLMediaElement.prototype = Object.create(HTMLElement.prototype);
5865
5866 registerWrapper(OriginalHTMLMediaElement, HTMLMediaElement,
5867 document.createElement('audio'));
5868
5869 scope.wrappers.HTMLMediaElement = HTMLMediaElement;
5870 })(window.ShadowDOMPolyfill);
5871
5872 // Copyright 2013 The Polymer Authors. All rights reserved.
5873 // Use of this source code is goverened by a BSD-style
5874 // license that can be found in the LICENSE file.
5875
5876 (function(scope) {
5877 'use strict';
5878
5879 var HTMLMediaElement = scope.wrappers.HTMLMediaElement;
5880 var registerWrapper = scope.registerWrapper;
5881 var unwrap = scope.unwrap;
5882 var rewrap = scope.rewrap;
5883
5884 var OriginalHTMLAudioElement = window.HTMLAudioElement;
5885
5886 if (!OriginalHTMLAudioElement) return;
5887
5888 function HTMLAudioElement(node) {
5889 HTMLMediaElement.call(this, node);
5890 }
5891 HTMLAudioElement.prototype = Object.create(HTMLMediaElement.prototype);
5892
5893 registerWrapper(OriginalHTMLAudioElement, HTMLAudioElement,
5894 document.createElement('audio'));
5895
5896 function Audio(src) {
5897 if (!(this instanceof Audio)) {
5898 throw new TypeError(
5899 'DOM object constructor cannot be called as a function.');
5900 }
5901
5902 var node = unwrap(document.createElement('audio'));
5903 HTMLMediaElement.call(this, node);
5904 rewrap(node, this);
5905
5906 node.setAttribute('preload', 'auto');
5907 if (src !== undefined)
5908 node.setAttribute('src', src);
5909 }
5910
5911 Audio.prototype = HTMLAudioElement.prototype;
5912
5913 scope.wrappers.HTMLAudioElement = HTMLAudioElement;
5914 scope.wrappers.Audio = Audio;
5915 })(window.ShadowDOMPolyfill);
5916
5917 // Copyright 2013 The Polymer Authors. All rights reserved.
5918 // Use of this source code is goverened by a BSD-style
5919 // license that can be found in the LICENSE file.
5920
5921 (function(scope) {
5922 'use strict';
5923
5924 var HTMLElement = scope.wrappers.HTMLElement;
5925 var mixin = scope.mixin;
5926 var registerWrapper = scope.registerWrapper;
5927 var rewrap = scope.rewrap;
5928 var unwrap = scope.unwrap;
5929 var wrap = scope.wrap;
5930
5931 var OriginalHTMLOptionElement = window.HTMLOptionElement;
5932
5933 function trimText(s) {
5934 return s.replace(/\s+/g, ' ').trim();
5935 }
5936
5937 function HTMLOptionElement(node) {
5938 HTMLElement.call(this, node);
5939 }
5940 HTMLOptionElement.prototype = Object.create(HTMLElement.prototype);
5941 mixin(HTMLOptionElement.prototype, {
5942 get text() {
5943 return trimText(this.textContent);
5944 },
5945 set text(value) {
5946 this.textContent = trimText(String(value));
5947 },
5948 get form() {
5949 return wrap(unwrap(this).form);
5950 }
5951 });
5952
5953 registerWrapper(OriginalHTMLOptionElement, HTMLOptionElement,
5954 document.createElement('option'));
5955
5956 function Option(text, value, defaultSelected, selected) {
5957 if (!(this instanceof Option)) {
5958 throw new TypeError(
5959 'DOM object constructor cannot be called as a function.');
5960 }
5961
5962 var node = unwrap(document.createElement('option'));
5963 HTMLElement.call(this, node);
5964 rewrap(node, this);
5965
5966 if (text !== undefined)
5967 node.text = text;
5968 if (value !== undefined)
5969 node.setAttribute('value', value);
5970 if (defaultSelected === true)
5971 node.setAttribute('selected', '');
5972 node.selected = selected === true;
5973 }
5974
5975 Option.prototype = HTMLOptionElement.prototype;
5976
5977 scope.wrappers.HTMLOptionElement = HTMLOptionElement;
5978 scope.wrappers.Option = Option;
5979 })(window.ShadowDOMPolyfill);
5980
5981 // Copyright 2014 The Polymer Authors. All rights reserved.
5982 // Use of this source code is goverened by a BSD-style
5983 // license that can be found in the LICENSE file.
5984
5985 (function(scope) {
5986 'use strict';
5987
5988 var HTMLElement = scope.wrappers.HTMLElement;
5989 var mixin = scope.mixin;
5990 var registerWrapper = scope.registerWrapper;
5991 var unwrap = scope.unwrap;
5992 var wrap = scope.wrap;
5993
5994 var OriginalHTMLSelectElement = window.HTMLSelectElement;
5995
5996 function HTMLSelectElement(node) {
5997 HTMLElement.call(this, node);
5998 }
5999 HTMLSelectElement.prototype = Object.create(HTMLElement.prototype);
6000 mixin(HTMLSelectElement.prototype, {
6001 add: function(element, before) {
6002 if (typeof before === 'object') // also includes null
6003 before = unwrap(before);
6004 unwrap(this).add(unwrap(element), before);
6005 },
6006
6007 remove: function(indexOrNode) {
6008 // Spec only allows index but implementations allow index or node.
6009 // remove() is also allowed which is same as remove(undefined)
6010 if (indexOrNode === undefined) {
6011 HTMLElement.prototype.remove.call(this);
6012 return;
6013 }
6014
6015 if (typeof indexOrNode === 'object')
6016 indexOrNode = unwrap(indexOrNode);
6017
6018 unwrap(this).remove(indexOrNode);
6019 },
6020
6021 get form() {
6022 return wrap(unwrap(this).form);
6023 }
6024 });
6025
6026 registerWrapper(OriginalHTMLSelectElement, HTMLSelectElement,
6027 document.createElement('select'));
6028
6029 scope.wrappers.HTMLSelectElement = HTMLSelectElement;
6030 })(window.ShadowDOMPolyfill);
6031
6032 /*
6033 * Copyright 2014 The Polymer Authors. All rights reserved.
6034 * Use of this source code is goverened by a BSD-style
6035 * license that can be found in the LICENSE file.
6036 */
6037
6038 (function(scope) {
6039 'use strict';
6040
6041 var HTMLElement = scope.wrappers.HTMLElement;
6042 var mixin = scope.mixin;
6043 var registerWrapper = scope.registerWrapper;
6044 var unwrap = scope.unwrap;
6045 var wrap = scope.wrap;
6046 var wrapHTMLCollection = scope.wrapHTMLCollection;
6047
6048 var OriginalHTMLTableElement = window.HTMLTableElement;
6049
6050 function HTMLTableElement(node) {
6051 HTMLElement.call(this, node);
6052 }
6053 HTMLTableElement.prototype = Object.create(HTMLElement.prototype);
6054 mixin(HTMLTableElement.prototype, {
6055 get caption() {
6056 return wrap(unwrap(this).caption);
6057 },
6058 createCaption: function() {
6059 return wrap(unwrap(this).createCaption());
6060 },
6061
6062 get tHead() {
6063 return wrap(unwrap(this).tHead);
6064 },
6065 createTHead: function() {
6066 return wrap(unwrap(this).createTHead());
6067 },
6068
6069 createTFoot: function() {
6070 return wrap(unwrap(this).createTFoot());
6071 },
6072 get tFoot() {
6073 return wrap(unwrap(this).tFoot);
6074 },
6075
6076 get tBodies() {
6077 return wrapHTMLCollection(unwrap(this).tBodies);
6078 },
6079 createTBody: function() {
6080 return wrap(unwrap(this).createTBody());
6081 },
6082
6083 get rows() {
6084 return wrapHTMLCollection(unwrap(this).rows);
6085 },
6086 insertRow: function(index) {
6087 return wrap(unwrap(this).insertRow(index));
6088 }
6089 });
6090
6091 registerWrapper(OriginalHTMLTableElement, HTMLTableElement,
6092 document.createElement('table'));
6093
6094 scope.wrappers.HTMLTableElement = HTMLTableElement;
6095 })(window.ShadowDOMPolyfill);
6096
6097 /*
6098 * Copyright 2014 The Polymer Authors. All rights reserved.
6099 * Use of this source code is goverened by a BSD-style
6100 * license that can be found in the LICENSE file.
6101 */
6102
6103 (function(scope) {
6104 'use strict';
6105
6106 var HTMLElement = scope.wrappers.HTMLElement;
6107 var mixin = scope.mixin;
6108 var registerWrapper = scope.registerWrapper;
6109 var wrapHTMLCollection = scope.wrapHTMLCollection;
6110 var unwrap = scope.unwrap;
6111 var wrap = scope.wrap;
6112
6113 var OriginalHTMLTableSectionElement = window.HTMLTableSectionElement;
6114
6115 function HTMLTableSectionElement(node) {
6116 HTMLElement.call(this, node);
6117 }
6118 HTMLTableSectionElement.prototype = Object.create(HTMLElement.prototype);
6119 mixin(HTMLTableSectionElement.prototype, {
6120 constructor: HTMLTableSectionElement,
6121 get rows() {
6122 return wrapHTMLCollection(unwrap(this).rows);
6123 },
6124 insertRow: function(index) {
6125 return wrap(unwrap(this).insertRow(index));
6126 }
6127 });
6128
6129 registerWrapper(OriginalHTMLTableSectionElement, HTMLTableSectionElement,
6130 document.createElement('thead'));
6131
6132 scope.wrappers.HTMLTableSectionElement = HTMLTableSectionElement;
6133 })(window.ShadowDOMPolyfill);
6134
6135 /*
6136 * Copyright 2014 The Polymer Authors. All rights reserved.
6137 * Use of this source code is goverened by a BSD-style
6138 * license that can be found in the LICENSE file.
6139 */
6140
6141 (function(scope) {
6142 'use strict';
6143
6144 var HTMLElement = scope.wrappers.HTMLElement;
6145 var mixin = scope.mixin;
6146 var registerWrapper = scope.registerWrapper;
6147 var wrapHTMLCollection = scope.wrapHTMLCollection;
6148 var unwrap = scope.unwrap;
6149 var wrap = scope.wrap;
6150
6151 var OriginalHTMLTableRowElement = window.HTMLTableRowElement;
6152
6153 function HTMLTableRowElement(node) {
6154 HTMLElement.call(this, node);
6155 }
6156 HTMLTableRowElement.prototype = Object.create(HTMLElement.prototype);
6157 mixin(HTMLTableRowElement.prototype, {
6158 get cells() {
6159 return wrapHTMLCollection(unwrap(this).cells);
6160 },
6161
6162 insertCell: function(index) {
6163 return wrap(unwrap(this).insertCell(index));
6164 }
6165 });
6166
6167 registerWrapper(OriginalHTMLTableRowElement, HTMLTableRowElement,
6168 document.createElement('tr'));
6169
6170 scope.wrappers.HTMLTableRowElement = HTMLTableRowElement;
6171 })(window.ShadowDOMPolyfill);
6172
6173 // Copyright 2013 The Polymer Authors. All rights reserved.
6174 // Use of this source code is goverened by a BSD-style
6175 // license that can be found in the LICENSE file.
6176
6177 (function(scope) {
6178 'use strict';
6179
6180 var HTMLContentElement = scope.wrappers.HTMLContentElement;
6181 var HTMLElement = scope.wrappers.HTMLElement;
6182 var HTMLShadowElement = scope.wrappers.HTMLShadowElement;
6183 var HTMLTemplateElement = scope.wrappers.HTMLTemplateElement;
6184 var mixin = scope.mixin;
6185 var registerWrapper = scope.registerWrapper;
6186
6187 var OriginalHTMLUnknownElement = window.HTMLUnknownElement;
6188
6189 function HTMLUnknownElement(node) {
6190 switch (node.localName) {
6191 case 'content':
6192 return new HTMLContentElement(node);
6193 case 'shadow':
6194 return new HTMLShadowElement(node);
6195 case 'template':
6196 return new HTMLTemplateElement(node);
6197 }
6198 HTMLElement.call(this, node);
6199 }
6200 HTMLUnknownElement.prototype = Object.create(HTMLElement.prototype);
6201 registerWrapper(OriginalHTMLUnknownElement, HTMLUnknownElement);
6202 scope.wrappers.HTMLUnknownElement = HTMLUnknownElement;
6203 })(window.ShadowDOMPolyfill);
6204
6205 // Copyright 2014 The Polymer Authors. All rights reserved.
6206 // Use of this source code is goverened by a BSD-style
6207 // license that can be found in the LICENSE file.
6208
6209 (function(scope) {
6210 'use strict';
6211
6212 var Element = scope.wrappers.Element;
6213 var HTMLElement = scope.wrappers.HTMLElement;
6214 var registerObject = scope.registerObject;
6215
6216 var SVG_NS = 'http://www.w3.org/2000/svg';
6217 var svgTitleElement = document.createElementNS(SVG_NS, 'title');
6218 var SVGTitleElement = registerObject(svgTitleElement);
6219 var SVGElement = Object.getPrototypeOf(SVGTitleElement.prototype).constructor;
6220
6221 // IE11 does not have classList for SVG elements. The spec says that classList
6222 // is an accessor on Element, but IE11 puts classList on HTMLElement, leaving
6223 // SVGElement without a classList property. We therefore move the accessor for
6224 // IE11.
6225 if (!('classList' in svgTitleElement)) {
6226 var descr = Object.getOwnPropertyDescriptor(Element.prototype, 'classList');
6227 Object.defineProperty(HTMLElement.prototype, 'classList', descr);
6228 delete Element.prototype.classList;
6229 }
6230
6231 scope.wrappers.SVGElement = SVGElement;
6232 })(window.ShadowDOMPolyfill);
6233
6234 // Copyright 2014 The Polymer Authors. All rights reserved.
6235 // Use of this source code is goverened by a BSD-style
6236 // license that can be found in the LICENSE file.
6237
6238 (function(scope) {
6239 'use strict';
6240
6241 var mixin = scope.mixin;
6242 var registerWrapper = scope.registerWrapper;
6243 var unwrap = scope.unwrap;
6244 var wrap = scope.wrap;
6245
6246 var OriginalSVGUseElement = window.SVGUseElement;
6247
6248 // IE uses SVGElement as parent interface, SVG2 (Blink & Gecko) uses
6249 // SVGGraphicsElement. Use the <g> element to get the right prototype.
6250
6251 var SVG_NS = 'http://www.w3.org/2000/svg';
6252 var gWrapper = wrap(document.createElementNS(SVG_NS, 'g'));
6253 var useElement = document.createElementNS(SVG_NS, 'use');
6254 var SVGGElement = gWrapper.constructor;
6255 var parentInterfacePrototype = Object.getPrototypeOf(SVGGElement.prototype);
6256 var parentInterface = parentInterfacePrototype.constructor;
6257
6258 function SVGUseElement(impl) {
6259 parentInterface.call(this, impl);
6260 }
6261
6262 SVGUseElement.prototype = Object.create(parentInterfacePrototype);
6263
6264 // Firefox does not expose instanceRoot.
6265 if ('instanceRoot' in useElement) {
6266 mixin(SVGUseElement.prototype, {
6267 get instanceRoot() {
6268 return wrap(unwrap(this).instanceRoot);
6269 },
6270 get animatedInstanceRoot() {
6271 return wrap(unwrap(this).animatedInstanceRoot);
6272 },
6273 });
6274 }
6275
6276 registerWrapper(OriginalSVGUseElement, SVGUseElement, useElement);
6277
6278 scope.wrappers.SVGUseElement = SVGUseElement;
6279 })(window.ShadowDOMPolyfill);
6280
6281 // Copyright 2014 The Polymer Authors. All rights reserved.
6282 // Use of this source code is goverened by a BSD-style
6283 // license that can be found in the LICENSE file.
6284
6285 (function(scope) {
6286 'use strict';
6287
6288 var EventTarget = scope.wrappers.EventTarget;
6289 var mixin = scope.mixin;
6290 var registerWrapper = scope.registerWrapper;
6291 var unsafeUnwrap = scope.unsafeUnwrap;
6292 var wrap = scope.wrap;
6293
6294 var OriginalSVGElementInstance = window.SVGElementInstance;
6295 if (!OriginalSVGElementInstance)
6296 return;
6297
6298 function SVGElementInstance(impl) {
6299 EventTarget.call(this, impl);
6300 }
6301
6302 SVGElementInstance.prototype = Object.create(EventTarget.prototype);
6303 mixin(SVGElementInstance.prototype, {
6304 /** @type {SVGElement} */
6305 get correspondingElement() {
6306 return wrap(unsafeUnwrap(this).correspondingElement);
6307 },
6308
6309 /** @type {SVGUseElement} */
6310 get correspondingUseElement() {
6311 return wrap(unsafeUnwrap(this).correspondingUseElement);
6312 },
6313
6314 /** @type {SVGElementInstance} */
6315 get parentNode() {
6316 return wrap(unsafeUnwrap(this).parentNode);
6317 },
6318
6319 /** @type {SVGElementInstanceList} */
6320 get childNodes() {
6321 throw new Error('Not implemented');
6322 },
6323
6324 /** @type {SVGElementInstance} */
6325 get firstChild() {
6326 return wrap(unsafeUnwrap(this).firstChild);
6327 },
6328
6329 /** @type {SVGElementInstance} */
6330 get lastChild() {
6331 return wrap(unsafeUnwrap(this).lastChild);
6332 },
6333
6334 /** @type {SVGElementInstance} */
6335 get previousSibling() {
6336 return wrap(unsafeUnwrap(this).previousSibling);
6337 },
6338
6339 /** @type {SVGElementInstance} */
6340 get nextSibling() {
6341 return wrap(unsafeUnwrap(this).nextSibling);
6342 }
6343 });
6344
6345 registerWrapper(OriginalSVGElementInstance, SVGElementInstance);
6346
6347 scope.wrappers.SVGElementInstance = SVGElementInstance;
6348 })(window.ShadowDOMPolyfill);
6349
6350 // Copyright 2013 The Polymer Authors. All rights reserved.
6351 // Use of this source code is goverened by a BSD-style
6352 // license that can be found in the LICENSE file.
6353
6354 (function(scope) {
6355 'use strict';
6356
6357 var mixin = scope.mixin;
6358 var registerWrapper = scope.registerWrapper;
6359 var setWrapper = scope.setWrapper;
6360 var unsafeUnwrap = scope.unsafeUnwrap;
6361 var unwrap = scope.unwrap;
6362 var unwrapIfNeeded = scope.unwrapIfNeeded;
6363 var wrap = scope.wrap;
6364
6365 var OriginalCanvasRenderingContext2D = window.CanvasRenderingContext2D;
6366
6367 function CanvasRenderingContext2D(impl) {
6368 setWrapper(impl, this);
6369 }
6370
6371 mixin(CanvasRenderingContext2D.prototype, {
6372 get canvas() {
6373 return wrap(unsafeUnwrap(this).canvas);
6374 },
6375
6376 drawImage: function() {
6377 arguments[0] = unwrapIfNeeded(arguments[0]);
6378 unsafeUnwrap(this).drawImage.apply(unsafeUnwrap(this), arguments);
6379 },
6380
6381 createPattern: function() {
6382 arguments[0] = unwrap(arguments[0]);
6383 return unsafeUnwrap(this).createPattern.apply(unsafeUnwrap(this), argument s);
6384 }
6385 });
6386
6387 registerWrapper(OriginalCanvasRenderingContext2D, CanvasRenderingContext2D,
6388 document.createElement('canvas').getContext('2d'));
6389
6390 scope.wrappers.CanvasRenderingContext2D = CanvasRenderingContext2D;
6391 })(window.ShadowDOMPolyfill);
6392
6393 // Copyright 2013 The Polymer Authors. All rights reserved.
6394 // Use of this source code is goverened by a BSD-style
6395 // license that can be found in the LICENSE file.
6396
6397 (function(scope) {
6398 'use strict';
6399
6400 var mixin = scope.mixin;
6401 var registerWrapper = scope.registerWrapper;
6402 var setWrapper = scope.setWrapper;
6403 var unsafeUnwrap = scope.unsafeUnwrap;
6404 var unwrapIfNeeded = scope.unwrapIfNeeded;
6405 var wrap = scope.wrap;
6406
6407 var OriginalWebGLRenderingContext = window.WebGLRenderingContext;
6408
6409 // IE10 does not have WebGL.
6410 if (!OriginalWebGLRenderingContext)
6411 return;
6412
6413 function WebGLRenderingContext(impl) {
6414 setWrapper(impl, this);
6415 }
6416
6417 mixin(WebGLRenderingContext.prototype, {
6418 get canvas() {
6419 return wrap(unsafeUnwrap(this).canvas);
6420 },
6421
6422 texImage2D: function() {
6423 arguments[5] = unwrapIfNeeded(arguments[5]);
6424 unsafeUnwrap(this).texImage2D.apply(unsafeUnwrap(this), arguments);
6425 },
6426
6427 texSubImage2D: function() {
6428 arguments[6] = unwrapIfNeeded(arguments[6]);
6429 unsafeUnwrap(this).texSubImage2D.apply(unsafeUnwrap(this), arguments);
6430 }
6431 });
6432
6433 // Blink/WebKit has broken DOM bindings. Usually we would create an instance
6434 // of the object and pass it into registerWrapper as a "blueprint" but
6435 // creating WebGL contexts is expensive and might fail so we use a dummy
6436 // object with dummy instance properties for these broken browsers.
6437 var instanceProperties = /WebKit/.test(navigator.userAgent) ?
6438 {drawingBufferHeight: null, drawingBufferWidth: null} : {};
6439
6440 registerWrapper(OriginalWebGLRenderingContext, WebGLRenderingContext,
6441 instanceProperties);
6442
6443 scope.wrappers.WebGLRenderingContext = WebGLRenderingContext;
6444 })(window.ShadowDOMPolyfill);
6445
6446 // Copyright 2013 The Polymer Authors. All rights reserved.
6447 // Use of this source code is goverened by a BSD-style
6448 // license that can be found in the LICENSE file.
6449
6450 (function(scope) {
6451 'use strict';
6452
6453 var registerWrapper = scope.registerWrapper;
6454 var setWrapper = scope.setWrapper;
6455 var unsafeUnwrap = scope.unsafeUnwrap;
6456 var unwrap = scope.unwrap;
6457 var unwrapIfNeeded = scope.unwrapIfNeeded;
6458 var wrap = scope.wrap;
6459
6460 var OriginalRange = window.Range;
6461
6462 function Range(impl) {
6463 setWrapper(impl, this);
6464 }
6465 Range.prototype = {
6466 get startContainer() {
6467 return wrap(unsafeUnwrap(this).startContainer);
6468 },
6469 get endContainer() {
6470 return wrap(unsafeUnwrap(this).endContainer);
6471 },
6472 get commonAncestorContainer() {
6473 return wrap(unsafeUnwrap(this).commonAncestorContainer);
6474 },
6475 setStart: function(refNode,offset) {
6476 unsafeUnwrap(this).setStart(unwrapIfNeeded(refNode), offset);
6477 },
6478 setEnd: function(refNode,offset) {
6479 unsafeUnwrap(this).setEnd(unwrapIfNeeded(refNode), offset);
6480 },
6481 setStartBefore: function(refNode) {
6482 unsafeUnwrap(this).setStartBefore(unwrapIfNeeded(refNode));
6483 },
6484 setStartAfter: function(refNode) {
6485 unsafeUnwrap(this).setStartAfter(unwrapIfNeeded(refNode));
6486 },
6487 setEndBefore: function(refNode) {
6488 unsafeUnwrap(this).setEndBefore(unwrapIfNeeded(refNode));
6489 },
6490 setEndAfter: function(refNode) {
6491 unsafeUnwrap(this).setEndAfter(unwrapIfNeeded(refNode));
6492 },
6493 selectNode: function(refNode) {
6494 unsafeUnwrap(this).selectNode(unwrapIfNeeded(refNode));
6495 },
6496 selectNodeContents: function(refNode) {
6497 unsafeUnwrap(this).selectNodeContents(unwrapIfNeeded(refNode));
6498 },
6499 compareBoundaryPoints: function(how, sourceRange) {
6500 return unsafeUnwrap(this).compareBoundaryPoints(how, unwrap(sourceRange));
6501 },
6502 extractContents: function() {
6503 return wrap(unsafeUnwrap(this).extractContents());
6504 },
6505 cloneContents: function() {
6506 return wrap(unsafeUnwrap(this).cloneContents());
6507 },
6508 insertNode: function(node) {
6509 unsafeUnwrap(this).insertNode(unwrapIfNeeded(node));
6510 },
6511 surroundContents: function(newParent) {
6512 unsafeUnwrap(this).surroundContents(unwrapIfNeeded(newParent));
6513 },
6514 cloneRange: function() {
6515 return wrap(unsafeUnwrap(this).cloneRange());
6516 },
6517 isPointInRange: function(node, offset) {
6518 return unsafeUnwrap(this).isPointInRange(unwrapIfNeeded(node), offset);
6519 },
6520 comparePoint: function(node, offset) {
6521 return unsafeUnwrap(this).comparePoint(unwrapIfNeeded(node), offset);
6522 },
6523 intersectsNode: function(node) {
6524 return unsafeUnwrap(this).intersectsNode(unwrapIfNeeded(node));
6525 },
6526 toString: function() {
6527 return unsafeUnwrap(this).toString();
6528 }
6529 };
6530
6531 // IE9 does not have createContextualFragment.
6532 if (OriginalRange.prototype.createContextualFragment) {
6533 Range.prototype.createContextualFragment = function(html) {
6534 return wrap(unsafeUnwrap(this).createContextualFragment(html));
6535 };
6536 }
6537
6538 registerWrapper(window.Range, Range, document.createRange());
6539
6540 scope.wrappers.Range = Range;
6541
6542 })(window.ShadowDOMPolyfill);
6543
6544 // Copyright 2013 The Polymer Authors. All rights reserved.
6545 // Use of this source code is goverened by a BSD-style
6546 // license that can be found in the LICENSE file.
6547
6548 (function(scope) {
6549 'use strict';
6550
6551 var GetElementsByInterface = scope.GetElementsByInterface;
6552 var ParentNodeInterface = scope.ParentNodeInterface;
6553 var SelectorsInterface = scope.SelectorsInterface;
6554 var mixin = scope.mixin;
6555 var registerObject = scope.registerObject;
6556
6557 var DocumentFragment = registerObject(document.createDocumentFragment());
6558 mixin(DocumentFragment.prototype, ParentNodeInterface);
6559 mixin(DocumentFragment.prototype, SelectorsInterface);
6560 mixin(DocumentFragment.prototype, GetElementsByInterface);
6561
6562 var Comment = registerObject(document.createComment(''));
6563
6564 scope.wrappers.Comment = Comment;
6565 scope.wrappers.DocumentFragment = DocumentFragment;
6566
6567 })(window.ShadowDOMPolyfill);
6568
6569 // Copyright 2013 The Polymer Authors. All rights reserved.
6570 // Use of this source code is goverened by a BSD-style
6571 // license that can be found in the LICENSE file.
6572
6573 (function(scope) {
6574 'use strict';
6575
6576 var DocumentFragment = scope.wrappers.DocumentFragment;
6577 var TreeScope = scope.TreeScope;
6578 var elementFromPoint = scope.elementFromPoint;
6579 var getInnerHTML = scope.getInnerHTML;
6580 var getTreeScope = scope.getTreeScope;
6581 var mixin = scope.mixin;
6582 var rewrap = scope.rewrap;
6583 var setInnerHTML = scope.setInnerHTML;
6584 var unsafeUnwrap = scope.unsafeUnwrap;
6585 var unwrap = scope.unwrap;
6586
6587 var shadowHostTable = new WeakMap();
6588 var nextOlderShadowTreeTable = new WeakMap();
6589
6590 var spaceCharRe = /[ \t\n\r\f]/;
6591
6592 function ShadowRoot(hostWrapper) {
6593 var node = unwrap(unsafeUnwrap(hostWrapper).ownerDocument.createDocumentFrag ment());
6594 DocumentFragment.call(this, node);
6595
6596 // createDocumentFragment associates the node with a wrapper
6597 // DocumentFragment instance. Override that.
6598 rewrap(node, this);
6599
6600 var oldShadowRoot = hostWrapper.shadowRoot;
6601 nextOlderShadowTreeTable.set(this, oldShadowRoot);
6602
6603 this.treeScope_ =
6604 new TreeScope(this, getTreeScope(oldShadowRoot || hostWrapper));
6605
6606 shadowHostTable.set(this, hostWrapper);
6607 }
6608 ShadowRoot.prototype = Object.create(DocumentFragment.prototype);
6609 mixin(ShadowRoot.prototype, {
6610 constructor: ShadowRoot,
6611
6612 get innerHTML() {
6613 return getInnerHTML(this);
6614 },
6615 set innerHTML(value) {
6616 setInnerHTML(this, value);
6617 this.invalidateShadowRenderer();
6618 },
6619
6620 get olderShadowRoot() {
6621 return nextOlderShadowTreeTable.get(this) || null;
6622 },
6623
6624 get host() {
6625 return shadowHostTable.get(this) || null;
6626 },
6627
6628 invalidateShadowRenderer: function() {
6629 return shadowHostTable.get(this).invalidateShadowRenderer();
6630 },
6631
6632 elementFromPoint: function(x, y) {
6633 return elementFromPoint(this, this.ownerDocument, x, y);
6634 },
6635
6636 getElementById: function(id) {
6637 if (spaceCharRe.test(id))
6638 return null;
6639 return this.querySelector('[id="' + id + '"]');
6640 }
6641 });
6642
6643 scope.wrappers.ShadowRoot = ShadowRoot;
6644
6645 })(window.ShadowDOMPolyfill);
6646
6647 // Copyright 2013 The Polymer Authors. All rights reserved.
6648 // Use of this source code is governed by a BSD-style
6649 // license that can be found in the LICENSE file.
6650
6651 (function(scope) {
6652 'use strict';
6653
6654 var Element = scope.wrappers.Element;
6655 var HTMLContentElement = scope.wrappers.HTMLContentElement;
6656 var HTMLShadowElement = scope.wrappers.HTMLShadowElement;
6657 var Node = scope.wrappers.Node;
6658 var ShadowRoot = scope.wrappers.ShadowRoot;
6659 var assert = scope.assert;
6660 var getTreeScope = scope.getTreeScope;
6661 var mixin = scope.mixin;
6662 var oneOf = scope.oneOf;
6663 var unsafeUnwrap = scope.unsafeUnwrap;
6664 var unwrap = scope.unwrap;
6665 var wrap = scope.wrap;
6666
6667 /**
6668 * Updates the fields of a wrapper to a snapshot of the logical DOM as needed.
6669 * Up means parentNode
6670 * Sideways means previous and next sibling.
6671 * @param {!Node} wrapper
6672 */
6673 function updateWrapperUpAndSideways(wrapper) {
6674 wrapper.previousSibling_ = wrapper.previousSibling;
6675 wrapper.nextSibling_ = wrapper.nextSibling;
6676 wrapper.parentNode_ = wrapper.parentNode;
6677 }
6678
6679 /**
6680 * Updates the fields of a wrapper to a snapshot of the logical DOM as needed.
6681 * Down means first and last child
6682 * @param {!Node} wrapper
6683 */
6684 function updateWrapperDown(wrapper) {
6685 wrapper.firstChild_ = wrapper.firstChild;
6686 wrapper.lastChild_ = wrapper.lastChild;
6687 }
6688
6689 function updateAllChildNodes(parentNodeWrapper) {
6690 assert(parentNodeWrapper instanceof Node);
6691 for (var childWrapper = parentNodeWrapper.firstChild;
6692 childWrapper;
6693 childWrapper = childWrapper.nextSibling) {
6694 updateWrapperUpAndSideways(childWrapper);
6695 }
6696 updateWrapperDown(parentNodeWrapper);
6697 }
6698
6699 function insertBefore(parentNodeWrapper, newChildWrapper, refChildWrapper) {
6700 var parentNode = unwrap(parentNodeWrapper);
6701 var newChild = unwrap(newChildWrapper);
6702 var refChild = refChildWrapper ? unwrap(refChildWrapper) : null;
6703
6704 remove(newChildWrapper);
6705 updateWrapperUpAndSideways(newChildWrapper);
6706
6707 if (!refChildWrapper) {
6708 parentNodeWrapper.lastChild_ = parentNodeWrapper.lastChild;
6709 if (parentNodeWrapper.lastChild === parentNodeWrapper.firstChild)
6710 parentNodeWrapper.firstChild_ = parentNodeWrapper.firstChild;
6711
6712 var lastChildWrapper = wrap(parentNode.lastChild);
6713 if (lastChildWrapper)
6714 lastChildWrapper.nextSibling_ = lastChildWrapper.nextSibling;
6715 } else {
6716 if (parentNodeWrapper.firstChild === refChildWrapper)
6717 parentNodeWrapper.firstChild_ = refChildWrapper;
6718
6719 refChildWrapper.previousSibling_ = refChildWrapper.previousSibling;
6720 }
6721
6722 scope.originalInsertBefore.call(parentNode, newChild, refChild);
6723 }
6724
6725 function remove(nodeWrapper) {
6726 var node = unwrap(nodeWrapper)
6727 var parentNode = node.parentNode;
6728 if (!parentNode)
6729 return;
6730
6731 var parentNodeWrapper = wrap(parentNode);
6732 updateWrapperUpAndSideways(nodeWrapper);
6733
6734 if (nodeWrapper.previousSibling)
6735 nodeWrapper.previousSibling.nextSibling_ = nodeWrapper;
6736 if (nodeWrapper.nextSibling)
6737 nodeWrapper.nextSibling.previousSibling_ = nodeWrapper;
6738
6739 if (parentNodeWrapper.lastChild === nodeWrapper)
6740 parentNodeWrapper.lastChild_ = nodeWrapper;
6741 if (parentNodeWrapper.firstChild === nodeWrapper)
6742 parentNodeWrapper.firstChild_ = nodeWrapper;
6743
6744 scope.originalRemoveChild.call(parentNode, node);
6745 }
6746
6747 var distributedNodesTable = new WeakMap();
6748 var destinationInsertionPointsTable = new WeakMap();
6749 var rendererForHostTable = new WeakMap();
6750
6751 function resetDistributedNodes(insertionPoint) {
6752 distributedNodesTable.set(insertionPoint, []);
6753 }
6754
6755 function getDistributedNodes(insertionPoint) {
6756 var rv = distributedNodesTable.get(insertionPoint);
6757 if (!rv)
6758 distributedNodesTable.set(insertionPoint, rv = []);
6759 return rv;
6760 }
6761
6762 function getChildNodesSnapshot(node) {
6763 var result = [], i = 0;
6764 for (var child = node.firstChild; child; child = child.nextSibling) {
6765 result[i++] = child;
6766 }
6767 return result;
6768 }
6769
6770 var request = oneOf(window, [
6771 'requestAnimationFrame',
6772 'mozRequestAnimationFrame',
6773 'webkitRequestAnimationFrame',
6774 'setTimeout'
6775 ]);
6776
6777 var pendingDirtyRenderers = [];
6778 var renderTimer;
6779
6780 function renderAllPending() {
6781 // TODO(arv): Order these in document order. That way we do not have to
6782 // render something twice.
6783 for (var i = 0; i < pendingDirtyRenderers.length; i++) {
6784 var renderer = pendingDirtyRenderers[i];
6785 var parentRenderer = renderer.parentRenderer;
6786 if (parentRenderer && parentRenderer.dirty)
6787 continue;
6788 renderer.render();
6789 }
6790
6791 pendingDirtyRenderers = [];
6792 }
6793
6794 function handleRequestAnimationFrame() {
6795 renderTimer = null;
6796 renderAllPending();
6797 }
6798
6799 /**
6800 * Returns existing shadow renderer for a host or creates it if it is needed.
6801 * @params {!Element} host
6802 * @return {!ShadowRenderer}
6803 */
6804 function getRendererForHost(host) {
6805 var renderer = rendererForHostTable.get(host);
6806 if (!renderer) {
6807 renderer = new ShadowRenderer(host);
6808 rendererForHostTable.set(host, renderer);
6809 }
6810 return renderer;
6811 }
6812
6813 function getShadowRootAncestor(node) {
6814 var root = getTreeScope(node).root;
6815 if (root instanceof ShadowRoot)
6816 return root;
6817 return null;
6818 }
6819
6820 function getRendererForShadowRoot(shadowRoot) {
6821 return getRendererForHost(shadowRoot.host);
6822 }
6823
6824 var spliceDiff = new ArraySplice();
6825 spliceDiff.equals = function(renderNode, rawNode) {
6826 return unwrap(renderNode.node) === rawNode;
6827 };
6828
6829 /**
6830 * RenderNode is used as an in memory "render tree". When we render the
6831 * composed tree we create a tree of RenderNodes, then we diff this against
6832 * the real DOM tree and make minimal changes as needed.
6833 */
6834 function RenderNode(node) {
6835 this.skip = false;
6836 this.node = node;
6837 this.childNodes = [];
6838 }
6839
6840 RenderNode.prototype = {
6841 append: function(node) {
6842 var rv = new RenderNode(node);
6843 this.childNodes.push(rv);
6844 return rv;
6845 },
6846
6847 sync: function(opt_added) {
6848 if (this.skip)
6849 return;
6850
6851 var nodeWrapper = this.node;
6852 // plain array of RenderNodes
6853 var newChildren = this.childNodes;
6854 // plain array of real nodes.
6855 var oldChildren = getChildNodesSnapshot(unwrap(nodeWrapper));
6856 var added = opt_added || new WeakMap();
6857
6858 var splices = spliceDiff.calculateSplices(newChildren, oldChildren);
6859
6860 var newIndex = 0, oldIndex = 0;
6861 var lastIndex = 0;
6862 for (var i = 0; i < splices.length; i++) {
6863 var splice = splices[i];
6864 for (; lastIndex < splice.index; lastIndex++) {
6865 oldIndex++;
6866 newChildren[newIndex++].sync(added);
6867 }
6868
6869 var removedCount = splice.removed.length;
6870 for (var j = 0; j < removedCount; j++) {
6871 var wrapper = wrap(oldChildren[oldIndex++]);
6872 if (!added.get(wrapper))
6873 remove(wrapper);
6874 }
6875
6876 var addedCount = splice.addedCount;
6877 var refNode = oldChildren[oldIndex] && wrap(oldChildren[oldIndex]);
6878 for (var j = 0; j < addedCount; j++) {
6879 var newChildRenderNode = newChildren[newIndex++];
6880 var newChildWrapper = newChildRenderNode.node;
6881 insertBefore(nodeWrapper, newChildWrapper, refNode);
6882
6883 // Keep track of added so that we do not remove the node after it
6884 // has been added.
6885 added.set(newChildWrapper, true);
6886
6887 newChildRenderNode.sync(added);
6888 }
6889
6890 lastIndex += addedCount;
6891 }
6892
6893 for (var i = lastIndex; i < newChildren.length; i++) {
6894 newChildren[i].sync(added);
6895 }
6896 }
6897 };
6898
6899 function ShadowRenderer(host) {
6900 this.host = host;
6901 this.dirty = false;
6902 this.invalidateAttributes();
6903 this.associateNode(host);
6904 }
6905
6906 ShadowRenderer.prototype = {
6907
6908 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#r endering-shadow-trees
6909 render: function(opt_renderNode) {
6910 if (!this.dirty)
6911 return;
6912
6913 this.invalidateAttributes();
6914
6915 var host = this.host;
6916
6917 this.distribution(host);
6918 var renderNode = opt_renderNode || new RenderNode(host);
6919 this.buildRenderTree(renderNode, host);
6920
6921 var topMostRenderer = !opt_renderNode;
6922 if (topMostRenderer)
6923 renderNode.sync();
6924
6925 this.dirty = false;
6926 },
6927
6928 get parentRenderer() {
6929 return getTreeScope(this.host).renderer;
6930 },
6931
6932 invalidate: function() {
6933 if (!this.dirty) {
6934 this.dirty = true;
6935 var parentRenderer = this.parentRenderer;
6936 if (parentRenderer)
6937 parentRenderer.invalidate();
6938 pendingDirtyRenderers.push(this);
6939 if (renderTimer)
6940 return;
6941 renderTimer = window[request](handleRequestAnimationFrame, 0);
6942 }
6943 },
6944
6945 // http://w3c.github.io/webcomponents/spec/shadow/#distribution-algorithms
6946 distribution: function(root) {
6947 this.resetAllSubtrees(root);
6948 this.distributionResolution(root);
6949 },
6950
6951 resetAll: function(node) {
6952 if (isInsertionPoint(node))
6953 resetDistributedNodes(node);
6954 else
6955 resetDestinationInsertionPoints(node);
6956
6957 this.resetAllSubtrees(node);
6958 },
6959
6960 resetAllSubtrees: function(node) {
6961 for (var child = node.firstChild; child; child = child.nextSibling) {
6962 this.resetAll(child);
6963 }
6964
6965 if (node.shadowRoot)
6966 this.resetAll(node.shadowRoot);
6967
6968 if (node.olderShadowRoot)
6969 this.resetAll(node.olderShadowRoot);
6970 },
6971
6972 // http://w3c.github.io/webcomponents/spec/shadow/#distribution-results
6973 distributionResolution: function(node) {
6974 if (isShadowHost(node)) {
6975 var shadowHost = node;
6976 // 1.1
6977 var pool = poolPopulation(shadowHost);
6978
6979 var shadowTrees = getShadowTrees(shadowHost);
6980
6981 // 1.2
6982 for (var i = 0; i < shadowTrees.length; i++) {
6983 // 1.2.1
6984 this.poolDistribution(shadowTrees[i], pool);
6985 }
6986
6987 // 1.3
6988 for (var i = shadowTrees.length - 1; i >= 0; i--) {
6989 var shadowTree = shadowTrees[i];
6990
6991 // 1.3.1
6992 // TODO(arv): We should keep the shadow insertion points on the
6993 // shadow root (or renderer) so we don't have to search the tree
6994 // every time.
6995 var shadow = getShadowInsertionPoint(shadowTree);
6996
6997 // 1.3.2
6998 if (shadow) {
6999
7000 // 1.3.2.1
7001 var olderShadowRoot = shadowTree.olderShadowRoot;
7002 if (olderShadowRoot) {
7003 // 1.3.2.1.1
7004 pool = poolPopulation(olderShadowRoot);
7005 }
7006
7007 // 1.3.2.2
7008 for (var j = 0; j < pool.length; j++) {
7009 // 1.3.2.2.1
7010 destributeNodeInto(pool[j], shadow);
7011 }
7012 }
7013
7014 // 1.3.3
7015 this.distributionResolution(shadowTree);
7016 }
7017 }
7018
7019 for (var child = node.firstChild; child; child = child.nextSibling) {
7020 this.distributionResolution(child);
7021 }
7022 },
7023
7024 // http://w3c.github.io/webcomponents/spec/shadow/#dfn-pool-distribution-alg orithm
7025 poolDistribution: function (node, pool) {
7026 if (node instanceof HTMLShadowElement)
7027 return;
7028
7029 if (node instanceof HTMLContentElement) {
7030 var content = node;
7031 this.updateDependentAttributes(content.getAttribute('select'));
7032
7033 var anyDistributed = false;
7034
7035 // 1.1
7036 for (var i = 0; i < pool.length; i++) {
7037 var node = pool[i];
7038 if (!node)
7039 continue;
7040 if (matches(node, content)) {
7041 destributeNodeInto(node, content);
7042 pool[i] = undefined;
7043 anyDistributed = true;
7044 }
7045 }
7046
7047 // 1.2
7048 // Fallback content
7049 if (!anyDistributed) {
7050 for (var child = content.firstChild;
7051 child;
7052 child = child.nextSibling) {
7053 destributeNodeInto(child, content);
7054 }
7055 }
7056
7057 return;
7058 }
7059
7060 for (var child = node.firstChild; child; child = child.nextSibling) {
7061 this.poolDistribution(child, pool);
7062 }
7063 },
7064
7065 buildRenderTree: function(renderNode, node) {
7066 var children = this.compose(node);
7067 for (var i = 0; i < children.length; i++) {
7068 var child = children[i];
7069 var childRenderNode = renderNode.append(child);
7070 this.buildRenderTree(childRenderNode, child);
7071 }
7072
7073 if (isShadowHost(node)) {
7074 var renderer = getRendererForHost(node);
7075 renderer.dirty = false;
7076 }
7077
7078 },
7079
7080 compose: function(node) {
7081 var children = [];
7082 var p = node.shadowRoot || node;
7083 for (var child = p.firstChild; child; child = child.nextSibling) {
7084 if (isInsertionPoint(child)) {
7085 this.associateNode(p);
7086 var distributedNodes = getDistributedNodes(child);
7087 for (var j = 0; j < distributedNodes.length; j++) {
7088 var distributedNode = distributedNodes[j];
7089 if (isFinalDestination(child, distributedNode))
7090 children.push(distributedNode);
7091 }
7092 } else {
7093 children.push(child);
7094 }
7095 }
7096 return children;
7097 },
7098
7099 /**
7100 * Invalidates the attributes used to keep track of which attributes may
7101 * cause the renderer to be invalidated.
7102 */
7103 invalidateAttributes: function() {
7104 this.attributes = Object.create(null);
7105 },
7106
7107 /**
7108 * Parses the selector and makes this renderer dependent on the attribute
7109 * being used in the selector.
7110 * @param {string} selector
7111 */
7112 updateDependentAttributes: function(selector) {
7113 if (!selector)
7114 return;
7115
7116 var attributes = this.attributes;
7117
7118 // .class
7119 if (/\.\w+/.test(selector))
7120 attributes['class'] = true;
7121
7122 // #id
7123 if (/#\w+/.test(selector))
7124 attributes['id'] = true;
7125
7126 selector.replace(/\[\s*([^\s=\|~\]]+)/g, function(_, name) {
7127 attributes[name] = true;
7128 });
7129
7130 // Pseudo selectors have been removed from the spec.
7131 },
7132
7133 dependsOnAttribute: function(name) {
7134 return this.attributes[name];
7135 },
7136
7137 associateNode: function(node) {
7138 unsafeUnwrap(node).polymerShadowRenderer_ = this;
7139 }
7140 };
7141
7142 // http://w3c.github.io/webcomponents/spec/shadow/#dfn-pool-population-algorit hm
7143 function poolPopulation(node) {
7144 var pool = [];
7145 for (var child = node.firstChild; child; child = child.nextSibling) {
7146 if (isInsertionPoint(child)) {
7147 pool.push.apply(pool, getDistributedNodes(child));
7148 } else {
7149 pool.push(child);
7150 }
7151 }
7152 return pool;
7153 }
7154
7155 function getShadowInsertionPoint(node) {
7156 if (node instanceof HTMLShadowElement)
7157 return node;
7158 if (node instanceof HTMLContentElement)
7159 return null;
7160 for (var child = node.firstChild; child; child = child.nextSibling) {
7161 var res = getShadowInsertionPoint(child);
7162 if (res)
7163 return res;
7164 }
7165 return null;
7166 }
7167
7168 function destributeNodeInto(child, insertionPoint) {
7169 getDistributedNodes(insertionPoint).push(child);
7170 var points = destinationInsertionPointsTable.get(child);
7171 if (!points)
7172 destinationInsertionPointsTable.set(child, [insertionPoint]);
7173 else
7174 points.push(insertionPoint);
7175 }
7176
7177 function getDestinationInsertionPoints(node) {
7178 return destinationInsertionPointsTable.get(node);
7179 }
7180
7181 function resetDestinationInsertionPoints(node) {
7182 // IE11 crashes when delete is used.
7183 destinationInsertionPointsTable.set(node, undefined);
7184 }
7185
7186 // AllowedSelectors :
7187 // TypeSelector
7188 // *
7189 // ClassSelector
7190 // IDSelector
7191 // AttributeSelector
7192 // negation
7193 var selectorStartCharRe = /^(:not\()?[*.#[a-zA-Z_|]/;
7194
7195 function matches(node, contentElement) {
7196 var select = contentElement.getAttribute('select');
7197 if (!select)
7198 return true;
7199
7200 // Here we know the select attribute is a non empty string.
7201 select = select.trim();
7202 if (!select)
7203 return true;
7204
7205 if (!(node instanceof Element))
7206 return false;
7207
7208 if (!selectorStartCharRe.test(select))
7209 return false;
7210
7211 try {
7212 return node.matches(select);
7213 } catch (ex) {
7214 // Invalid selector.
7215 return false;
7216 }
7217 }
7218
7219 function isFinalDestination(insertionPoint, node) {
7220 var points = getDestinationInsertionPoints(node);
7221 return points && points[points.length - 1] === insertionPoint;
7222 }
7223
7224 function isInsertionPoint(node) {
7225 return node instanceof HTMLContentElement ||
7226 node instanceof HTMLShadowElement;
7227 }
7228
7229 function isShadowHost(shadowHost) {
7230 return shadowHost.shadowRoot;
7231 }
7232
7233 // Returns the shadow trees as an array, with the youngest tree at the
7234 // beginning of the array.
7235 function getShadowTrees(host) {
7236 var trees = [];
7237
7238 for (var tree = host.shadowRoot; tree; tree = tree.olderShadowRoot) {
7239 trees.push(tree);
7240 }
7241 return trees;
7242 }
7243
7244 function render(host) {
7245 new ShadowRenderer(host).render();
7246 };
7247
7248 // Need to rerender shadow host when:
7249 //
7250 // - a direct child to the ShadowRoot is added or removed
7251 // - a direct child to the host is added or removed
7252 // - a new shadow root is created
7253 // - a direct child to a content/shadow element is added or removed
7254 // - a sibling to a content/shadow element is added or removed
7255 // - content[select] is changed
7256 // - an attribute in a direct child to a host is modified
7257
7258 /**
7259 * This gets called when a node was added or removed to it.
7260 */
7261 Node.prototype.invalidateShadowRenderer = function(force) {
7262 var renderer = unsafeUnwrap(this).polymerShadowRenderer_;
7263 if (renderer) {
7264 renderer.invalidate();
7265 return true;
7266 }
7267
7268 return false;
7269 };
7270
7271 HTMLContentElement.prototype.getDistributedNodes =
7272 HTMLShadowElement.prototype.getDistributedNodes = function() {
7273 // TODO(arv): We should only rerender the dirty ancestor renderers (from
7274 // the root and down).
7275 renderAllPending();
7276 return getDistributedNodes(this);
7277 };
7278
7279 Element.prototype.getDestinationInsertionPoints = function() {
7280 renderAllPending();
7281 return getDestinationInsertionPoints(this) || [];
7282 };
7283
7284 HTMLContentElement.prototype.nodeIsInserted_ =
7285 HTMLShadowElement.prototype.nodeIsInserted_ = function() {
7286 // Invalidate old renderer if any.
7287 this.invalidateShadowRenderer();
7288
7289 var shadowRoot = getShadowRootAncestor(this);
7290 var renderer;
7291 if (shadowRoot)
7292 renderer = getRendererForShadowRoot(shadowRoot);
7293 unsafeUnwrap(this).polymerShadowRenderer_ = renderer;
7294 if (renderer)
7295 renderer.invalidate();
7296 };
7297
7298 scope.getRendererForHost = getRendererForHost;
7299 scope.getShadowTrees = getShadowTrees;
7300 scope.renderAllPending = renderAllPending;
7301
7302 scope.getDestinationInsertionPoints = getDestinationInsertionPoints;
7303
7304 // Exposed for testing
7305 scope.visual = {
7306 insertBefore: insertBefore,
7307 remove: remove,
7308 };
7309
7310 })(window.ShadowDOMPolyfill);
7311
7312 // Copyright 2013 The Polymer Authors. All rights reserved.
7313 // Use of this source code is goverened by a BSD-style
7314 // license that can be found in the LICENSE file.
7315
7316 (function(scope) {
7317 'use strict';
7318
7319 var HTMLElement = scope.wrappers.HTMLElement;
7320 var assert = scope.assert;
7321 var mixin = scope.mixin;
7322 var registerWrapper = scope.registerWrapper;
7323 var unwrap = scope.unwrap;
7324 var wrap = scope.wrap;
7325
7326 var elementsWithFormProperty = [
7327 'HTMLButtonElement',
7328 'HTMLFieldSetElement',
7329 'HTMLInputElement',
7330 'HTMLKeygenElement',
7331 'HTMLLabelElement',
7332 'HTMLLegendElement',
7333 'HTMLObjectElement',
7334 // HTMLOptionElement is handled in HTMLOptionElement.js
7335 'HTMLOutputElement',
7336 // HTMLSelectElement is handled in HTMLSelectElement.js
7337 'HTMLTextAreaElement',
7338 ];
7339
7340 function createWrapperConstructor(name) {
7341 if (!window[name])
7342 return;
7343
7344 // Ensure we are not overriding an already existing constructor.
7345 assert(!scope.wrappers[name]);
7346
7347 var GeneratedWrapper = function(node) {
7348 // At this point all of them extend HTMLElement.
7349 HTMLElement.call(this, node);
7350 }
7351 GeneratedWrapper.prototype = Object.create(HTMLElement.prototype);
7352 mixin(GeneratedWrapper.prototype, {
7353 get form() {
7354 return wrap(unwrap(this).form);
7355 },
7356 });
7357
7358 registerWrapper(window[name], GeneratedWrapper,
7359 document.createElement(name.slice(4, -7)));
7360 scope.wrappers[name] = GeneratedWrapper;
7361 }
7362
7363 elementsWithFormProperty.forEach(createWrapperConstructor);
7364
7365 })(window.ShadowDOMPolyfill);
7366
7367 // Copyright 2014 The Polymer Authors. All rights reserved.
7368 // Use of this source code is goverened by a BSD-style
7369 // license that can be found in the LICENSE file.
7370
7371 (function(scope) {
7372 'use strict';
7373
7374 var registerWrapper = scope.registerWrapper;
7375 var setWrapper = scope.setWrapper;
7376 var unsafeUnwrap = scope.unsafeUnwrap;
7377 var unwrap = scope.unwrap;
7378 var unwrapIfNeeded = scope.unwrapIfNeeded;
7379 var wrap = scope.wrap;
7380
7381 var OriginalSelection = window.Selection;
7382
7383 function Selection(impl) {
7384 setWrapper(impl, this);
7385 }
7386 Selection.prototype = {
7387 get anchorNode() {
7388 return wrap(unsafeUnwrap(this).anchorNode);
7389 },
7390 get focusNode() {
7391 return wrap(unsafeUnwrap(this).focusNode);
7392 },
7393 addRange: function(range) {
7394 unsafeUnwrap(this).addRange(unwrap(range));
7395 },
7396 collapse: function(node, index) {
7397 unsafeUnwrap(this).collapse(unwrapIfNeeded(node), index);
7398 },
7399 containsNode: function(node, allowPartial) {
7400 return unsafeUnwrap(this).containsNode(unwrapIfNeeded(node), allowPartial) ;
7401 },
7402 extend: function(node, offset) {
7403 unsafeUnwrap(this).extend(unwrapIfNeeded(node), offset);
7404 },
7405 getRangeAt: function(index) {
7406 return wrap(unsafeUnwrap(this).getRangeAt(index));
7407 },
7408 removeRange: function(range) {
7409 unsafeUnwrap(this).removeRange(unwrap(range));
7410 },
7411 selectAllChildren: function(node) {
7412 unsafeUnwrap(this).selectAllChildren(unwrapIfNeeded(node));
7413 },
7414 toString: function() {
7415 return unsafeUnwrap(this).toString();
7416 }
7417 };
7418
7419 // WebKit extensions. Not implemented.
7420 // readonly attribute Node baseNode;
7421 // readonly attribute long baseOffset;
7422 // readonly attribute Node extentNode;
7423 // readonly attribute long extentOffset;
7424 // [RaisesException] void setBaseAndExtent([Default=Undefined] optional Node b aseNode,
7425 // [Default=Undefined] optional long baseOffset,
7426 // [Default=Undefined] optional Node extentNode,
7427 // [Default=Undefined] optional long extentOffset);
7428 // [RaisesException, ImplementedAs=collapse] void setPosition([Default=Undefin ed] optional Node node,
7429 // [Default=Undefined] optional long offset);
7430
7431 registerWrapper(window.Selection, Selection, window.getSelection());
7432
7433 scope.wrappers.Selection = Selection;
7434
7435 })(window.ShadowDOMPolyfill);
7436
7437 // Copyright 2013 The Polymer Authors. All rights reserved.
7438 // Use of this source code is goverened by a BSD-style
7439 // license that can be found in the LICENSE file.
7440
7441 (function(scope) {
7442 'use strict';
7443
7444 var GetElementsByInterface = scope.GetElementsByInterface;
7445 var Node = scope.wrappers.Node;
7446 var ParentNodeInterface = scope.ParentNodeInterface;
7447 var Selection = scope.wrappers.Selection;
7448 var SelectorsInterface = scope.SelectorsInterface;
7449 var ShadowRoot = scope.wrappers.ShadowRoot;
7450 var TreeScope = scope.TreeScope;
7451 var cloneNode = scope.cloneNode;
7452 var defineWrapGetter = scope.defineWrapGetter;
7453 var elementFromPoint = scope.elementFromPoint;
7454 var forwardMethodsToWrapper = scope.forwardMethodsToWrapper;
7455 var matchesNames = scope.matchesNames;
7456 var mixin = scope.mixin;
7457 var registerWrapper = scope.registerWrapper;
7458 var renderAllPending = scope.renderAllPending;
7459 var rewrap = scope.rewrap;
7460 var setWrapper = scope.setWrapper;
7461 var unsafeUnwrap = scope.unsafeUnwrap;
7462 var unwrap = scope.unwrap;
7463 var wrap = scope.wrap;
7464 var wrapEventTargetMethods = scope.wrapEventTargetMethods;
7465 var wrapNodeList = scope.wrapNodeList;
7466
7467 var implementationTable = new WeakMap();
7468
7469 function Document(node) {
7470 Node.call(this, node);
7471 this.treeScope_ = new TreeScope(this, null);
7472 }
7473 Document.prototype = Object.create(Node.prototype);
7474
7475 defineWrapGetter(Document, 'documentElement');
7476
7477 // Conceptually both body and head can be in a shadow but suporting that seems
7478 // overkill at this point.
7479 defineWrapGetter(Document, 'body');
7480 defineWrapGetter(Document, 'head');
7481
7482 // document cannot be overridden so we override a bunch of its methods
7483 // directly on the instance.
7484
7485 function wrapMethod(name) {
7486 var original = document[name];
7487 Document.prototype[name] = function() {
7488 return wrap(original.apply(unsafeUnwrap(this), arguments));
7489 };
7490 }
7491
7492 [
7493 'createComment',
7494 'createDocumentFragment',
7495 'createElement',
7496 'createElementNS',
7497 'createEvent',
7498 'createEventNS',
7499 'createRange',
7500 'createTextNode',
7501 'getElementById'
7502 ].forEach(wrapMethod);
7503
7504 var originalAdoptNode = document.adoptNode;
7505
7506 function adoptNodeNoRemove(node, doc) {
7507 originalAdoptNode.call(unsafeUnwrap(doc), unwrap(node));
7508 adoptSubtree(node, doc);
7509 }
7510
7511 function adoptSubtree(node, doc) {
7512 if (node.shadowRoot)
7513 doc.adoptNode(node.shadowRoot);
7514 if (node instanceof ShadowRoot)
7515 adoptOlderShadowRoots(node, doc);
7516 for (var child = node.firstChild; child; child = child.nextSibling) {
7517 adoptSubtree(child, doc);
7518 }
7519 }
7520
7521 function adoptOlderShadowRoots(shadowRoot, doc) {
7522 var oldShadowRoot = shadowRoot.olderShadowRoot;
7523 if (oldShadowRoot)
7524 doc.adoptNode(oldShadowRoot);
7525 }
7526
7527 var originalGetSelection = document.getSelection;
7528
7529 mixin(Document.prototype, {
7530 adoptNode: function(node) {
7531 if (node.parentNode)
7532 node.parentNode.removeChild(node);
7533 adoptNodeNoRemove(node, this);
7534 return node;
7535 },
7536 elementFromPoint: function(x, y) {
7537 return elementFromPoint(this, this, x, y);
7538 },
7539 importNode: function(node, deep) {
7540 return cloneNode(node, deep, unsafeUnwrap(this));
7541 },
7542 getSelection: function() {
7543 renderAllPending();
7544 return new Selection(originalGetSelection.call(unwrap(this)));
7545 },
7546 getElementsByName: function(name) {
7547 return SelectorsInterface.querySelectorAll.call(this,
7548 '[name=' + JSON.stringify(String(name)) + ']');
7549 }
7550 });
7551
7552 if (document.registerElement) {
7553 var originalRegisterElement = document.registerElement;
7554 Document.prototype.registerElement = function(tagName, object) {
7555 var prototype, extendsOption;
7556 if (object !== undefined) {
7557 prototype = object.prototype;
7558 extendsOption = object.extends;
7559 }
7560
7561 if (!prototype)
7562 prototype = Object.create(HTMLElement.prototype);
7563
7564
7565 // If we already used the object as a prototype for another custom
7566 // element.
7567 if (scope.nativePrototypeTable.get(prototype)) {
7568 // TODO(arv): DOMException
7569 throw new Error('NotSupportedError');
7570 }
7571
7572 // Find first object on the prototype chain that already have a native
7573 // prototype. Keep track of all the objects before that so we can create
7574 // a similar structure for the native case.
7575 var proto = Object.getPrototypeOf(prototype);
7576 var nativePrototype;
7577 var prototypes = [];
7578 while (proto) {
7579 nativePrototype = scope.nativePrototypeTable.get(proto);
7580 if (nativePrototype)
7581 break;
7582 prototypes.push(proto);
7583 proto = Object.getPrototypeOf(proto);
7584 }
7585
7586 if (!nativePrototype) {
7587 // TODO(arv): DOMException
7588 throw new Error('NotSupportedError');
7589 }
7590
7591 // This works by creating a new prototype object that is empty, but has
7592 // the native prototype as its proto. The original prototype object
7593 // passed into register is used as the wrapper prototype.
7594
7595 var newPrototype = Object.create(nativePrototype);
7596 for (var i = prototypes.length - 1; i >= 0; i--) {
7597 newPrototype = Object.create(newPrototype);
7598 }
7599
7600 // Add callbacks if present.
7601 // Names are taken from:
7602 // 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
7603 // and not from the spec since the spec is out of date.
7604 [
7605 'createdCallback',
7606 'attachedCallback',
7607 'detachedCallback',
7608 'attributeChangedCallback',
7609 ].forEach(function(name) {
7610 var f = prototype[name];
7611 if (!f)
7612 return;
7613 newPrototype[name] = function() {
7614 // if this element has been wrapped prior to registration,
7615 // the wrapper is stale; in this case rewrap
7616 if (!(wrap(this) instanceof CustomElementConstructor)) {
7617 rewrap(this);
7618 }
7619 f.apply(wrap(this), arguments);
7620 };
7621 });
7622
7623 var p = {prototype: newPrototype};
7624 if (extendsOption)
7625 p.extends = extendsOption;
7626
7627 function CustomElementConstructor(node) {
7628 if (!node) {
7629 if (extendsOption) {
7630 return document.createElement(extendsOption, tagName);
7631 } else {
7632 return document.createElement(tagName);
7633 }
7634 }
7635 setWrapper(node, this);
7636 }
7637 CustomElementConstructor.prototype = prototype;
7638 CustomElementConstructor.prototype.constructor = CustomElementConstructor;
7639
7640 scope.constructorTable.set(newPrototype, CustomElementConstructor);
7641 scope.nativePrototypeTable.set(prototype, newPrototype);
7642
7643 // registration is synchronous so do it last
7644 var nativeConstructor = originalRegisterElement.call(unwrap(this),
7645 tagName, p);
7646 return CustomElementConstructor;
7647 };
7648
7649 forwardMethodsToWrapper([
7650 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocume nt
7651 ], [
7652 'registerElement',
7653 ]);
7654 }
7655
7656 // We also override some of the methods on document.body and document.head
7657 // for convenience.
7658 forwardMethodsToWrapper([
7659 window.HTMLBodyElement,
7660 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument
7661 window.HTMLHeadElement,
7662 window.HTMLHtmlElement,
7663 ], [
7664 'appendChild',
7665 'compareDocumentPosition',
7666 'contains',
7667 'getElementsByClassName',
7668 'getElementsByTagName',
7669 'getElementsByTagNameNS',
7670 'insertBefore',
7671 'querySelector',
7672 'querySelectorAll',
7673 'removeChild',
7674 'replaceChild',
7675 ].concat(matchesNames));
7676
7677 forwardMethodsToWrapper([
7678 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument
7679 ], [
7680 'adoptNode',
7681 'importNode',
7682 'contains',
7683 'createComment',
7684 'createDocumentFragment',
7685 'createElement',
7686 'createElementNS',
7687 'createEvent',
7688 'createEventNS',
7689 'createRange',
7690 'createTextNode',
7691 'elementFromPoint',
7692 'getElementById',
7693 'getElementsByName',
7694 'getSelection',
7695 ]);
7696
7697 mixin(Document.prototype, GetElementsByInterface);
7698 mixin(Document.prototype, ParentNodeInterface);
7699 mixin(Document.prototype, SelectorsInterface);
7700
7701 mixin(Document.prototype, {
7702 get implementation() {
7703 var implementation = implementationTable.get(this);
7704 if (implementation)
7705 return implementation;
7706 implementation =
7707 new DOMImplementation(unwrap(this).implementation);
7708 implementationTable.set(this, implementation);
7709 return implementation;
7710 },
7711
7712 get defaultView() {
7713 return wrap(unwrap(this).defaultView);
7714 }
7715 });
7716
7717 registerWrapper(window.Document, Document,
7718 document.implementation.createHTMLDocument(''));
7719
7720 // Both WebKit and Gecko uses HTMLDocument for document. HTML5/DOM only has
7721 // one Document interface and IE implements the standard correctly.
7722 if (window.HTMLDocument)
7723 registerWrapper(window.HTMLDocument, Document);
7724
7725 wrapEventTargetMethods([
7726 window.HTMLBodyElement,
7727 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument
7728 window.HTMLHeadElement,
7729 ]);
7730
7731 function DOMImplementation(impl) {
7732 setWrapper(impl, this);
7733 }
7734
7735 function wrapImplMethod(constructor, name) {
7736 var original = document.implementation[name];
7737 constructor.prototype[name] = function() {
7738 return wrap(original.apply(unsafeUnwrap(this), arguments));
7739 };
7740 }
7741
7742 function forwardImplMethod(constructor, name) {
7743 var original = document.implementation[name];
7744 constructor.prototype[name] = function() {
7745 return original.apply(unsafeUnwrap(this), arguments);
7746 };
7747 }
7748
7749 wrapImplMethod(DOMImplementation, 'createDocumentType');
7750 wrapImplMethod(DOMImplementation, 'createDocument');
7751 wrapImplMethod(DOMImplementation, 'createHTMLDocument');
7752 forwardImplMethod(DOMImplementation, 'hasFeature');
7753
7754 registerWrapper(window.DOMImplementation, DOMImplementation);
7755
7756 forwardMethodsToWrapper([
7757 window.DOMImplementation,
7758 ], [
7759 'createDocumentType',
7760 'createDocument',
7761 'createHTMLDocument',
7762 'hasFeature',
7763 ]);
7764
7765 scope.adoptNodeNoRemove = adoptNodeNoRemove;
7766 scope.wrappers.DOMImplementation = DOMImplementation;
7767 scope.wrappers.Document = Document;
7768
7769 })(window.ShadowDOMPolyfill);
7770
7771 // Copyright 2013 The Polymer Authors. All rights reserved.
7772 // Use of this source code is goverened by a BSD-style
7773 // license that can be found in the LICENSE file.
7774
7775 (function(scope) {
7776 'use strict';
7777
7778 var EventTarget = scope.wrappers.EventTarget;
7779 var Selection = scope.wrappers.Selection;
7780 var mixin = scope.mixin;
7781 var registerWrapper = scope.registerWrapper;
7782 var renderAllPending = scope.renderAllPending;
7783 var unwrap = scope.unwrap;
7784 var unwrapIfNeeded = scope.unwrapIfNeeded;
7785 var wrap = scope.wrap;
7786
7787 var OriginalWindow = window.Window;
7788 var originalGetComputedStyle = window.getComputedStyle;
7789 var originalGetDefaultComputedStyle = window.getDefaultComputedStyle;
7790 var originalGetSelection = window.getSelection;
7791
7792 function Window(impl) {
7793 EventTarget.call(this, impl);
7794 }
7795 Window.prototype = Object.create(EventTarget.prototype);
7796
7797 OriginalWindow.prototype.getComputedStyle = function(el, pseudo) {
7798 return wrap(this || window).getComputedStyle(unwrapIfNeeded(el), pseudo);
7799 };
7800
7801 // Mozilla proprietary extension.
7802 if (originalGetDefaultComputedStyle) {
7803 OriginalWindow.prototype.getDefaultComputedStyle = function(el, pseudo) {
7804 return wrap(this || window).getDefaultComputedStyle(
7805 unwrapIfNeeded(el), pseudo);
7806 };
7807 }
7808
7809 OriginalWindow.prototype.getSelection = function() {
7810 return wrap(this || window).getSelection();
7811 };
7812
7813 // Work around for https://bugzilla.mozilla.org/show_bug.cgi?id=943065
7814 delete window.getComputedStyle;
7815 delete window.getDefaultComputedStyle;
7816 delete window.getSelection;
7817
7818 ['addEventListener', 'removeEventListener', 'dispatchEvent'].forEach(
7819 function(name) {
7820 OriginalWindow.prototype[name] = function() {
7821 var w = wrap(this || window);
7822 return w[name].apply(w, arguments);
7823 };
7824
7825 // Work around for https://bugzilla.mozilla.org/show_bug.cgi?id=943065
7826 delete window[name];
7827 });
7828
7829 mixin(Window.prototype, {
7830 getComputedStyle: function(el, pseudo) {
7831 renderAllPending();
7832 return originalGetComputedStyle.call(unwrap(this), unwrapIfNeeded(el),
7833 pseudo);
7834 },
7835 getSelection: function() {
7836 renderAllPending();
7837 return new Selection(originalGetSelection.call(unwrap(this)));
7838 },
7839
7840 get document() {
7841 return wrap(unwrap(this).document);
7842 }
7843 });
7844
7845 // Mozilla proprietary extension.
7846 if (originalGetDefaultComputedStyle) {
7847 Window.prototype.getDefaultComputedStyle = function(el, pseudo) {
7848 renderAllPending();
7849 return originalGetDefaultComputedStyle.call(unwrap(this),
7850 unwrapIfNeeded(el),pseudo);
7851 };
7852 }
7853
7854 registerWrapper(OriginalWindow, Window, window);
7855
7856 scope.wrappers.Window = Window;
7857
7858 })(window.ShadowDOMPolyfill);
7859
7860 /**
7861 * Copyright 2014 The Polymer Authors. All rights reserved.
7862 * Use of this source code is goverened by a BSD-style
7863 * license that can be found in the LICENSE file.
7864 */
7865
7866 (function(scope) {
7867 'use strict';
7868
7869 var unwrap = scope.unwrap;
7870
7871 // DataTransfer (Clipboard in old Blink/WebKit) has a single method that
7872 // requires wrapping. Since it is only a method we do not need a real wrapper,
7873 // we can just override the method.
7874
7875 var OriginalDataTransfer = window.DataTransfer || window.Clipboard;
7876 var OriginalDataTransferSetDragImage =
7877 OriginalDataTransfer.prototype.setDragImage;
7878
7879 if (OriginalDataTransferSetDragImage) {
7880 OriginalDataTransfer.prototype.setDragImage = function(image, x, y) {
7881 OriginalDataTransferSetDragImage.call(this, unwrap(image), x, y);
7882 };
7883 }
7884
7885 })(window.ShadowDOMPolyfill);
7886
7887 /**
7888 * Copyright 2014 The Polymer Authors. All rights reserved.
7889 * Use of this source code is goverened by a BSD-style
7890 * license that can be found in the LICENSE file.
7891 */
7892
7893 (function(scope) {
7894 'use strict';
7895
7896 var registerWrapper = scope.registerWrapper;
7897 var setWrapper = scope.setWrapper;
7898 var unwrap = scope.unwrap;
7899
7900 var OriginalFormData = window.FormData;
7901 if (!OriginalFormData) return;
7902
7903 function FormData(formElement) {
7904 var impl;
7905 if (formElement instanceof OriginalFormData) {
7906 impl = formElement;
7907 } else {
7908 impl = new OriginalFormData(formElement && unwrap(formElement));
7909 }
7910 setWrapper(impl, this);
7911 }
7912
7913 registerWrapper(OriginalFormData, FormData, new OriginalFormData());
7914
7915 scope.wrappers.FormData = FormData;
7916
7917 })(window.ShadowDOMPolyfill);
7918
7919 /*
7920 * Copyright 2014 The Polymer Authors. All rights reserved.
7921 * Use of this source code is goverened by a BSD-style
7922 * license that can be found in the LICENSE file.
7923 */
7924
7925 (function(scope) {
7926 'use strict';
7927
7928 var unwrapIfNeeded = scope.unwrapIfNeeded;
7929 var originalSend = XMLHttpRequest.prototype.send;
7930
7931 // Since we only need to adjust XHR.send, we just patch it instead of wrapping
7932 // the entire object. This happens when FormData is passed.
7933 XMLHttpRequest.prototype.send = function(obj) {
7934 return originalSend.call(this, unwrapIfNeeded(obj));
7935 };
7936
7937 })(window.ShadowDOMPolyfill);
7938
7939 // Copyright 2013 The Polymer Authors. All rights reserved.
7940 // Use of this source code is goverened by a BSD-style
7941 // license that can be found in the LICENSE file.
7942
7943 (function(scope) {
7944 'use strict';
7945
7946 var isWrapperFor = scope.isWrapperFor;
7947
7948 // This is a list of the elements we currently override the global constructor
7949 // for.
7950 var elements = {
7951 'a': 'HTMLAnchorElement',
7952 // Do not create an applet element by default since it shows a warning in
7953 // IE.
7954 // https://github.com/Polymer/polymer/issues/217
7955 // 'applet': 'HTMLAppletElement',
7956 'area': 'HTMLAreaElement',
7957 'audio': 'HTMLAudioElement',
7958 'base': 'HTMLBaseElement',
7959 'body': 'HTMLBodyElement',
7960 'br': 'HTMLBRElement',
7961 'button': 'HTMLButtonElement',
7962 'canvas': 'HTMLCanvasElement',
7963 'caption': 'HTMLTableCaptionElement',
7964 'col': 'HTMLTableColElement',
7965 // 'command': 'HTMLCommandElement', // Not fully implemented in Gecko.
7966 'content': 'HTMLContentElement',
7967 'data': 'HTMLDataElement',
7968 'datalist': 'HTMLDataListElement',
7969 'del': 'HTMLModElement',
7970 'dir': 'HTMLDirectoryElement',
7971 'div': 'HTMLDivElement',
7972 'dl': 'HTMLDListElement',
7973 'embed': 'HTMLEmbedElement',
7974 'fieldset': 'HTMLFieldSetElement',
7975 'font': 'HTMLFontElement',
7976 'form': 'HTMLFormElement',
7977 'frame': 'HTMLFrameElement',
7978 'frameset': 'HTMLFrameSetElement',
7979 'h1': 'HTMLHeadingElement',
7980 'head': 'HTMLHeadElement',
7981 'hr': 'HTMLHRElement',
7982 'html': 'HTMLHtmlElement',
7983 'iframe': 'HTMLIFrameElement',
7984 'img': 'HTMLImageElement',
7985 'input': 'HTMLInputElement',
7986 'keygen': 'HTMLKeygenElement',
7987 'label': 'HTMLLabelElement',
7988 'legend': 'HTMLLegendElement',
7989 'li': 'HTMLLIElement',
7990 'link': 'HTMLLinkElement',
7991 'map': 'HTMLMapElement',
7992 'marquee': 'HTMLMarqueeElement',
7993 'menu': 'HTMLMenuElement',
7994 'menuitem': 'HTMLMenuItemElement',
7995 'meta': 'HTMLMetaElement',
7996 'meter': 'HTMLMeterElement',
7997 'object': 'HTMLObjectElement',
7998 'ol': 'HTMLOListElement',
7999 'optgroup': 'HTMLOptGroupElement',
8000 'option': 'HTMLOptionElement',
8001 'output': 'HTMLOutputElement',
8002 'p': 'HTMLParagraphElement',
8003 'param': 'HTMLParamElement',
8004 'pre': 'HTMLPreElement',
8005 'progress': 'HTMLProgressElement',
8006 'q': 'HTMLQuoteElement',
8007 'script': 'HTMLScriptElement',
8008 'select': 'HTMLSelectElement',
8009 'shadow': 'HTMLShadowElement',
8010 'source': 'HTMLSourceElement',
8011 'span': 'HTMLSpanElement',
8012 'style': 'HTMLStyleElement',
8013 'table': 'HTMLTableElement',
8014 'tbody': 'HTMLTableSectionElement',
8015 // WebKit and Moz are wrong:
8016 // https://bugs.webkit.org/show_bug.cgi?id=111469
8017 // https://bugzilla.mozilla.org/show_bug.cgi?id=848096
8018 // 'td': 'HTMLTableCellElement',
8019 'template': 'HTMLTemplateElement',
8020 'textarea': 'HTMLTextAreaElement',
8021 'thead': 'HTMLTableSectionElement',
8022 'time': 'HTMLTimeElement',
8023 'title': 'HTMLTitleElement',
8024 'tr': 'HTMLTableRowElement',
8025 'track': 'HTMLTrackElement',
8026 'ul': 'HTMLUListElement',
8027 'video': 'HTMLVideoElement',
8028 };
8029
8030 function overrideConstructor(tagName) {
8031 var nativeConstructorName = elements[tagName];
8032 var nativeConstructor = window[nativeConstructorName];
8033 if (!nativeConstructor)
8034 return;
8035 var element = document.createElement(tagName);
8036 var wrapperConstructor = element.constructor;
8037 window[nativeConstructorName] = wrapperConstructor;
8038 }
8039
8040 Object.keys(elements).forEach(overrideConstructor);
8041
8042 Object.getOwnPropertyNames(scope.wrappers).forEach(function(name) {
8043 window[name] = scope.wrappers[name]
8044 });
8045
8046 })(window.ShadowDOMPolyfill);
8047
8048 /*
8049 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
8050 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
8051 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
8052 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
8053 * Code distributed by Google as part of the polymer project is also
8054 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
8055 */
8056
8057 (function(scope) {
8058
8059 // convenient global
8060 window.wrap = ShadowDOMPolyfill.wrapIfNeeded;
8061 window.unwrap = ShadowDOMPolyfill.unwrapIfNeeded;
8062
8063 // users may want to customize other types
8064 // TODO(sjmiles): 'button' is now supported by ShadowDOMPolyfill, but
8065 // I've left this code here in case we need to temporarily patch another
8066 // type
8067 /*
8068 (function() {
8069 var elts = {HTMLButtonElement: 'button'};
8070 for (var c in elts) {
8071 window[c] = function() { throw 'Patched Constructor'; };
8072 window[c].prototype = Object.getPrototypeOf(
8073 document.createElement(elts[c]));
8074 }
8075 })();
8076 */
8077
8078 // patch in prefixed name
8079 Object.defineProperty(Element.prototype, 'webkitShadowRoot',
8080 Object.getOwnPropertyDescriptor(Element.prototype, 'shadowRoot'));
8081
8082 var originalCreateShadowRoot = Element.prototype.createShadowRoot;
8083 Element.prototype.createShadowRoot = function() {
8084 var root = originalCreateShadowRoot.call(this);
8085 CustomElements.watchShadow(this);
8086 return root;
8087 };
8088
8089 Element.prototype.webkitCreateShadowRoot = Element.prototype.createShadowRoot;
8090
8091 function queryShadow(node, selector) {
8092 var m, el = node.firstElementChild;
8093 var shadows, sr, i;
8094 shadows = [];
8095 sr = node.shadowRoot;
8096 while(sr) {
8097 shadows.push(sr);
8098 sr = sr.olderShadowRoot;
8099 }
8100 for(i = shadows.length - 1; i >= 0; i--) {
8101 m = shadows[i].querySelector(selector);
8102 if (m) {
8103 return m;
8104 }
8105 }
8106 while(el) {
8107 m = queryShadow(el, selector);
8108 if (m) {
8109 return m;
8110 }
8111 el = el.nextElementSibling;
8112 }
8113 return null;
8114 }
8115
8116 function queryAllShadows(node, selector, results) {
8117 var el = node.firstElementChild;
8118 var temp, sr, shadows, i, j;
8119 shadows = [];
8120 sr = node.shadowRoot;
8121 while(sr) {
8122 shadows.push(sr);
8123 sr = sr.olderShadowRoot;
8124 }
8125 for (i = shadows.length - 1; i >= 0; i--) {
8126 temp = shadows[i].querySelectorAll(selector);
8127 for(j = 0; j < temp.length; j++) {
8128 results.push(temp[j]);
8129 }
8130 }
8131 while (el) {
8132 queryAllShadows(el, selector, results);
8133 el = el.nextElementSibling;
8134 }
8135 return results;
8136 }
8137
8138 scope.queryAllShadows = function(node, selector, all) {
8139 if (all) {
8140 return queryAllShadows(node, selector, []);
8141 } else {
8142 return queryShadow(node, selector);
8143 }
8144 };
8145 })(window.Platform);
8146
8147 /*
8148 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
8149 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
8150 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
8151 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
8152 * Code distributed by Google as part of the polymer project is also
8153 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
8154 */
8155
8156 /*
8157 This is a limited shim for ShadowDOM css styling.
8158 https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#style s
8159
8160 The intention here is to support only the styling features which can be
8161 relatively simply implemented. The goal is to allow users to avoid the
8162 most obvious pitfalls and do so without compromising performance significantly .
8163 For ShadowDOM styling that's not covered here, a set of best practices
8164 can be provided that should allow users to accomplish more complex styling.
8165
8166 The following is a list of specific ShadowDOM styling features and a brief
8167 discussion of the approach used to shim.
8168
8169 Shimmed features:
8170
8171 * :host, :host-context: ShadowDOM allows styling of the shadowRoot's host
8172 element using the :host rule. To shim this feature, the :host styles are
8173 reformatted and prefixed with a given scope name and promoted to a
8174 document level stylesheet.
8175 For example, given a scope name of .foo, a rule like this:
8176
8177 :host {
8178 background: red;
8179 }
8180 }
8181
8182 becomes:
8183
8184 .foo {
8185 background: red;
8186 }
8187
8188 * encapsultion: Styles defined within ShadowDOM, apply only to
8189 dom inside the ShadowDOM. Polymer uses one of two techniques to imlement
8190 this feature.
8191
8192 By default, rules are prefixed with the host element tag name
8193 as a descendant selector. This ensures styling does not leak out of the 'top'
8194 of the element's ShadowDOM. For example,
8195
8196 div {
8197 font-weight: bold;
8198 }
8199
8200 becomes:
8201
8202 x-foo div {
8203 font-weight: bold;
8204 }
8205
8206 becomes:
8207
8208
8209 Alternatively, if Platform.ShadowCSS.strictStyling is set to true then
8210 selectors are scoped by adding an attribute selector suffix to each
8211 simple selector that contains the host element tag name. Each element
8212 in the element's ShadowDOM template is also given the scope attribute.
8213 Thus, these rules match only elements that have the scope attribute.
8214 For example, given a scope name of x-foo, a rule like this:
8215
8216 div {
8217 font-weight: bold;
8218 }
8219
8220 becomes:
8221
8222 div[x-foo] {
8223 font-weight: bold;
8224 }
8225
8226 Note that elements that are dynamically added to a scope must have the scope
8227 selector added to them manually.
8228
8229 * upper/lower bound encapsulation: Styles which are defined outside a
8230 shadowRoot should not cross the ShadowDOM boundary and should not apply
8231 inside a shadowRoot.
8232
8233 This styling behavior is not emulated. Some possible ways to do this that
8234 were rejected due to complexity and/or performance concerns include: (1) reset
8235 every possible property for every possible selector for a given scope name;
8236 (2) re-implement css in javascript.
8237
8238 As an alternative, users should make sure to use selectors
8239 specific to the scope in which they are working.
8240
8241 * ::distributed: This behavior is not emulated. It's often not necessary
8242 to style the contents of a specific insertion point and instead, descendants
8243 of the host element can be styled selectively. Users can also create an
8244 extra node around an insertion point and style that node's contents
8245 via descendent selectors. For example, with a shadowRoot like this:
8246
8247 <style>
8248 ::content(div) {
8249 background: red;
8250 }
8251 </style>
8252 <content></content>
8253
8254 could become:
8255
8256 <style>
8257 / *@polyfill .content-container div * /
8258 ::content(div) {
8259 background: red;
8260 }
8261 </style>
8262 <div class="content-container">
8263 <content></content>
8264 </div>
8265
8266 Note the use of @polyfill in the comment above a ShadowDOM specific style
8267 declaration. This is a directive to the styling shim to use the selector
8268 in comments in lieu of the next selector when running under polyfill.
8269 */
8270 (function(scope) {
8271
8272 var ShadowCSS = {
8273 strictStyling: false,
8274 registry: {},
8275 // Shim styles for a given root associated with a name and extendsName
8276 // 1. cache root styles by name
8277 // 2. optionally tag root nodes with scope name
8278 // 3. shim polyfill directives /* @polyfill */ and /* @polyfill-rule */
8279 // 4. shim :host and scoping
8280 shimStyling: function(root, name, extendsName) {
8281 var scopeStyles = this.prepareRoot(root, name, extendsName);
8282 var typeExtension = this.isTypeExtension(extendsName);
8283 var scopeSelector = this.makeScopeSelector(name, typeExtension);
8284 // use caching to make working with styles nodes easier and to facilitate
8285 // lookup of extendee
8286 var cssText = stylesToCssText(scopeStyles, true);
8287 cssText = this.scopeCssText(cssText, scopeSelector);
8288 // cache shimmed css on root for user extensibility
8289 if (root) {
8290 root.shimmedStyle = cssText;
8291 }
8292 // add style to document
8293 this.addCssToDocument(cssText, name);
8294 },
8295 /*
8296 * Shim a style element with the given selector. Returns cssText that can
8297 * be included in the document via Platform.ShadowCSS.addCssToDocument(css).
8298 */
8299 shimStyle: function(style, selector) {
8300 return this.shimCssText(style.textContent, selector);
8301 },
8302 /*
8303 * Shim some cssText with the given selector. Returns cssText that can
8304 * be included in the document via Platform.ShadowCSS.addCssToDocument(css).
8305 */
8306 shimCssText: function(cssText, selector) {
8307 cssText = this.insertDirectives(cssText);
8308 return this.scopeCssText(cssText, selector);
8309 },
8310 makeScopeSelector: function(name, typeExtension) {
8311 if (name) {
8312 return typeExtension ? '[is=' + name + ']' : name;
8313 }
8314 return '';
8315 },
8316 isTypeExtension: function(extendsName) {
8317 return extendsName && extendsName.indexOf('-') < 0;
8318 },
8319 prepareRoot: function(root, name, extendsName) {
8320 var def = this.registerRoot(root, name, extendsName);
8321 this.replaceTextInStyles(def.rootStyles, this.insertDirectives);
8322 // remove existing style elements
8323 this.removeStyles(root, def.rootStyles);
8324 // apply strict attr
8325 if (this.strictStyling) {
8326 this.applyScopeToContent(root, name);
8327 }
8328 return def.scopeStyles;
8329 },
8330 removeStyles: function(root, styles) {
8331 for (var i=0, l=styles.length, s; (i<l) && (s=styles[i]); i++) {
8332 s.parentNode.removeChild(s);
8333 }
8334 },
8335 registerRoot: function(root, name, extendsName) {
8336 var def = this.registry[name] = {
8337 root: root,
8338 name: name,
8339 extendsName: extendsName
8340 }
8341 var styles = this.findStyles(root);
8342 def.rootStyles = styles;
8343 def.scopeStyles = def.rootStyles;
8344 var extendee = this.registry[def.extendsName];
8345 if (extendee) {
8346 def.scopeStyles = extendee.scopeStyles.concat(def.scopeStyles);
8347 }
8348 return def;
8349 },
8350 findStyles: function(root) {
8351 if (!root) {
8352 return [];
8353 }
8354 var styles = root.querySelectorAll('style');
8355 return Array.prototype.filter.call(styles, function(s) {
8356 return !s.hasAttribute(NO_SHIM_ATTRIBUTE);
8357 });
8358 },
8359 applyScopeToContent: function(root, name) {
8360 if (root) {
8361 // add the name attribute to each node in root.
8362 Array.prototype.forEach.call(root.querySelectorAll('*'),
8363 function(node) {
8364 node.setAttribute(name, '');
8365 });
8366 // and template contents too
8367 Array.prototype.forEach.call(root.querySelectorAll('template'),
8368 function(template) {
8369 this.applyScopeToContent(template.content, name);
8370 },
8371 this);
8372 }
8373 },
8374 insertDirectives: function(cssText) {
8375 cssText = this.insertPolyfillDirectivesInCssText(cssText);
8376 return this.insertPolyfillRulesInCssText(cssText);
8377 },
8378 /*
8379 * Process styles to convert native ShadowDOM rules that will trip
8380 * up the css parser; we rely on decorating the stylesheet with inert rules.
8381 *
8382 * For example, we convert this rule:
8383 *
8384 * polyfill-next-selector { content: ':host menu-item'; }
8385 * ::content menu-item {
8386 *
8387 * to this:
8388 *
8389 * scopeName menu-item {
8390 *
8391 **/
8392 insertPolyfillDirectivesInCssText: function(cssText) {
8393 // TODO(sorvell): remove either content or comment
8394 cssText = cssText.replace(cssCommentNextSelectorRe, function(match, p1) {
8395 // remove end comment delimiter and add block start
8396 return p1.slice(0, -2) + '{';
8397 });
8398 return cssText.replace(cssContentNextSelectorRe, function(match, p1) {
8399 return p1 + ' {';
8400 });
8401 },
8402 /*
8403 * Process styles to add rules which will only apply under the polyfill
8404 *
8405 * For example, we convert this rule:
8406 *
8407 * polyfill-rule {
8408 * content: ':host menu-item';
8409 * ...
8410 * }
8411 *
8412 * to this:
8413 *
8414 * scopeName menu-item {...}
8415 *
8416 **/
8417 insertPolyfillRulesInCssText: function(cssText) {
8418 // TODO(sorvell): remove either content or comment
8419 cssText = cssText.replace(cssCommentRuleRe, function(match, p1) {
8420 // remove end comment delimiter
8421 return p1.slice(0, -1);
8422 });
8423 return cssText.replace(cssContentRuleRe, function(match, p1, p2, p3) {
8424 var rule = match.replace(p1, '').replace(p2, '');
8425 return p3 + rule;
8426 });
8427 },
8428 /* Ensure styles are scoped. Pseudo-scoping takes a rule like:
8429 *
8430 * .foo {... }
8431 *
8432 * and converts this to
8433 *
8434 * scopeName .foo { ... }
8435 */
8436 scopeCssText: function(cssText, scopeSelector) {
8437 var unscoped = this.extractUnscopedRulesFromCssText(cssText);
8438 cssText = this.insertPolyfillHostInCssText(cssText);
8439 cssText = this.convertColonHost(cssText);
8440 cssText = this.convertColonHostContext(cssText);
8441 cssText = this.convertShadowDOMSelectors(cssText);
8442 if (scopeSelector) {
8443 var self = this, cssText;
8444 withCssRules(cssText, function(rules) {
8445 cssText = self.scopeRules(rules, scopeSelector);
8446 });
8447
8448 }
8449 cssText = cssText + '\n' + unscoped;
8450 return cssText.trim();
8451 },
8452 /*
8453 * Process styles to add rules which will only apply under the polyfill
8454 * and do not process via CSSOM. (CSSOM is destructive to rules on rare
8455 * occasions, e.g. -webkit-calc on Safari.)
8456 * For example, we convert this rule:
8457 *
8458 * (comment start) @polyfill-unscoped-rule menu-item {
8459 * ... } (comment end)
8460 *
8461 * to this:
8462 *
8463 * menu-item {...}
8464 *
8465 **/
8466 extractUnscopedRulesFromCssText: function(cssText) {
8467 // TODO(sorvell): remove either content or comment
8468 var r = '', m;
8469 while (m = cssCommentUnscopedRuleRe.exec(cssText)) {
8470 r += m[1].slice(0, -1) + '\n\n';
8471 }
8472 while (m = cssContentUnscopedRuleRe.exec(cssText)) {
8473 r += m[0].replace(m[2], '').replace(m[1], m[3]) + '\n\n';
8474 }
8475 return r;
8476 },
8477 /*
8478 * convert a rule like :host(.foo) > .bar { }
8479 *
8480 * to
8481 *
8482 * scopeName.foo > .bar
8483 */
8484 convertColonHost: function(cssText) {
8485 return this.convertColonRule(cssText, cssColonHostRe,
8486 this.colonHostPartReplacer);
8487 },
8488 /*
8489 * convert a rule like :host-context(.foo) > .bar { }
8490 *
8491 * to
8492 *
8493 * scopeName.foo > .bar, .foo scopeName > .bar { }
8494 *
8495 * and
8496 *
8497 * :host-context(.foo:host) .bar { ... }
8498 *
8499 * to
8500 *
8501 * scopeName.foo .bar { ... }
8502 */
8503 convertColonHostContext: function(cssText) {
8504 return this.convertColonRule(cssText, cssColonHostContextRe,
8505 this.colonHostContextPartReplacer);
8506 },
8507 convertColonRule: function(cssText, regExp, partReplacer) {
8508 // p1 = :host, p2 = contents of (), p3 rest of rule
8509 return cssText.replace(regExp, function(m, p1, p2, p3) {
8510 p1 = polyfillHostNoCombinator;
8511 if (p2) {
8512 var parts = p2.split(','), r = [];
8513 for (var i=0, l=parts.length, p; (i<l) && (p=parts[i]); i++) {
8514 p = p.trim();
8515 r.push(partReplacer(p1, p, p3));
8516 }
8517 return r.join(',');
8518 } else {
8519 return p1 + p3;
8520 }
8521 });
8522 },
8523 colonHostContextPartReplacer: function(host, part, suffix) {
8524 if (part.match(polyfillHost)) {
8525 return this.colonHostPartReplacer(host, part, suffix);
8526 } else {
8527 return host + part + suffix + ', ' + part + ' ' + host + suffix;
8528 }
8529 },
8530 colonHostPartReplacer: function(host, part, suffix) {
8531 return host + part.replace(polyfillHost, '') + suffix;
8532 },
8533 /*
8534 * Convert combinators like ::shadow and pseudo-elements like ::content
8535 * by replacing with space.
8536 */
8537 convertShadowDOMSelectors: function(cssText) {
8538 for (var i=0; i < shadowDOMSelectorsRe.length; i++) {
8539 cssText = cssText.replace(shadowDOMSelectorsRe[i], ' ');
8540 }
8541 return cssText;
8542 },
8543 // change a selector like 'div' to 'name div'
8544 scopeRules: function(cssRules, scopeSelector) {
8545 var cssText = '';
8546 if (cssRules) {
8547 Array.prototype.forEach.call(cssRules, function(rule) {
8548 if (rule.selectorText && (rule.style && rule.style.cssText !== undefined )) {
8549 cssText += this.scopeSelector(rule.selectorText, scopeSelector,
8550 this.strictStyling) + ' {\n\t';
8551 cssText += this.propertiesFromRule(rule) + '\n}\n\n';
8552 } else if (rule.type === CSSRule.MEDIA_RULE) {
8553 cssText += '@media ' + rule.media.mediaText + ' {\n';
8554 cssText += this.scopeRules(rule.cssRules, scopeSelector);
8555 cssText += '\n}\n\n';
8556 } else {
8557 // KEYFRAMES_RULE in IE throws when we query cssText
8558 // when it contains a -webkit- property.
8559 // if this happens, we fallback to constructing the rule
8560 // from the CSSRuleSet
8561 // https://connect.microsoft.com/IE/feedbackdetail/view/955703/accessi ng-csstext-of-a-keyframe-rule-that-contains-a-webkit-property-via-cssom-generate s-exception
8562 try {
8563 if (rule.cssText) {
8564 cssText += rule.cssText + '\n\n';
8565 }
8566 } catch(x) {
8567 if (rule.type === CSSRule.KEYFRAMES_RULE && rule.cssRules) {
8568 cssText += this.ieSafeCssTextFromKeyFrameRule(rule);
8569 }
8570 }
8571 }
8572 }, this);
8573 }
8574 return cssText;
8575 },
8576 ieSafeCssTextFromKeyFrameRule: function(rule) {
8577 var cssText = '@keyframes ' + rule.name + ' {';
8578 Array.prototype.forEach.call(rule.cssRules, function(rule) {
8579 cssText += ' ' + rule.keyText + ' {' + rule.style.cssText + '}';
8580 });
8581 cssText += ' }';
8582 return cssText;
8583 },
8584 scopeSelector: function(selector, scopeSelector, strict) {
8585 var r = [], parts = selector.split(',');
8586 parts.forEach(function(p) {
8587 p = p.trim();
8588 if (this.selectorNeedsScoping(p, scopeSelector)) {
8589 p = (strict && !p.match(polyfillHostNoCombinator)) ?
8590 this.applyStrictSelectorScope(p, scopeSelector) :
8591 this.applySelectorScope(p, scopeSelector);
8592 }
8593 r.push(p);
8594 }, this);
8595 return r.join(', ');
8596 },
8597 selectorNeedsScoping: function(selector, scopeSelector) {
8598 if (Array.isArray(scopeSelector)) {
8599 return true;
8600 }
8601 var re = this.makeScopeMatcher(scopeSelector);
8602 return !selector.match(re);
8603 },
8604 makeScopeMatcher: function(scopeSelector) {
8605 scopeSelector = scopeSelector.replace(/\[/g, '\\[').replace(/\[/g, '\\]');
8606 return new RegExp('^(' + scopeSelector + ')' + selectorReSuffix, 'm');
8607 },
8608 applySelectorScope: function(selector, selectorScope) {
8609 return Array.isArray(selectorScope) ?
8610 this.applySelectorScopeList(selector, selectorScope) :
8611 this.applySimpleSelectorScope(selector, selectorScope);
8612 },
8613 // apply an array of selectors
8614 applySelectorScopeList: function(selector, scopeSelectorList) {
8615 var r = [];
8616 for (var i=0, s; (s=scopeSelectorList[i]); i++) {
8617 r.push(this.applySimpleSelectorScope(selector, s));
8618 }
8619 return r.join(', ');
8620 },
8621 // scope via name and [is=name]
8622 applySimpleSelectorScope: function(selector, scopeSelector) {
8623 if (selector.match(polyfillHostRe)) {
8624 selector = selector.replace(polyfillHostNoCombinator, scopeSelector);
8625 return selector.replace(polyfillHostRe, scopeSelector + ' ');
8626 } else {
8627 return scopeSelector + ' ' + selector;
8628 }
8629 },
8630 // return a selector with [name] suffix on each simple selector
8631 // e.g. .foo.bar > .zot becomes .foo[name].bar[name] > .zot[name]
8632 applyStrictSelectorScope: function(selector, scopeSelector) {
8633 scopeSelector = scopeSelector.replace(/\[is=([^\]]*)\]/g, '$1');
8634 var splits = [' ', '>', '+', '~'],
8635 scoped = selector,
8636 attrName = '[' + scopeSelector + ']';
8637 splits.forEach(function(sep) {
8638 var parts = scoped.split(sep);
8639 scoped = parts.map(function(p) {
8640 // remove :host since it should be unnecessary
8641 var t = p.trim().replace(polyfillHostRe, '');
8642 if (t && (splits.indexOf(t) < 0) && (t.indexOf(attrName) < 0)) {
8643 p = t.replace(/([^:]*)(:*)(.*)/, '$1' + attrName + '$2$3')
8644 }
8645 return p;
8646 }).join(sep);
8647 });
8648 return scoped;
8649 },
8650 insertPolyfillHostInCssText: function(selector) {
8651 return selector.replace(colonHostContextRe, polyfillHostContext).replace(
8652 colonHostRe, polyfillHost);
8653 },
8654 propertiesFromRule: function(rule) {
8655 var cssText = rule.style.cssText;
8656 // TODO(sorvell): Safari cssom incorrectly removes quotes from the content
8657 // property. (https://bugs.webkit.org/show_bug.cgi?id=118045)
8658 // don't replace attr rules
8659 if (rule.style.content && !rule.style.content.match(/['"]+|attr/)) {
8660 cssText = cssText.replace(/content:[^;]*;/g, 'content: \'' +
8661 rule.style.content + '\';');
8662 }
8663 // TODO(sorvell): we can workaround this issue here, but we need a list
8664 // of troublesome properties to fix https://github.com/Polymer/platform/issu es/53
8665 //
8666 // inherit rules can be omitted from cssText
8667 // TODO(sorvell): remove when Blink bug is fixed:
8668 // https://code.google.com/p/chromium/issues/detail?id=358273
8669 var style = rule.style;
8670 for (var i in style) {
8671 if (style[i] === 'initial') {
8672 cssText += i + ': initial; ';
8673 }
8674 }
8675 return cssText;
8676 },
8677 replaceTextInStyles: function(styles, action) {
8678 if (styles && action) {
8679 if (!(styles instanceof Array)) {
8680 styles = [styles];
8681 }
8682 Array.prototype.forEach.call(styles, function(s) {
8683 s.textContent = action.call(this, s.textContent);
8684 }, this);
8685 }
8686 },
8687 addCssToDocument: function(cssText, name) {
8688 if (cssText.match('@import')) {
8689 addOwnSheet(cssText, name);
8690 } else {
8691 addCssToDocument(cssText);
8692 }
8693 }
8694 };
8695
8696 var selectorRe = /([^{]*)({[\s\S]*?})/gim,
8697 cssCommentRe = /\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim,
8698 // TODO(sorvell): remove either content or comment
8699 cssCommentNextSelectorRe = /\/\*\s*@polyfill ([^*]*\*+([^/*][^*]*\*+)*\/)([^ {]*?){/gim,
8700 cssContentNextSelectorRe = /polyfill-next-selector[^}]*content\:[\s]*?['"](. *?)['"][;\s]*}([^{]*?){/gim,
8701 // TODO(sorvell): remove either content or comment
8702 cssCommentRuleRe = /\/\*\s@polyfill-rule([^*]*\*+([^/*][^*]*\*+)*)\//gim,
8703 cssContentRuleRe = /(polyfill-rule)[^}]*(content\:[\s]*['"](.*?)['"])[;\s]*[ ^}]*}/gim,
8704 // TODO(sorvell): remove either content or comment
8705 cssCommentUnscopedRuleRe = /\/\*\s@polyfill-unscoped-rule([^*]*\*+([^/*][^*] *\*+)*)\//gim,
8706 cssContentUnscopedRuleRe = /(polyfill-unscoped-rule)[^}]*(content\:[\s]*['"] (.*?)['"])[;\s]*[^}]*}/gim,
8707 cssPseudoRe = /::(x-[^\s{,(]*)/gim,
8708 cssPartRe = /::part\(([^)]*)\)/gim,
8709 // note: :host pre-processed to -shadowcsshost.
8710 polyfillHost = '-shadowcsshost',
8711 // note: :host-context pre-processed to -shadowcsshostcontext.
8712 polyfillHostContext = '-shadowcsscontext',
8713 parenSuffix = ')(?:\\((' +
8714 '(?:\\([^)(]*\\)|[^)(]*)+?' +
8715 ')\\))?([^,{]*)';
8716 cssColonHostRe = new RegExp('(' + polyfillHost + parenSuffix, 'gim'),
8717 cssColonHostContextRe = new RegExp('(' + polyfillHostContext + parenSuffix, 'gim'),
8718 selectorReSuffix = '([>\\s~+\[.,{:][\\s\\S]*)?$',
8719 colonHostRe = /\:host/gim,
8720 colonHostContextRe = /\:host-context/gim,
8721 /* host name without combinator */
8722 polyfillHostNoCombinator = polyfillHost + '-no-combinator',
8723 polyfillHostRe = new RegExp(polyfillHost, 'gim'),
8724 polyfillHostContextRe = new RegExp(polyfillHostContext, 'gim'),
8725 shadowDOMSelectorsRe = [
8726 /\^\^/g,
8727 /\^/g,
8728 /\/shadow\//g,
8729 /\/shadow-deep\//g,
8730 /::shadow/g,
8731 /\/deep\//g,
8732 /::content/g
8733 ];
8734
8735 function stylesToCssText(styles, preserveComments) {
8736 var cssText = '';
8737 Array.prototype.forEach.call(styles, function(s) {
8738 cssText += s.textContent + '\n\n';
8739 });
8740 // strip comments for easier processing
8741 if (!preserveComments) {
8742 cssText = cssText.replace(cssCommentRe, '');
8743 }
8744 return cssText;
8745 }
8746
8747 function cssTextToStyle(cssText) {
8748 var style = document.createElement('style');
8749 style.textContent = cssText;
8750 return style;
8751 }
8752
8753 function cssToRules(cssText) {
8754 var style = cssTextToStyle(cssText);
8755 document.head.appendChild(style);
8756 var rules = [];
8757 if (style.sheet) {
8758 // TODO(sorvell): Firefox throws when accessing the rules of a stylesheet
8759 // with an @import
8760 // https://bugzilla.mozilla.org/show_bug.cgi?id=625013
8761 try {
8762 rules = style.sheet.cssRules;
8763 } catch(e) {
8764 //
8765 }
8766 } else {
8767 console.warn('sheet not found', style);
8768 }
8769 style.parentNode.removeChild(style);
8770 return rules;
8771 }
8772
8773 var frame = document.createElement('iframe');
8774 frame.style.display = 'none';
8775
8776 function initFrame() {
8777 frame.initialized = true;
8778 document.body.appendChild(frame);
8779 var doc = frame.contentDocument;
8780 var base = doc.createElement('base');
8781 base.href = document.baseURI;
8782 doc.head.appendChild(base);
8783 }
8784
8785 function inFrame(fn) {
8786 if (!frame.initialized) {
8787 initFrame();
8788 }
8789 document.body.appendChild(frame);
8790 fn(frame.contentDocument);
8791 document.body.removeChild(frame);
8792 }
8793
8794 // TODO(sorvell): use an iframe if the cssText contains an @import to workaround
8795 // https://code.google.com/p/chromium/issues/detail?id=345114
8796 var isChrome = navigator.userAgent.match('Chrome');
8797 function withCssRules(cssText, callback) {
8798 if (!callback) {
8799 return;
8800 }
8801 var rules;
8802 if (cssText.match('@import') && isChrome) {
8803 var style = cssTextToStyle(cssText);
8804 inFrame(function(doc) {
8805 doc.head.appendChild(style.impl);
8806 rules = Array.prototype.slice.call(style.sheet.cssRules, 0);
8807 callback(rules);
8808 });
8809 } else {
8810 rules = cssToRules(cssText);
8811 callback(rules);
8812 }
8813 }
8814
8815 function rulesToCss(cssRules) {
8816 for (var i=0, css=[]; i < cssRules.length; i++) {
8817 css.push(cssRules[i].cssText);
8818 }
8819 return css.join('\n\n');
8820 }
8821
8822 function addCssToDocument(cssText) {
8823 if (cssText) {
8824 getSheet().appendChild(document.createTextNode(cssText));
8825 }
8826 }
8827
8828 function addOwnSheet(cssText, name) {
8829 var style = cssTextToStyle(cssText);
8830 style.setAttribute(name, '');
8831 style.setAttribute(SHIMMED_ATTRIBUTE, '');
8832 document.head.appendChild(style);
8833 }
8834
8835 var SHIM_ATTRIBUTE = 'shim-shadowdom';
8836 var SHIMMED_ATTRIBUTE = 'shim-shadowdom-css';
8837 var NO_SHIM_ATTRIBUTE = 'no-shim';
8838
8839 var sheet;
8840 function getSheet() {
8841 if (!sheet) {
8842 sheet = document.createElement("style");
8843 sheet.setAttribute(SHIMMED_ATTRIBUTE, '');
8844 sheet[SHIMMED_ATTRIBUTE] = true;
8845 }
8846 return sheet;
8847 }
8848
8849 // add polyfill stylesheet to document
8850 if (window.ShadowDOMPolyfill) {
8851 addCssToDocument('style { display: none !important; }\n');
8852 var doc = wrap(document);
8853 var head = doc.querySelector('head');
8854 head.insertBefore(getSheet(), head.childNodes[0]);
8855
8856 // TODO(sorvell): monkey-patching HTMLImports is abusive;
8857 // consider a better solution.
8858 document.addEventListener('DOMContentLoaded', function() {
8859 var urlResolver = scope.urlResolver;
8860
8861 if (window.HTMLImports && !HTMLImports.useNative) {
8862 var SHIM_SHEET_SELECTOR = 'link[rel=stylesheet]' +
8863 '[' + SHIM_ATTRIBUTE + ']';
8864 var SHIM_STYLE_SELECTOR = 'style[' + SHIM_ATTRIBUTE + ']';
8865 HTMLImports.importer.documentPreloadSelectors += ',' + SHIM_SHEET_SELECTOR ;
8866 HTMLImports.importer.importsPreloadSelectors += ',' + SHIM_SHEET_SELECTOR;
8867
8868 HTMLImports.parser.documentSelectors = [
8869 HTMLImports.parser.documentSelectors,
8870 SHIM_SHEET_SELECTOR,
8871 SHIM_STYLE_SELECTOR
8872 ].join(',');
8873
8874 var originalParseGeneric = HTMLImports.parser.parseGeneric;
8875
8876 HTMLImports.parser.parseGeneric = function(elt) {
8877 if (elt[SHIMMED_ATTRIBUTE]) {
8878 return;
8879 }
8880 var style = elt.__importElement || elt;
8881 if (!style.hasAttribute(SHIM_ATTRIBUTE)) {
8882 originalParseGeneric.call(this, elt);
8883 return;
8884 }
8885 if (elt.__resource) {
8886 style = elt.ownerDocument.createElement('style');
8887 style.textContent = elt.__resource;
8888 }
8889 // relay on HTMLImports for path fixup
8890 HTMLImports.path.resolveUrlsInStyle(style);
8891 style.textContent = ShadowCSS.shimStyle(style);
8892 style.removeAttribute(SHIM_ATTRIBUTE, '');
8893 style.setAttribute(SHIMMED_ATTRIBUTE, '');
8894 style[SHIMMED_ATTRIBUTE] = true;
8895 // place in document
8896 if (style.parentNode !== head) {
8897 // replace links in head
8898 if (elt.parentNode === head) {
8899 head.replaceChild(style, elt);
8900 } else {
8901 this.addElementToDocument(style);
8902 }
8903 }
8904 style.__importParsed = true;
8905 this.markParsingComplete(elt);
8906 this.parseNext();
8907 }
8908
8909 var hasResource = HTMLImports.parser.hasResource;
8910 HTMLImports.parser.hasResource = function(node) {
8911 if (node.localName === 'link' && node.rel === 'stylesheet' &&
8912 node.hasAttribute(SHIM_ATTRIBUTE)) {
8913 return (node.__resource);
8914 } else {
8915 return hasResource.call(this, node);
8916 }
8917 }
8918
8919 }
8920 });
8921 }
8922
8923 // exports
8924 scope.ShadowCSS = ShadowCSS;
8925
8926 })(window.Platform);
8927
8928 } else {
8929 /*
8930 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
8931 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
8932 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
8933 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
8934 * Code distributed by Google as part of the polymer project is also
8935 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
8936 */
8937
8938 (function(scope) {
8939
8940 // so we can call wrap/unwrap without testing for ShadowDOMPolyfill
8941 window.wrap = window.unwrap = function(n){
8942 return n;
8943 }
8944
8945 addEventListener('DOMContentLoaded', function() {
8946 if (CustomElements.useNative === false) {
8947 var originalCreateShadowRoot = Element.prototype.createShadowRoot;
8948 Element.prototype.createShadowRoot = function() {
8949 var root = originalCreateShadowRoot.call(this);
8950 CustomElements.watchShadow(this);
8951 return root;
8952 };
8953 }
8954 });
8955
8956 })(window.Platform);
8957
8958 }
8959 /* Any copyright is dedicated to the Public Domain.
8960 * http://creativecommons.org/publicdomain/zero/1.0/ */
8961
8962 (function(scope) {
8963 'use strict';
8964
8965 // feature detect for URL constructor
8966 var hasWorkingUrl = false;
8967 if (!scope.forceJURL) {
8968 try {
8969 var u = new URL('b', 'http://a');
8970 hasWorkingUrl = u.href === 'http://a/b';
8971 } catch(e) {}
8972 }
8973
8974 if (hasWorkingUrl)
8975 return;
8976
8977 var relative = Object.create(null);
8978 relative['ftp'] = 21;
8979 relative['file'] = 0;
8980 relative['gopher'] = 70;
8981 relative['http'] = 80;
8982 relative['https'] = 443;
8983 relative['ws'] = 80;
8984 relative['wss'] = 443;
8985
8986 var relativePathDotMapping = Object.create(null);
8987 relativePathDotMapping['%2e'] = '.';
8988 relativePathDotMapping['.%2e'] = '..';
8989 relativePathDotMapping['%2e.'] = '..';
8990 relativePathDotMapping['%2e%2e'] = '..';
8991
8992 function isRelativeScheme(scheme) {
8993 return relative[scheme] !== undefined;
8994 }
8995
8996 function invalid() {
8997 clear.call(this);
8998 this._isInvalid = true;
8999 }
9000
9001 function IDNAToASCII(h) {
9002 if ('' == h) {
9003 invalid.call(this)
9004 }
9005 // XXX
9006 return h.toLowerCase()
9007 }
9008
9009 function percentEscape(c) {
9010 var unicode = c.charCodeAt(0);
9011 if (unicode > 0x20 &&
9012 unicode < 0x7F &&
9013 // " # < > ? `
9014 [0x22, 0x23, 0x3C, 0x3E, 0x3F, 0x60].indexOf(unicode) == -1
9015 ) {
9016 return c;
9017 }
9018 return encodeURIComponent(c);
9019 }
9020
9021 function percentEscapeQuery(c) {
9022 // XXX This actually needs to encode c using encoding and then
9023 // convert the bytes one-by-one.
9024
9025 var unicode = c.charCodeAt(0);
9026 if (unicode > 0x20 &&
9027 unicode < 0x7F &&
9028 // " # < > ` (do not escape '?')
9029 [0x22, 0x23, 0x3C, 0x3E, 0x60].indexOf(unicode) == -1
9030 ) {
9031 return c;
9032 }
9033 return encodeURIComponent(c);
9034 }
9035
9036 var EOF = undefined,
9037 ALPHA = /[a-zA-Z]/,
9038 ALPHANUMERIC = /[a-zA-Z0-9\+\-\.]/;
9039
9040 function parse(input, stateOverride, base) {
9041 function err(message) {
9042 errors.push(message)
9043 }
9044
9045 var state = stateOverride || 'scheme start',
9046 cursor = 0,
9047 buffer = '',
9048 seenAt = false,
9049 seenBracket = false,
9050 errors = [];
9051
9052 loop: while ((input[cursor - 1] != EOF || cursor == 0) && !this._isInvalid) {
9053 var c = input[cursor];
9054 switch (state) {
9055 case 'scheme start':
9056 if (c && ALPHA.test(c)) {
9057 buffer += c.toLowerCase(); // ASCII-safe
9058 state = 'scheme';
9059 } else if (!stateOverride) {
9060 buffer = '';
9061 state = 'no scheme';
9062 continue;
9063 } else {
9064 err('Invalid scheme.');
9065 break loop;
9066 }
9067 break;
9068
9069 case 'scheme':
9070 if (c && ALPHANUMERIC.test(c)) {
9071 buffer += c.toLowerCase(); // ASCII-safe
9072 } else if (':' == c) {
9073 this._scheme = buffer;
9074 buffer = '';
9075 if (stateOverride) {
9076 break loop;
9077 }
9078 if (isRelativeScheme(this._scheme)) {
9079 this._isRelative = true;
9080 }
9081 if ('file' == this._scheme) {
9082 state = 'relative';
9083 } else if (this._isRelative && base && base._scheme == this._scheme) {
9084 state = 'relative or authority';
9085 } else if (this._isRelative) {
9086 state = 'authority first slash';
9087 } else {
9088 state = 'scheme data';
9089 }
9090 } else if (!stateOverride) {
9091 buffer = '';
9092 cursor = 0;
9093 state = 'no scheme';
9094 continue;
9095 } else if (EOF == c) {
9096 break loop;
9097 } else {
9098 err('Code point not allowed in scheme: ' + c)
9099 break loop;
9100 }
9101 break;
9102
9103 case 'scheme data':
9104 if ('?' == c) {
9105 query = '?';
9106 state = 'query';
9107 } else if ('#' == c) {
9108 this._fragment = '#';
9109 state = 'fragment';
9110 } else {
9111 // XXX error handling
9112 if (EOF != c && '\t' != c && '\n' != c && '\r' != c) {
9113 this._schemeData += percentEscape(c);
9114 }
9115 }
9116 break;
9117
9118 case 'no scheme':
9119 if (!base || !(isRelativeScheme(base._scheme))) {
9120 err('Missing scheme.');
9121 invalid.call(this);
9122 } else {
9123 state = 'relative';
9124 continue;
9125 }
9126 break;
9127
9128 case 'relative or authority':
9129 if ('/' == c && '/' == input[cursor+1]) {
9130 state = 'authority ignore slashes';
9131 } else {
9132 err('Expected /, got: ' + c);
9133 state = 'relative';
9134 continue
9135 }
9136 break;
9137
9138 case 'relative':
9139 this._isRelative = true;
9140 if ('file' != this._scheme)
9141 this._scheme = base._scheme;
9142 if (EOF == c) {
9143 this._host = base._host;
9144 this._port = base._port;
9145 this._path = base._path.slice();
9146 this._query = base._query;
9147 break loop;
9148 } else if ('/' == c || '\\' == c) {
9149 if ('\\' == c)
9150 err('\\ is an invalid code point.');
9151 state = 'relative slash';
9152 } else if ('?' == c) {
9153 this._host = base._host;
9154 this._port = base._port;
9155 this._path = base._path.slice();
9156 this._query = '?';
9157 state = 'query';
9158 } else if ('#' == c) {
9159 this._host = base._host;
9160 this._port = base._port;
9161 this._path = base._path.slice();
9162 this._query = base._query;
9163 this._fragment = '#';
9164 state = 'fragment';
9165 } else {
9166 var nextC = input[cursor+1]
9167 var nextNextC = input[cursor+2]
9168 if (
9169 'file' != this._scheme || !ALPHA.test(c) ||
9170 (nextC != ':' && nextC != '|') ||
9171 (EOF != nextNextC && '/' != nextNextC && '\\' != nextNextC && '?' != nextNextC && '#' != nextNextC)) {
9172 this._host = base._host;
9173 this._port = base._port;
9174 this._path = base._path.slice();
9175 this._path.pop();
9176 }
9177 state = 'relative path';
9178 continue;
9179 }
9180 break;
9181
9182 case 'relative slash':
9183 if ('/' == c || '\\' == c) {
9184 if ('\\' == c) {
9185 err('\\ is an invalid code point.');
9186 }
9187 if ('file' == this._scheme) {
9188 state = 'file host';
9189 } else {
9190 state = 'authority ignore slashes';
9191 }
9192 } else {
9193 if ('file' != this._scheme) {
9194 this._host = base._host;
9195 this._port = base._port;
9196 }
9197 state = 'relative path';
9198 continue;
9199 }
9200 break;
9201
9202 case 'authority first slash':
9203 if ('/' == c) {
9204 state = 'authority second slash';
9205 } else {
9206 err("Expected '/', got: " + c);
9207 state = 'authority ignore slashes';
9208 continue;
9209 }
9210 break;
9211
9212 case 'authority second slash':
9213 state = 'authority ignore slashes';
9214 if ('/' != c) {
9215 err("Expected '/', got: " + c);
9216 continue;
9217 }
9218 break;
9219
9220 case 'authority ignore slashes':
9221 if ('/' != c && '\\' != c) {
9222 state = 'authority';
9223 continue;
9224 } else {
9225 err('Expected authority, got: ' + c);
9226 }
9227 break;
9228
9229 case 'authority':
9230 if ('@' == c) {
9231 if (seenAt) {
9232 err('@ already seen.');
9233 buffer += '%40';
9234 }
9235 seenAt = true;
9236 for (var i = 0; i < buffer.length; i++) {
9237 var cp = buffer[i];
9238 if ('\t' == cp || '\n' == cp || '\r' == cp) {
9239 err('Invalid whitespace in authority.');
9240 continue;
9241 }
9242 // XXX check URL code points
9243 if (':' == cp && null === this._password) {
9244 this._password = '';
9245 continue;
9246 }
9247 var tempC = percentEscape(cp);
9248 (null !== this._password) ? this._password += tempC : this._userna me += tempC;
9249 }
9250 buffer = '';
9251 } else if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c) {
9252 cursor -= buffer.length;
9253 buffer = '';
9254 state = 'host';
9255 continue;
9256 } else {
9257 buffer += c;
9258 }
9259 break;
9260
9261 case 'file host':
9262 if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c) {
9263 if (buffer.length == 2 && ALPHA.test(buffer[0]) && (buffer[1] == ':' || buffer[1] == '|')) {
9264 state = 'relative path';
9265 } else if (buffer.length == 0) {
9266 state = 'relative path start';
9267 } else {
9268 this._host = IDNAToASCII.call(this, buffer);
9269 buffer = '';
9270 state = 'relative path start';
9271 }
9272 continue;
9273 } else if ('\t' == c || '\n' == c || '\r' == c) {
9274 err('Invalid whitespace in file host.');
9275 } else {
9276 buffer += c;
9277 }
9278 break;
9279
9280 case 'host':
9281 case 'hostname':
9282 if (':' == c && !seenBracket) {
9283 // XXX host parsing
9284 this._host = IDNAToASCII.call(this, buffer);
9285 buffer = '';
9286 state = 'port';
9287 if ('hostname' == stateOverride) {
9288 break loop;
9289 }
9290 } else if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c) {
9291 this._host = IDNAToASCII.call(this, buffer);
9292 buffer = '';
9293 state = 'relative path start';
9294 if (stateOverride) {
9295 break loop;
9296 }
9297 continue;
9298 } else if ('\t' != c && '\n' != c && '\r' != c) {
9299 if ('[' == c) {
9300 seenBracket = true;
9301 } else if (']' == c) {
9302 seenBracket = false;
9303 }
9304 buffer += c;
9305 } else {
9306 err('Invalid code point in host/hostname: ' + c);
9307 }
9308 break;
9309
9310 case 'port':
9311 if (/[0-9]/.test(c)) {
9312 buffer += c;
9313 } else if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c | | stateOverride) {
9314 if ('' != buffer) {
9315 var temp = parseInt(buffer, 10);
9316 if (temp != relative[this._scheme]) {
9317 this._port = temp + '';
9318 }
9319 buffer = '';
9320 }
9321 if (stateOverride) {
9322 break loop;
9323 }
9324 state = 'relative path start';
9325 continue;
9326 } else if ('\t' == c || '\n' == c || '\r' == c) {
9327 err('Invalid code point in port: ' + c);
9328 } else {
9329 invalid.call(this);
9330 }
9331 break;
9332
9333 case 'relative path start':
9334 if ('\\' == c)
9335 err("'\\' not allowed in path.");
9336 state = 'relative path';
9337 if ('/' != c && '\\' != c) {
9338 continue;
9339 }
9340 break;
9341
9342 case 'relative path':
9343 if (EOF == c || '/' == c || '\\' == c || (!stateOverride && ('?' == c || '#' == c))) {
9344 if ('\\' == c) {
9345 err('\\ not allowed in relative path.');
9346 }
9347 var tmp;
9348 if (tmp = relativePathDotMapping[buffer.toLowerCase()]) {
9349 buffer = tmp;
9350 }
9351 if ('..' == buffer) {
9352 this._path.pop();
9353 if ('/' != c && '\\' != c) {
9354 this._path.push('');
9355 }
9356 } else if ('.' == buffer && '/' != c && '\\' != c) {
9357 this._path.push('');
9358 } else if ('.' != buffer) {
9359 if ('file' == this._scheme && this._path.length == 0 && buffer.len gth == 2 && ALPHA.test(buffer[0]) && buffer[1] == '|') {
9360 buffer = buffer[0] + ':';
9361 }
9362 this._path.push(buffer);
9363 }
9364 buffer = '';
9365 if ('?' == c) {
9366 this._query = '?';
9367 state = 'query';
9368 } else if ('#' == c) {
9369 this._fragment = '#';
9370 state = 'fragment';
9371 }
9372 } else if ('\t' != c && '\n' != c && '\r' != c) {
9373 buffer += percentEscape(c);
9374 }
9375 break;
9376
9377 case 'query':
9378 if (!stateOverride && '#' == c) {
9379 this._fragment = '#';
9380 state = 'fragment';
9381 } else if (EOF != c && '\t' != c && '\n' != c && '\r' != c) {
9382 this._query += percentEscapeQuery(c);
9383 }
9384 break;
9385
9386 case 'fragment':
9387 if (EOF != c && '\t' != c && '\n' != c && '\r' != c) {
9388 this._fragment += c;
9389 }
9390 break;
9391 }
9392
9393 cursor++;
9394 }
9395 }
9396
9397 function clear() {
9398 this._scheme = '';
9399 this._schemeData = '';
9400 this._username = '';
9401 this._password = null;
9402 this._host = '';
9403 this._port = '';
9404 this._path = [];
9405 this._query = '';
9406 this._fragment = '';
9407 this._isInvalid = false;
9408 this._isRelative = false;
9409 }
9410
9411 // Does not process domain names or IP addresses.
9412 // Does not handle encoding for the query parameter.
9413 function jURL(url, base /* , encoding */) {
9414 if (base !== undefined && !(base instanceof jURL))
9415 base = new jURL(String(base));
9416
9417 this._url = url;
9418 clear.call(this);
9419
9420 var input = url.replace(/^[ \t\r\n\f]+|[ \t\r\n\f]+$/g, '');
9421 // encoding = encoding || 'utf-8'
9422
9423 parse.call(this, input, null, base);
9424 }
9425
9426 jURL.prototype = {
9427 get href() {
9428 if (this._isInvalid)
9429 return this._url;
9430
9431 var authority = '';
9432 if ('' != this._username || null != this._password) {
9433 authority = this._username +
9434 (null != this._password ? ':' + this._password : '') + '@';
9435 }
9436
9437 return this.protocol +
9438 (this._isRelative ? '//' + authority + this.host : '') +
9439 this.pathname + this._query + this._fragment;
9440 },
9441 set href(href) {
9442 clear.call(this);
9443 parse.call(this, href);
9444 },
9445
9446 get protocol() {
9447 return this._scheme + ':';
9448 },
9449 set protocol(protocol) {
9450 if (this._isInvalid)
9451 return;
9452 parse.call(this, protocol + ':', 'scheme start');
9453 },
9454
9455 get host() {
9456 return this._isInvalid ? '' : this._port ?
9457 this._host + ':' + this._port : this._host;
9458 },
9459 set host(host) {
9460 if (this._isInvalid || !this._isRelative)
9461 return;
9462 parse.call(this, host, 'host');
9463 },
9464
9465 get hostname() {
9466 return this._host;
9467 },
9468 set hostname(hostname) {
9469 if (this._isInvalid || !this._isRelative)
9470 return;
9471 parse.call(this, hostname, 'hostname');
9472 },
9473
9474 get port() {
9475 return this._port;
9476 },
9477 set port(port) {
9478 if (this._isInvalid || !this._isRelative)
9479 return;
9480 parse.call(this, port, 'port');
9481 },
9482
9483 get pathname() {
9484 return this._isInvalid ? '' : this._isRelative ?
9485 '/' + this._path.join('/') : this._schemeData;
9486 },
9487 set pathname(pathname) {
9488 if (this._isInvalid || !this._isRelative)
9489 return;
9490 this._path = [];
9491 parse.call(this, pathname, 'relative path start');
9492 },
9493
9494 get search() {
9495 return this._isInvalid || !this._query || '?' == this._query ?
9496 '' : this._query;
9497 },
9498 set search(search) {
9499 if (this._isInvalid || !this._isRelative)
9500 return;
9501 this._query = '?';
9502 if ('?' == search[0])
9503 search = search.slice(1);
9504 parse.call(this, search, 'query');
9505 },
9506
9507 get hash() {
9508 return this._isInvalid || !this._fragment || '#' == this._fragment ?
9509 '' : this._fragment;
9510 },
9511 set hash(hash) {
9512 if (this._isInvalid)
9513 return;
9514 this._fragment = '#';
9515 if ('#' == hash[0])
9516 hash = hash.slice(1);
9517 parse.call(this, hash, 'fragment');
9518 },
9519
9520 get origin() {
9521 var host;
9522 if (this._isInvalid || !this._scheme) {
9523 return '';
9524 }
9525 // javascript: Gecko returns String(""), WebKit/Blink String("null")
9526 // Gecko throws error for "data://"
9527 // data: Gecko returns "", Blink returns "data://", WebKit returns "null"
9528 // Gecko returns String("") for file: mailto:
9529 // WebKit/Blink returns String("SCHEME://") for file: mailto:
9530 switch (this._scheme) {
9531 case 'data':
9532 case 'file':
9533 case 'javascript':
9534 case 'mailto':
9535 return 'null';
9536 }
9537 host = this.host;
9538 if (!host) {
9539 return '';
9540 }
9541 return this._scheme + '://' + host;
9542 }
9543 };
9544
9545 // Copy over the static methods
9546 var OriginalURL = scope.URL;
9547 if (OriginalURL) {
9548 jURL.createObjectURL = function(blob) {
9549 // IE extension allows a second optional options argument.
9550 // http://msdn.microsoft.com/en-us/library/ie/hh772302(v=vs.85).aspx
9551 return OriginalURL.createObjectURL.apply(OriginalURL, arguments);
9552 };
9553 jURL.revokeObjectURL = function(url) {
9554 OriginalURL.revokeObjectURL(url);
9555 };
9556 }
9557
9558 scope.URL = jURL;
9559
9560 })(this);
9561
9562 /*
9563 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
9564 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
9565 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
9566 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
9567 * Code distributed by Google as part of the polymer project is also
9568 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
9569 */
9570
9571 (function(scope) {
9572
9573 // Old versions of iOS do not have bind.
9574
9575 if (!Function.prototype.bind) {
9576 Function.prototype.bind = function(scope) {
9577 var self = this;
9578 var args = Array.prototype.slice.call(arguments, 1);
9579 return function() {
9580 var args2 = args.slice();
9581 args2.push.apply(args2, arguments);
9582 return self.apply(scope, args2);
9583 };
9584 };
9585 }
9586
9587 })(window.Platform);
9588
9589 /*
9590 * Copyright 2012 The Polymer Authors. All rights reserved.
9591 * Use of this source code is goverened by a BSD-style
9592 * license that can be found in the LICENSE file.
9593 */
9594
9595 (function(global) {
9596
9597 var registrationsTable = new WeakMap();
9598
9599 // We use setImmediate or postMessage for our future callback.
9600 var setImmediate = window.msSetImmediate;
9601
9602 // Use post message to emulate setImmediate.
9603 if (!setImmediate) {
9604 var setImmediateQueue = [];
9605 var sentinel = String(Math.random());
9606 window.addEventListener('message', function(e) {
9607 if (e.data === sentinel) {
9608 var queue = setImmediateQueue;
9609 setImmediateQueue = [];
9610 queue.forEach(function(func) {
9611 func();
9612 });
9613 }
9614 });
9615 setImmediate = function(func) {
9616 setImmediateQueue.push(func);
9617 window.postMessage(sentinel, '*');
9618 };
9619 }
9620
9621 // This is used to ensure that we never schedule 2 callas to setImmediate
9622 var isScheduled = false;
9623
9624 // Keep track of observers that needs to be notified next time.
9625 var scheduledObservers = [];
9626
9627 /**
9628 * Schedules |dispatchCallback| to be called in the future.
9629 * @param {MutationObserver} observer
9630 */
9631 function scheduleCallback(observer) {
9632 scheduledObservers.push(observer);
9633 if (!isScheduled) {
9634 isScheduled = true;
9635 setImmediate(dispatchCallbacks);
9636 }
9637 }
9638
9639 function wrapIfNeeded(node) {
9640 return window.ShadowDOMPolyfill &&
9641 window.ShadowDOMPolyfill.wrapIfNeeded(node) ||
9642 node;
9643 }
9644
9645 function dispatchCallbacks() {
9646 // http://dom.spec.whatwg.org/#mutation-observers
9647
9648 isScheduled = false; // Used to allow a new setImmediate call above.
9649
9650 var observers = scheduledObservers;
9651 scheduledObservers = [];
9652 // Sort observers based on their creation UID (incremental).
9653 observers.sort(function(o1, o2) {
9654 return o1.uid_ - o2.uid_;
9655 });
9656
9657 var anyNonEmpty = false;
9658 observers.forEach(function(observer) {
9659
9660 // 2.1, 2.2
9661 var queue = observer.takeRecords();
9662 // 2.3. Remove all transient registered observers whose observer is mo.
9663 removeTransientObserversFor(observer);
9664
9665 // 2.4
9666 if (queue.length) {
9667 observer.callback_(queue, observer);
9668 anyNonEmpty = true;
9669 }
9670 });
9671
9672 // 3.
9673 if (anyNonEmpty)
9674 dispatchCallbacks();
9675 }
9676
9677 function removeTransientObserversFor(observer) {
9678 observer.nodes_.forEach(function(node) {
9679 var registrations = registrationsTable.get(node);
9680 if (!registrations)
9681 return;
9682 registrations.forEach(function(registration) {
9683 if (registration.observer === observer)
9684 registration.removeTransientObservers();
9685 });
9686 });
9687 }
9688
9689 /**
9690 * This function is used for the "For each registered observer observer (with
9691 * observer's options as options) in target's list of registered observers,
9692 * run these substeps:" and the "For each ancestor ancestor of target, and for
9693 * each registered observer observer (with options options) in ancestor's list
9694 * of registered observers, run these substeps:" part of the algorithms. The
9695 * |options.subtree| is checked to ensure that the callback is called
9696 * correctly.
9697 *
9698 * @param {Node} target
9699 * @param {function(MutationObserverInit):MutationRecord} callback
9700 */
9701 function forEachAncestorAndObserverEnqueueRecord(target, callback) {
9702 for (var node = target; node; node = node.parentNode) {
9703 var registrations = registrationsTable.get(node);
9704
9705 if (registrations) {
9706 for (var j = 0; j < registrations.length; j++) {
9707 var registration = registrations[j];
9708 var options = registration.options;
9709
9710 // Only target ignores subtree.
9711 if (node !== target && !options.subtree)
9712 continue;
9713
9714 var record = callback(options);
9715 if (record)
9716 registration.enqueue(record);
9717 }
9718 }
9719 }
9720 }
9721
9722 var uidCounter = 0;
9723
9724 /**
9725 * The class that maps to the DOM MutationObserver interface.
9726 * @param {Function} callback.
9727 * @constructor
9728 */
9729 function JsMutationObserver(callback) {
9730 this.callback_ = callback;
9731 this.nodes_ = [];
9732 this.records_ = [];
9733 this.uid_ = ++uidCounter;
9734 }
9735
9736 JsMutationObserver.prototype = {
9737 observe: function(target, options) {
9738 target = wrapIfNeeded(target);
9739
9740 // 1.1
9741 if (!options.childList && !options.attributes && !options.characterData ||
9742
9743 // 1.2
9744 options.attributeOldValue && !options.attributes ||
9745
9746 // 1.3
9747 options.attributeFilter && options.attributeFilter.length &&
9748 !options.attributes ||
9749
9750 // 1.4
9751 options.characterDataOldValue && !options.characterData) {
9752
9753 throw new SyntaxError();
9754 }
9755
9756 var registrations = registrationsTable.get(target);
9757 if (!registrations)
9758 registrationsTable.set(target, registrations = []);
9759
9760 // 2
9761 // If target's list of registered observers already includes a registered
9762 // observer associated with the context object, replace that registered
9763 // observer's options with options.
9764 var registration;
9765 for (var i = 0; i < registrations.length; i++) {
9766 if (registrations[i].observer === this) {
9767 registration = registrations[i];
9768 registration.removeListeners();
9769 registration.options = options;
9770 break;
9771 }
9772 }
9773
9774 // 3.
9775 // Otherwise, add a new registered observer to target's list of registered
9776 // observers with the context object as the observer and options as the
9777 // options, and add target to context object's list of nodes on which it
9778 // is registered.
9779 if (!registration) {
9780 registration = new Registration(this, target, options);
9781 registrations.push(registration);
9782 this.nodes_.push(target);
9783 }
9784
9785 registration.addListeners();
9786 },
9787
9788 disconnect: function() {
9789 this.nodes_.forEach(function(node) {
9790 var registrations = registrationsTable.get(node);
9791 for (var i = 0; i < registrations.length; i++) {
9792 var registration = registrations[i];
9793 if (registration.observer === this) {
9794 registration.removeListeners();
9795 registrations.splice(i, 1);
9796 // Each node can only have one registered observer associated with
9797 // this observer.
9798 break;
9799 }
9800 }
9801 }, this);
9802 this.records_ = [];
9803 },
9804
9805 takeRecords: function() {
9806 var copyOfRecords = this.records_;
9807 this.records_ = [];
9808 return copyOfRecords;
9809 }
9810 };
9811
9812 /**
9813 * @param {string} type
9814 * @param {Node} target
9815 * @constructor
9816 */
9817 function MutationRecord(type, target) {
9818 this.type = type;
9819 this.target = target;
9820 this.addedNodes = [];
9821 this.removedNodes = [];
9822 this.previousSibling = null;
9823 this.nextSibling = null;
9824 this.attributeName = null;
9825 this.attributeNamespace = null;
9826 this.oldValue = null;
9827 }
9828
9829 function copyMutationRecord(original) {
9830 var record = new MutationRecord(original.type, original.target);
9831 record.addedNodes = original.addedNodes.slice();
9832 record.removedNodes = original.removedNodes.slice();
9833 record.previousSibling = original.previousSibling;
9834 record.nextSibling = original.nextSibling;
9835 record.attributeName = original.attributeName;
9836 record.attributeNamespace = original.attributeNamespace;
9837 record.oldValue = original.oldValue;
9838 return record;
9839 };
9840
9841 // We keep track of the two (possibly one) records used in a single mutation.
9842 var currentRecord, recordWithOldValue;
9843
9844 /**
9845 * Creates a record without |oldValue| and caches it as |currentRecord| for
9846 * later use.
9847 * @param {string} oldValue
9848 * @return {MutationRecord}
9849 */
9850 function getRecord(type, target) {
9851 return currentRecord = new MutationRecord(type, target);
9852 }
9853
9854 /**
9855 * Gets or creates a record with |oldValue| based in the |currentRecord|
9856 * @param {string} oldValue
9857 * @return {MutationRecord}
9858 */
9859 function getRecordWithOldValue(oldValue) {
9860 if (recordWithOldValue)
9861 return recordWithOldValue;
9862 recordWithOldValue = copyMutationRecord(currentRecord);
9863 recordWithOldValue.oldValue = oldValue;
9864 return recordWithOldValue;
9865 }
9866
9867 function clearRecords() {
9868 currentRecord = recordWithOldValue = undefined;
9869 }
9870
9871 /**
9872 * @param {MutationRecord} record
9873 * @return {boolean} Whether the record represents a record from the current
9874 * mutation event.
9875 */
9876 function recordRepresentsCurrentMutation(record) {
9877 return record === recordWithOldValue || record === currentRecord;
9878 }
9879
9880 /**
9881 * Selects which record, if any, to replace the last record in the queue.
9882 * This returns |null| if no record should be replaced.
9883 *
9884 * @param {MutationRecord} lastRecord
9885 * @param {MutationRecord} newRecord
9886 * @param {MutationRecord}
9887 */
9888 function selectRecord(lastRecord, newRecord) {
9889 if (lastRecord === newRecord)
9890 return lastRecord;
9891
9892 // Check if the the record we are adding represents the same record. If
9893 // so, we keep the one with the oldValue in it.
9894 if (recordWithOldValue && recordRepresentsCurrentMutation(lastRecord))
9895 return recordWithOldValue;
9896
9897 return null;
9898 }
9899
9900 /**
9901 * Class used to represent a registered observer.
9902 * @param {MutationObserver} observer
9903 * @param {Node} target
9904 * @param {MutationObserverInit} options
9905 * @constructor
9906 */
9907 function Registration(observer, target, options) {
9908 this.observer = observer;
9909 this.target = target;
9910 this.options = options;
9911 this.transientObservedNodes = [];
9912 }
9913
9914 Registration.prototype = {
9915 enqueue: function(record) {
9916 var records = this.observer.records_;
9917 var length = records.length;
9918
9919 // There are cases where we replace the last record with the new record.
9920 // For example if the record represents the same mutation we need to use
9921 // the one with the oldValue. If we get same record (this can happen as we
9922 // walk up the tree) we ignore the new record.
9923 if (records.length > 0) {
9924 var lastRecord = records[length - 1];
9925 var recordToReplaceLast = selectRecord(lastRecord, record);
9926 if (recordToReplaceLast) {
9927 records[length - 1] = recordToReplaceLast;
9928 return;
9929 }
9930 } else {
9931 scheduleCallback(this.observer);
9932 }
9933
9934 records[length] = record;
9935 },
9936
9937 addListeners: function() {
9938 this.addListeners_(this.target);
9939 },
9940
9941 addListeners_: function(node) {
9942 var options = this.options;
9943 if (options.attributes)
9944 node.addEventListener('DOMAttrModified', this, true);
9945
9946 if (options.characterData)
9947 node.addEventListener('DOMCharacterDataModified', this, true);
9948
9949 if (options.childList)
9950 node.addEventListener('DOMNodeInserted', this, true);
9951
9952 if (options.childList || options.subtree)
9953 node.addEventListener('DOMNodeRemoved', this, true);
9954 },
9955
9956 removeListeners: function() {
9957 this.removeListeners_(this.target);
9958 },
9959
9960 removeListeners_: function(node) {
9961 var options = this.options;
9962 if (options.attributes)
9963 node.removeEventListener('DOMAttrModified', this, true);
9964
9965 if (options.characterData)
9966 node.removeEventListener('DOMCharacterDataModified', this, true);
9967
9968 if (options.childList)
9969 node.removeEventListener('DOMNodeInserted', this, true);
9970
9971 if (options.childList || options.subtree)
9972 node.removeEventListener('DOMNodeRemoved', this, true);
9973 },
9974
9975 /**
9976 * Adds a transient observer on node. The transient observer gets removed
9977 * next time we deliver the change records.
9978 * @param {Node} node
9979 */
9980 addTransientObserver: function(node) {
9981 // Don't add transient observers on the target itself. We already have all
9982 // the required listeners set up on the target.
9983 if (node === this.target)
9984 return;
9985
9986 this.addListeners_(node);
9987 this.transientObservedNodes.push(node);
9988 var registrations = registrationsTable.get(node);
9989 if (!registrations)
9990 registrationsTable.set(node, registrations = []);
9991
9992 // We know that registrations does not contain this because we already
9993 // checked if node === this.target.
9994 registrations.push(this);
9995 },
9996
9997 removeTransientObservers: function() {
9998 var transientObservedNodes = this.transientObservedNodes;
9999 this.transientObservedNodes = [];
10000
10001 transientObservedNodes.forEach(function(node) {
10002 // Transient observers are never added to the target.
10003 this.removeListeners_(node);
10004
10005 var registrations = registrationsTable.get(node);
10006 for (var i = 0; i < registrations.length; i++) {
10007 if (registrations[i] === this) {
10008 registrations.splice(i, 1);
10009 // Each node can only have one registered observer associated with
10010 // this observer.
10011 break;
10012 }
10013 }
10014 }, this);
10015 },
10016
10017 handleEvent: function(e) {
10018 // Stop propagation since we are managing the propagation manually.
10019 // This means that other mutation events on the page will not work
10020 // correctly but that is by design.
10021 e.stopImmediatePropagation();
10022
10023 switch (e.type) {
10024 case 'DOMAttrModified':
10025 // http://dom.spec.whatwg.org/#concept-mo-queue-attributes
10026
10027 var name = e.attrName;
10028 var namespace = e.relatedNode.namespaceURI;
10029 var target = e.target;
10030
10031 // 1.
10032 var record = new getRecord('attributes', target);
10033 record.attributeName = name;
10034 record.attributeNamespace = namespace;
10035
10036 // 2.
10037 var oldValue =
10038 e.attrChange === MutationEvent.ADDITION ? null : e.prevValue;
10039
10040 forEachAncestorAndObserverEnqueueRecord(target, function(options) {
10041 // 3.1, 4.2
10042 if (!options.attributes)
10043 return;
10044
10045 // 3.2, 4.3
10046 if (options.attributeFilter && options.attributeFilter.length &&
10047 options.attributeFilter.indexOf(name) === -1 &&
10048 options.attributeFilter.indexOf(namespace) === -1) {
10049 return;
10050 }
10051 // 3.3, 4.4
10052 if (options.attributeOldValue)
10053 return getRecordWithOldValue(oldValue);
10054
10055 // 3.4, 4.5
10056 return record;
10057 });
10058
10059 break;
10060
10061 case 'DOMCharacterDataModified':
10062 // http://dom.spec.whatwg.org/#concept-mo-queue-characterdata
10063 var target = e.target;
10064
10065 // 1.
10066 var record = getRecord('characterData', target);
10067
10068 // 2.
10069 var oldValue = e.prevValue;
10070
10071
10072 forEachAncestorAndObserverEnqueueRecord(target, function(options) {
10073 // 3.1, 4.2
10074 if (!options.characterData)
10075 return;
10076
10077 // 3.2, 4.3
10078 if (options.characterDataOldValue)
10079 return getRecordWithOldValue(oldValue);
10080
10081 // 3.3, 4.4
10082 return record;
10083 });
10084
10085 break;
10086
10087 case 'DOMNodeRemoved':
10088 this.addTransientObserver(e.target);
10089 // Fall through.
10090 case 'DOMNodeInserted':
10091 // http://dom.spec.whatwg.org/#concept-mo-queue-childlist
10092 var target = e.relatedNode;
10093 var changedNode = e.target;
10094 var addedNodes, removedNodes;
10095 if (e.type === 'DOMNodeInserted') {
10096 addedNodes = [changedNode];
10097 removedNodes = [];
10098 } else {
10099
10100 addedNodes = [];
10101 removedNodes = [changedNode];
10102 }
10103 var previousSibling = changedNode.previousSibling;
10104 var nextSibling = changedNode.nextSibling;
10105
10106 // 1.
10107 var record = getRecord('childList', target);
10108 record.addedNodes = addedNodes;
10109 record.removedNodes = removedNodes;
10110 record.previousSibling = previousSibling;
10111 record.nextSibling = nextSibling;
10112
10113 forEachAncestorAndObserverEnqueueRecord(target, function(options) {
10114 // 2.1, 3.2
10115 if (!options.childList)
10116 return;
10117
10118 // 2.2, 3.3
10119 return record;
10120 });
10121
10122 }
10123
10124 clearRecords();
10125 }
10126 };
10127
10128 global.JsMutationObserver = JsMutationObserver;
10129
10130 if (!global.MutationObserver)
10131 global.MutationObserver = JsMutationObserver;
10132
10133
10134 })(this);
10135
10136 /*
10137 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
10138 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
10139 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
10140 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
10141 * Code distributed by Google as part of the polymer project is also
10142 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
10143 */
10144 window.HTMLImports = window.HTMLImports || {flags:{}};
10145 /*
10146 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
10147 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
10148 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
10149 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
10150 * Code distributed by Google as part of the polymer project is also
10151 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
10152 */
10153
10154 (function(scope) {
10155
10156 var IMPORT_LINK_TYPE = 'import';
10157 var hasNative = (IMPORT_LINK_TYPE in document.createElement('link'));
10158 var useNative = hasNative;
10159 var isIE = /Trident/.test(navigator.userAgent);
10160
10161 // TODO(sorvell): SD polyfill intrusion
10162 var hasShadowDOMPolyfill = Boolean(window.ShadowDOMPolyfill);
10163 var wrap = function(node) {
10164 return hasShadowDOMPolyfill ? ShadowDOMPolyfill.wrapIfNeeded(node) : node;
10165 };
10166
10167 var rootDocument = wrap(document);
10168
10169 // NOTE: We cannot polyfill document.currentScript because it's not possible
10170 // both to override and maintain the ability to capture the native value;
10171 // therefore we choose to expose _currentScript both when native imports
10172 // and the polyfill are in use.
10173 var currentScriptDescriptor = {
10174 get: function() {
10175 var script = HTMLImports.currentScript || document.currentScript ||
10176 // NOTE: only works when called in synchronously executing code.
10177 // readyState should check if `loading` but IE10 is
10178 // interactive when scripts run so we cheat.
10179 (document.readyState !== 'complete' ?
10180 document.scripts[document.scripts.length - 1] : null);
10181 return wrap(script);
10182 },
10183 configurable: true
10184 };
10185
10186 Object.defineProperty(document, '_currentScript', currentScriptDescriptor);
10187 Object.defineProperty(rootDocument, '_currentScript', currentScriptDescriptor);
10188
10189 // call a callback when all HTMLImports in the document at call (or at least
10190 // document ready) time have loaded.
10191 // 1. ensure the document is in a ready state (has dom), then
10192 // 2. watch for loading of imports and call callback when done
10193 function whenReady(callback, doc) {
10194 doc = doc || rootDocument;
10195 // if document is loading, wait and try again
10196 whenDocumentReady(function() {
10197 watchImportsLoad(callback, doc);
10198 }, doc);
10199 }
10200
10201 // call the callback when the document is in a ready state (has dom)
10202 var requiredReadyState = isIE ? 'complete' : 'interactive';
10203 var READY_EVENT = 'readystatechange';
10204 function isDocumentReady(doc) {
10205 return (doc.readyState === 'complete' ||
10206 doc.readyState === requiredReadyState);
10207 }
10208
10209 // call <callback> when we ensure the document is in a ready state
10210 function whenDocumentReady(callback, doc) {
10211 if (!isDocumentReady(doc)) {
10212 var checkReady = function() {
10213 if (doc.readyState === 'complete' ||
10214 doc.readyState === requiredReadyState) {
10215 doc.removeEventListener(READY_EVENT, checkReady);
10216 whenDocumentReady(callback, doc);
10217 }
10218 };
10219 doc.addEventListener(READY_EVENT, checkReady);
10220 } else if (callback) {
10221 callback();
10222 }
10223 }
10224
10225 function markTargetLoaded(event) {
10226 event.target.__loaded = true;
10227 }
10228
10229 // call <callback> when we ensure all imports have loaded
10230 function watchImportsLoad(callback, doc) {
10231 var imports = doc.querySelectorAll('link[rel=import]');
10232 var loaded = 0, l = imports.length;
10233 function checkDone(d) {
10234 if ((loaded == l) && callback) {
10235 callback();
10236 }
10237 }
10238 function loadedImport(e) {
10239 markTargetLoaded(e);
10240 loaded++;
10241 checkDone();
10242 }
10243 if (l) {
10244 for (var i=0, imp; (i<l) && (imp=imports[i]); i++) {
10245 if (isImportLoaded(imp)) {
10246 loadedImport.call(imp, {target: imp});
10247 } else {
10248 imp.addEventListener('load', loadedImport);
10249 imp.addEventListener('error', loadedImport);
10250 }
10251 }
10252 } else {
10253 checkDone();
10254 }
10255 }
10256
10257 // NOTE: test for native imports loading is based on explicitly watching
10258 // all imports (see below).
10259 // We cannot rely on this entirely without watching the entire document
10260 // for import links. For perf reasons, currently only head is watched.
10261 // Instead, we fallback to checking if the import property is available
10262 // and the document is not itself loading.
10263 function isImportLoaded(link) {
10264 return useNative ? link.__loaded ||
10265 (link.import && link.import.readyState !== 'loading') :
10266 link.__importParsed;
10267 }
10268
10269 // TODO(sorvell): Workaround for
10270 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=25007, should be removed when
10271 // this bug is addressed.
10272 // (1) Install a mutation observer to see when HTMLImports have loaded
10273 // (2) if this script is run during document load it will watch any existing
10274 // imports for loading.
10275 //
10276 // NOTE: The workaround has restricted functionality: (1) it's only compatible
10277 // with imports that are added to document.head since the mutation observer
10278 // watches only head for perf reasons, (2) it requires this script
10279 // to run before any imports have completed loading.
10280 if (useNative) {
10281 new MutationObserver(function(mxns) {
10282 for (var i=0, l=mxns.length, m; (i < l) && (m=mxns[i]); i++) {
10283 if (m.addedNodes) {
10284 handleImports(m.addedNodes);
10285 }
10286 }
10287 }).observe(document.head, {childList: true});
10288
10289 function handleImports(nodes) {
10290 for (var i=0, l=nodes.length, n; (i<l) && (n=nodes[i]); i++) {
10291 if (isImport(n)) {
10292 handleImport(n);
10293 }
10294 }
10295 }
10296
10297 function isImport(element) {
10298 return element.localName === 'link' && element.rel === 'import';
10299 }
10300
10301 function handleImport(element) {
10302 var loaded = element.import;
10303 if (loaded) {
10304 markTargetLoaded({target: element});
10305 } else {
10306 element.addEventListener('load', markTargetLoaded);
10307 element.addEventListener('error', markTargetLoaded);
10308 }
10309 }
10310
10311 // make sure to catch any imports that are in the process of loading
10312 // when this script is run.
10313 (function() {
10314 if (document.readyState === 'loading') {
10315 var imports = document.querySelectorAll('link[rel=import]');
10316 for (var i=0, l=imports.length, imp; (i<l) && (imp=imports[i]); i++) {
10317 handleImport(imp);
10318 }
10319 }
10320 })();
10321
10322 }
10323
10324 // Fire the 'HTMLImportsLoaded' event when imports in document at load time
10325 // have loaded. This event is required to simulate the script blocking
10326 // behavior of native imports. A main document script that needs to be sure
10327 // imports have loaded should wait for this event.
10328 whenReady(function() {
10329 HTMLImports.ready = true;
10330 HTMLImports.readyTime = new Date().getTime();
10331 rootDocument.dispatchEvent(
10332 new CustomEvent('HTMLImportsLoaded', {bubbles: true})
10333 );
10334 });
10335
10336 // exports
10337 scope.useNative = useNative;
10338 scope.isImportLoaded = isImportLoaded;
10339 scope.whenReady = whenReady;
10340 scope.rootDocument = rootDocument;
10341 scope.IMPORT_LINK_TYPE = IMPORT_LINK_TYPE;
10342 scope.isIE = isIE;
10343
10344 })(window.HTMLImports);
10345 /*
10346 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
10347 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
10348 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
10349 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
10350 * Code distributed by Google as part of the polymer project is also
10351 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
10352 */
10353 (function(scope) {
10354
10355 // imports
10356 var path = scope.path;
10357 var xhr = scope.xhr;
10358 var flags = scope.flags;
10359
10360 // TODO(sorvell): this loader supports a dynamic list of urls
10361 // and an oncomplete callback that is called when the loader is done.
10362 // The polyfill currently does *not* need this dynamism or the onComplete
10363 // concept. Because of this, the loader could be simplified quite a bit.
10364 var Loader = function(onLoad, onComplete) {
10365 this.cache = {};
10366 this.onload = onLoad;
10367 this.oncomplete = onComplete;
10368 this.inflight = 0;
10369 this.pending = {};
10370 };
10371
10372 Loader.prototype = {
10373
10374 addNodes: function(nodes) {
10375 // number of transactions to complete
10376 this.inflight += nodes.length;
10377 // commence transactions
10378 for (var i=0, l=nodes.length, n; (i<l) && (n=nodes[i]); i++) {
10379 this.require(n);
10380 }
10381 // anything to do?
10382 this.checkDone();
10383 },
10384
10385 addNode: function(node) {
10386 // number of transactions to complete
10387 this.inflight++;
10388 // commence transactions
10389 this.require(node);
10390 // anything to do?
10391 this.checkDone();
10392 },
10393
10394 require: function(elt) {
10395 var url = elt.src || elt.href;
10396 // ensure we have a standard url that can be used
10397 // reliably for deduping.
10398 // TODO(sjmiles): ad-hoc
10399 elt.__nodeUrl = url;
10400 // deduplication
10401 if (!this.dedupe(url, elt)) {
10402 // fetch this resource
10403 this.fetch(url, elt);
10404 }
10405 },
10406
10407 dedupe: function(url, elt) {
10408 if (this.pending[url]) {
10409 // add to list of nodes waiting for inUrl
10410 this.pending[url].push(elt);
10411 // don't need fetch
10412 return true;
10413 }
10414 var resource;
10415 if (this.cache[url]) {
10416 this.onload(url, elt, this.cache[url]);
10417 // finished this transaction
10418 this.tail();
10419 // don't need fetch
10420 return true;
10421 }
10422 // first node waiting for inUrl
10423 this.pending[url] = [elt];
10424 // need fetch (not a dupe)
10425 return false;
10426 },
10427
10428 fetch: function(url, elt) {
10429 flags.load && console.log('fetch', url, elt);
10430 if (url.match(/^data:/)) {
10431 // Handle Data URI Scheme
10432 var pieces = url.split(',');
10433 var header = pieces[0];
10434 var body = pieces[1];
10435 if(header.indexOf(';base64') > -1) {
10436 body = atob(body);
10437 } else {
10438 body = decodeURIComponent(body);
10439 }
10440 setTimeout(function() {
10441 this.receive(url, elt, null, body);
10442 }.bind(this), 0);
10443 } else {
10444 var receiveXhr = function(err, resource, redirectedUrl) {
10445 this.receive(url, elt, err, resource, redirectedUrl);
10446 }.bind(this);
10447 xhr.load(url, receiveXhr);
10448 // TODO(sorvell): blocked on)
10449 // https://code.google.com/p/chromium/issues/detail?id=257221
10450 // xhr'ing for a document makes scripts in imports runnable; otherwise
10451 // they are not; however, it requires that we have doctype=html in
10452 // the import which is unacceptable. This is only needed on Chrome
10453 // to avoid the bug above.
10454 /*
10455 if (isDocumentLink(elt)) {
10456 xhr.loadDocument(url, receiveXhr);
10457 } else {
10458 xhr.load(url, receiveXhr);
10459 }
10460 */
10461 }
10462 },
10463
10464 receive: function(url, elt, err, resource, redirectedUrl) {
10465 this.cache[url] = resource;
10466 var $p = this.pending[url];
10467 for (var i=0, l=$p.length, p; (i<l) && (p=$p[i]); i++) {
10468 // If url was redirected, use the redirected location so paths are
10469 // calculated relative to that.
10470 this.onload(url, p, resource, err, redirectedUrl);
10471 this.tail();
10472 }
10473 this.pending[url] = null;
10474 },
10475
10476 tail: function() {
10477 --this.inflight;
10478 this.checkDone();
10479 },
10480
10481 checkDone: function() {
10482 if (!this.inflight) {
10483 this.oncomplete();
10484 }
10485 }
10486
10487 };
10488
10489 xhr = xhr || {
10490 async: true,
10491
10492 ok: function(request) {
10493 return (request.status >= 200 && request.status < 300)
10494 || (request.status === 304)
10495 || (request.status === 0);
10496 },
10497
10498 load: function(url, next, nextContext) {
10499 var request = new XMLHttpRequest();
10500 if (scope.flags.debug || scope.flags.bust) {
10501 url += '?' + Math.random();
10502 }
10503 request.open('GET', url, xhr.async);
10504 request.addEventListener('readystatechange', function(e) {
10505 if (request.readyState === 4) {
10506 // Servers redirecting an import can add a Location header to help us
10507 // polyfill correctly.
10508 var locationHeader = request.getResponseHeader("Location");
10509 var redirectedUrl = null;
10510 if (locationHeader) {
10511 var redirectedUrl = (locationHeader.substr( 0, 1 ) === "/")
10512 ? location.origin + locationHeader // Location is a relative path
10513 : locationHeader; // Full path
10514 }
10515 next.call(nextContext, !xhr.ok(request) && request,
10516 request.response || request.responseText, redirectedUrl);
10517 }
10518 });
10519 request.send();
10520 return request;
10521 },
10522
10523 loadDocument: function(url, next, nextContext) {
10524 this.load(url, next, nextContext).responseType = 'document';
10525 }
10526
10527 };
10528
10529 // exports
10530 scope.xhr = xhr;
10531 scope.Loader = Loader;
10532
10533 })(window.HTMLImports);
10534
10535 /*
10536 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
10537 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
10538 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
10539 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
10540 * Code distributed by Google as part of the polymer project is also
10541 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
10542 */
10543 (function(scope) {
10544
10545 // imports
10546 var rootDocument = scope.rootDocument;
10547 var flags = scope.flags;
10548 var isIE = scope.isIE;
10549 var IMPORT_LINK_TYPE = scope.IMPORT_LINK_TYPE;
10550
10551 // importParser
10552 // highlander object to manage parsing of imports
10553 // parses import related elements
10554 // and ensures proper parse order
10555 // parse order is enforced by crawling the tree and monitoring which elements
10556 // have been parsed; async parsing is also supported.
10557
10558 // highlander object for parsing a document tree
10559 var importParser = {
10560
10561 // parse selectors for main document elements
10562 documentSelectors: 'link[rel=' + IMPORT_LINK_TYPE + ']',
10563
10564 // parse selectors for import document elements
10565 importsSelectors: [
10566 'link[rel=' + IMPORT_LINK_TYPE + ']',
10567 'link[rel=stylesheet]',
10568 'style',
10569 'script:not([type])',
10570 'script[type="text/javascript"]'
10571 ].join(','),
10572
10573 map: {
10574 link: 'parseLink',
10575 script: 'parseScript',
10576 style: 'parseStyle'
10577 },
10578
10579 dynamicElements: [],
10580
10581 // try to parse the next import in the tree
10582 parseNext: function() {
10583 var next = this.nextToParse();
10584 if (next) {
10585 this.parse(next);
10586 }
10587 },
10588
10589 parse: function(elt) {
10590 if (this.isParsed(elt)) {
10591 flags.parse && console.log('[%s] is already parsed', elt.localName);
10592 return;
10593 }
10594 var fn = this[this.map[elt.localName]];
10595 if (fn) {
10596 this.markParsing(elt);
10597 fn.call(this, elt);
10598 }
10599 },
10600
10601 parseDynamic: function(elt, quiet) {
10602 this.dynamicElements.push(elt);
10603 if (!quiet) {
10604 this.parseNext();
10605 }
10606 },
10607
10608 // only 1 element may be parsed at a time; parsing is async so each
10609 // parsing implementation must inform the system that parsing is complete
10610 // via markParsingComplete.
10611 // To prompt the system to parse the next element, parseNext should then be
10612 // called.
10613 // Note, parseNext used to be included at the end of markParsingComplete, but
10614 // we must not do this so that, for example, we can (1) mark parsing complete
10615 // then (2) fire an import load event, and then (3) parse the next resource.
10616 markParsing: function(elt) {
10617 flags.parse && console.log('parsing', elt);
10618 this.parsingElement = elt;
10619 },
10620
10621 markParsingComplete: function(elt) {
10622 elt.__importParsed = true;
10623 this.markDynamicParsingComplete(elt);
10624 if (elt.__importElement) {
10625 elt.__importElement.__importParsed = true;
10626 this.markDynamicParsingComplete(elt.__importElement);
10627 }
10628 this.parsingElement = null;
10629 flags.parse && console.log('completed', elt);
10630 },
10631
10632 markDynamicParsingComplete: function(elt) {
10633 var i = this.dynamicElements.indexOf(elt);
10634 if (i >= 0) {
10635 this.dynamicElements.splice(i, 1);
10636 }
10637 },
10638
10639 parseImport: function(elt) {
10640 // TODO(sorvell): consider if there's a better way to do this;
10641 // expose an imports parsing hook; this is needed, for example, by the
10642 // CustomElements polyfill.
10643 if (HTMLImports.__importsParsingHook) {
10644 HTMLImports.__importsParsingHook(elt);
10645 }
10646 if (elt.import) {
10647 elt.import.__importParsed = true;
10648 }
10649 this.markParsingComplete(elt);
10650 // fire load event
10651 if (elt.__resource && !elt.__error) {
10652 elt.dispatchEvent(new CustomEvent('load', {bubbles: false}));
10653 } else {
10654 elt.dispatchEvent(new CustomEvent('error', {bubbles: false}));
10655 }
10656 // TODO(sorvell): workaround for Safari addEventListener not working
10657 // for elements not in the main document.
10658 if (elt.__pending) {
10659 var fn;
10660 while (elt.__pending.length) {
10661 fn = elt.__pending.shift();
10662 if (fn) {
10663 fn({target: elt});
10664 }
10665 }
10666 }
10667 this.parseNext();
10668 },
10669
10670 parseLink: function(linkElt) {
10671 if (nodeIsImport(linkElt)) {
10672 this.parseImport(linkElt);
10673 } else {
10674 // make href absolute
10675 linkElt.href = linkElt.href;
10676 this.parseGeneric(linkElt);
10677 }
10678 },
10679
10680 parseStyle: function(elt) {
10681 // TODO(sorvell): style element load event can just not fire so clone styles
10682 var src = elt;
10683 elt = cloneStyle(elt);
10684 elt.__importElement = src;
10685 this.parseGeneric(elt);
10686 },
10687
10688 parseGeneric: function(elt) {
10689 this.trackElement(elt);
10690 this.addElementToDocument(elt);
10691 },
10692
10693 rootImportForElement: function(elt) {
10694 var n = elt;
10695 while (n.ownerDocument.__importLink) {
10696 n = n.ownerDocument.__importLink;
10697 }
10698 return n;
10699 },
10700
10701 addElementToDocument: function(elt) {
10702 var port = this.rootImportForElement(elt.__importElement || elt);
10703 var l = port.__insertedElements = port.__insertedElements || 0;
10704 var refNode = port.nextElementSibling;
10705 for (var i=0; i < l; i++) {
10706 refNode = refNode && refNode.nextElementSibling;
10707 }
10708 port.parentNode.insertBefore(elt, refNode);
10709 },
10710
10711 // tracks when a loadable element has loaded
10712 trackElement: function(elt, callback) {
10713 var self = this;
10714 var done = function(e) {
10715 if (callback) {
10716 callback(e);
10717 }
10718 self.markParsingComplete(elt);
10719 self.parseNext();
10720 };
10721 elt.addEventListener('load', done);
10722 elt.addEventListener('error', done);
10723
10724 // NOTE: IE does not fire "load" event for styles that have already loaded
10725 // This is in violation of the spec, so we try our hardest to work around it
10726 if (isIE && elt.localName === 'style') {
10727 var fakeLoad = false;
10728 // If there's not @import in the textContent, assume it has loaded
10729 if (elt.textContent.indexOf('@import') == -1) {
10730 fakeLoad = true;
10731 // if we have a sheet, we have been parsed
10732 } else if (elt.sheet) {
10733 fakeLoad = true;
10734 var csr = elt.sheet.cssRules;
10735 var len = csr ? csr.length : 0;
10736 // search the rules for @import's
10737 for (var i = 0, r; (i < len) && (r = csr[i]); i++) {
10738 if (r.type === CSSRule.IMPORT_RULE) {
10739 // if every @import has resolved, fake the load
10740 fakeLoad = fakeLoad && Boolean(r.styleSheet);
10741 }
10742 }
10743 }
10744 // dispatch a fake load event and continue parsing
10745 if (fakeLoad) {
10746 elt.dispatchEvent(new CustomEvent('load', {bubbles: false}));
10747 }
10748 }
10749 },
10750
10751 // NOTE: execute scripts by injecting them and watching for the load/error
10752 // event. Inline scripts are handled via dataURL's because browsers tend to
10753 // provide correct parsing errors in this case. If this has any compatibility
10754 // issues, we can switch to injecting the inline script with textContent.
10755 // Scripts with dataURL's do not appear to generate load events and therefore
10756 // we assume they execute synchronously.
10757 parseScript: function(scriptElt) {
10758 var script = document.createElement('script');
10759 script.__importElement = scriptElt;
10760 script.src = scriptElt.src ? scriptElt.src :
10761 generateScriptDataUrl(scriptElt);
10762 scope.currentScript = scriptElt;
10763 this.trackElement(script, function(e) {
10764 script.parentNode.removeChild(script);
10765 scope.currentScript = null;
10766 });
10767 this.addElementToDocument(script);
10768 },
10769
10770 // determine the next element in the tree which should be parsed
10771 nextToParse: function() {
10772 this._mayParse = [];
10773 return !this.parsingElement && (this.nextToParseInDoc(rootDocument) ||
10774 this.nextToParseDynamic());
10775 },
10776
10777 nextToParseInDoc: function(doc, link) {
10778 // use `marParse` list to avoid looping into the same document again
10779 // since it could cause an iloop.
10780 if (doc && this._mayParse.indexOf(doc) < 0) {
10781 this._mayParse.push(doc);
10782 var nodes = doc.querySelectorAll(this.parseSelectorsForNode(doc));
10783 for (var i=0, l=nodes.length, p=0, n; (i<l) && (n=nodes[i]); i++) {
10784 if (!this.isParsed(n)) {
10785 if (this.hasResource(n)) {
10786 return nodeIsImport(n) ? this.nextToParseInDoc(n.import, n) : n;
10787 } else {
10788 return;
10789 }
10790 }
10791 }
10792 }
10793 // all nodes have been parsed, ready to parse import, if any
10794 return link;
10795 },
10796
10797 nextToParseDynamic: function() {
10798 return this.dynamicElements[0];
10799 },
10800
10801 // return the set of parse selectors relevant for this node.
10802 parseSelectorsForNode: function(node) {
10803 var doc = node.ownerDocument || node;
10804 return doc === rootDocument ? this.documentSelectors :
10805 this.importsSelectors;
10806 },
10807
10808 isParsed: function(node) {
10809 return node.__importParsed;
10810 },
10811
10812 needsDynamicParsing: function(elt) {
10813 return (this.dynamicElements.indexOf(elt) >= 0);
10814 },
10815
10816 hasResource: function(node) {
10817 if (nodeIsImport(node) && (node.import === undefined)) {
10818 return false;
10819 }
10820 return true;
10821 }
10822
10823 };
10824
10825 function nodeIsImport(elt) {
10826 return (elt.localName === 'link') && (elt.rel === IMPORT_LINK_TYPE);
10827 }
10828
10829 function generateScriptDataUrl(script) {
10830 var scriptContent = generateScriptContent(script);
10831 return 'data:text/javascript;charset=utf-8,' + encodeURIComponent(scriptConten t);
10832 }
10833
10834 function generateScriptContent(script) {
10835 return script.textContent + generateSourceMapHint(script);
10836 }
10837
10838 // calculate source map hint
10839 function generateSourceMapHint(script) {
10840 var moniker = script.__nodeUrl;
10841 if (!moniker) {
10842 moniker = script.ownerDocument.baseURI;
10843 // there could be more than one script this url
10844 var tag = '[' + Math.floor((Math.random()+1)*1000) + ']';
10845 // TODO(sjmiles): Polymer hack, should be pluggable if we need to allow
10846 // this sort of thing
10847 var matches = script.textContent.match(/Polymer\(['"]([^'"]*)/);
10848 tag = matches && matches[1] || tag;
10849 // tag the moniker
10850 moniker += '/' + tag + '.js';
10851 }
10852 return '\n//# sourceURL=' + moniker + '\n';
10853 }
10854
10855 // style/stylesheet handling
10856
10857 // clone style with proper path resolution for main document
10858 // NOTE: styles are the only elements that require direct path fixup.
10859 function cloneStyle(style) {
10860 var clone = style.ownerDocument.createElement('style');
10861 clone.textContent = style.textContent;
10862 path.resolveUrlsInStyle(clone);
10863 return clone;
10864 }
10865
10866 // path fixup: style elements in imports must be made relative to the main
10867 // document. We fixup url's in url() and @import.
10868 var CSS_URL_REGEXP = /(url\()([^)]*)(\))/g;
10869 var CSS_IMPORT_REGEXP = /(@import[\s]+(?!url\())([^;]*)(;)/g;
10870
10871 var path = {
10872
10873 resolveUrlsInStyle: function(style) {
10874 var doc = style.ownerDocument;
10875 var resolver = doc.createElement('a');
10876 style.textContent = this.resolveUrlsInCssText(style.textContent, resolver);
10877 return style;
10878 },
10879
10880 resolveUrlsInCssText: function(cssText, urlObj) {
10881 var r = this.replaceUrls(cssText, urlObj, CSS_URL_REGEXP);
10882 r = this.replaceUrls(r, urlObj, CSS_IMPORT_REGEXP);
10883 return r;
10884 },
10885
10886 replaceUrls: function(text, urlObj, regexp) {
10887 return text.replace(regexp, function(m, pre, url, post) {
10888 var urlPath = url.replace(/["']/g, '');
10889 urlObj.href = urlPath;
10890 urlPath = urlObj.href;
10891 return pre + '\'' + urlPath + '\'' + post;
10892 });
10893 }
10894
10895 };
10896
10897 // exports
10898 scope.parser = importParser;
10899 scope.path = path;
10900
10901 })(HTMLImports);
10902
10903 /*
10904 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
10905 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
10906 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
10907 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
10908 * Code distributed by Google as part of the polymer project is also
10909 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
10910 */
10911 (function(scope) {
10912
10913 // imports
10914 var useNative = scope.useNative;
10915 var flags = scope.flags;
10916 var IMPORT_LINK_TYPE = scope.IMPORT_LINK_TYPE;
10917
10918 if (!useNative) {
10919
10920 // imports
10921 var rootDocument = scope.rootDocument;
10922 var xhr = scope.xhr;
10923 var Loader = scope.Loader;
10924 var parser = scope.parser;
10925
10926 // importer
10927 // highlander object to manage loading of imports
10928
10929 // for any document, importer:
10930 // - loads any linked import documents (with deduping)
10931
10932 var importer = {
10933
10934 documents: {},
10935
10936 // nodes to load in the mian document
10937 documentPreloadSelectors: 'link[rel=' + IMPORT_LINK_TYPE + ']',
10938
10939 // nodes to load in imports
10940 importsPreloadSelectors: [
10941 'link[rel=' + IMPORT_LINK_TYPE + ']'
10942 ].join(','),
10943
10944 loadNode: function(node) {
10945 importLoader.addNode(node);
10946 },
10947
10948 // load all loadable elements within the parent element
10949 loadSubtree: function(parent) {
10950 var nodes = this.marshalNodes(parent);
10951 // add these nodes to loader's queue
10952 importLoader.addNodes(nodes);
10953 },
10954
10955 marshalNodes: function(parent) {
10956 // all preloadable nodes in inDocument
10957 return parent.querySelectorAll(this.loadSelectorsForNode(parent));
10958 },
10959
10960 // find the proper set of load selectors for a given node
10961 loadSelectorsForNode: function(node) {
10962 var doc = node.ownerDocument || node;
10963 return doc === rootDocument ? this.documentPreloadSelectors :
10964 this.importsPreloadSelectors;
10965 },
10966
10967 loaded: function(url, elt, resource, err, redirectedUrl) {
10968 flags.load && console.log('loaded', url, elt);
10969 // store generic resource
10970 // TODO(sorvell): fails for nodes inside <template>.content
10971 // see https://code.google.com/p/chromium/issues/detail?id=249381.
10972 elt.__resource = resource;
10973 elt.__error = err;
10974 if (isDocumentLink(elt)) {
10975 var doc = this.documents[url];
10976 // if we've never seen a document at this url
10977 if (doc === undefined) {
10978 // generate an HTMLDocument from data
10979 doc = err ? null : makeDocument(resource, redirectedUrl || url);
10980 if (doc) {
10981 doc.__importLink = elt;
10982 // note, we cannot use MO to detect parsed nodes because
10983 // SD polyfill does not report these as mutations.
10984 this.bootDocument(doc);
10985 }
10986 // cache document
10987 this.documents[url] = doc;
10988 }
10989 // don't store import record until we're actually loaded
10990 // store document resource
10991 elt.import = doc;
10992 }
10993 parser.parseNext();
10994 },
10995
10996 bootDocument: function(doc) {
10997 this.loadSubtree(doc);
10998 this.observe(doc);
10999 parser.parseNext();
11000 },
11001
11002 loadedAll: function() {
11003 parser.parseNext();
11004 }
11005
11006 };
11007
11008 // loader singleton
11009 var importLoader = new Loader(importer.loaded.bind(importer),
11010 importer.loadedAll.bind(importer));
11011
11012 function isDocumentLink(elt) {
11013 return isLinkRel(elt, IMPORT_LINK_TYPE);
11014 }
11015
11016 function isLinkRel(elt, rel) {
11017 return elt.localName === 'link' && elt.getAttribute('rel') === rel;
11018 }
11019
11020 function isScript(elt) {
11021 return elt.localName === 'script';
11022 }
11023
11024 function makeDocument(resource, url) {
11025 // create a new HTML document
11026 var doc = resource;
11027 if (!(doc instanceof Document)) {
11028 doc = document.implementation.createHTMLDocument(IMPORT_LINK_TYPE);
11029 }
11030 // cache the new document's source url
11031 doc._URL = url;
11032 // establish a relative path via <base>
11033 var base = doc.createElement('base');
11034 base.setAttribute('href', url);
11035 // add baseURI support to browsers (IE) that lack it.
11036 if (!doc.baseURI) {
11037 doc.baseURI = url;
11038 }
11039 // ensure UTF-8 charset
11040 var meta = doc.createElement('meta');
11041 meta.setAttribute('charset', 'utf-8');
11042
11043 doc.head.appendChild(meta);
11044 doc.head.appendChild(base);
11045 // install HTML last as it may trigger CustomElement upgrades
11046 // TODO(sjmiles): problem wrt to template boostrapping below,
11047 // template bootstrapping must (?) come before element upgrade
11048 // but we cannot bootstrap templates until they are in a document
11049 // which is too late
11050 if (!(resource instanceof Document)) {
11051 // install html
11052 doc.body.innerHTML = resource;
11053 }
11054 // TODO(sorvell): ideally this code is not aware of Template polyfill,
11055 // but for now the polyfill needs help to bootstrap these templates
11056 if (window.HTMLTemplateElement && HTMLTemplateElement.bootstrap) {
11057 HTMLTemplateElement.bootstrap(doc);
11058 }
11059 return doc;
11060 }
11061
11062 // Polyfill document.baseURI for browsers without it.
11063 if (!document.baseURI) {
11064 var baseURIDescriptor = {
11065 get: function() {
11066 var base = document.querySelector('base');
11067 return base ? base.href : window.location.href;
11068 },
11069 configurable: true
11070 };
11071
11072 Object.defineProperty(document, 'baseURI', baseURIDescriptor);
11073 Object.defineProperty(rootDocument, 'baseURI', baseURIDescriptor);
11074 }
11075
11076 // IE shim for CustomEvent
11077 if (typeof window.CustomEvent !== 'function') {
11078 window.CustomEvent = function(inType, dictionary) {
11079 var e = document.createEvent('HTMLEvents');
11080 e.initEvent(inType,
11081 dictionary.bubbles === false ? false : true,
11082 dictionary.cancelable === false ? false : true,
11083 dictionary.detail);
11084 return e;
11085 };
11086 }
11087
11088 } else {
11089 // do nothing if using native imports
11090 var importer = {};
11091 }
11092
11093 // exports
11094 scope.importer = importer;
11095 scope.IMPORT_LINK_TYPE = IMPORT_LINK_TYPE;
11096 scope.importLoader = importLoader;
11097
11098 })(window.HTMLImports);
11099
11100 /*
11101 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
11102 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
11103 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
11104 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
11105 * Code distributed by Google as part of the polymer project is also
11106 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
11107 */
11108 (function(scope){
11109
11110 // imports
11111 var IMPORT_LINK_TYPE = scope.IMPORT_LINK_TYPE;
11112 var importer = scope.importer;
11113 var parser = scope.parser;
11114
11115 var importSelector = 'link[rel=' + IMPORT_LINK_TYPE + ']';
11116
11117
11118 // we track mutations for addedNodes, looking for imports
11119 function handler(mutations) {
11120 for (var i=0, l=mutations.length, m; (i<l) && (m=mutations[i]); i++) {
11121 if (m.type === 'childList' && m.addedNodes.length) {
11122 addedNodes(m.addedNodes);
11123 }
11124 }
11125 }
11126
11127 // find loadable elements and add them to the importer
11128 // IFF the owning document has already parsed, then parsable elements
11129 // need to be marked for dynamic parsing.
11130 function addedNodes(nodes) {
11131 var owner, parsed;
11132 for (var i=0, l=nodes.length, n, loading; (i<l) && (n=nodes[i]); i++) {
11133 if (!owner) {
11134 owner = n.ownerDocument;
11135 parsed = parser.isParsed(owner);
11136 }
11137 // note: the act of loading kicks the parser, so we use parseDynamic's
11138 // 2nd argument to control if this added node needs to kick the parser.
11139 loading = shouldLoadNode(n);
11140 if (loading) {
11141 importer.loadNode(n);
11142 }
11143 if (shouldParseNode(n) && parsed) {
11144 parser.parseDynamic(n, loading);
11145 }
11146 if (n.children && n.children.length) {
11147 addedNodes(n.children);
11148 }
11149 }
11150 }
11151
11152 function shouldLoadNode(node) {
11153 return (node.nodeType === 1) && matches.call(node,
11154 importer.loadSelectorsForNode(node));
11155 }
11156
11157 function shouldParseNode(node) {
11158 return (node.nodeType === 1) && matches.call(node,
11159 parser.parseSelectorsForNode(node));
11160 }
11161
11162 // x-plat matches
11163 var matches = HTMLElement.prototype.matches ||
11164 HTMLElement.prototype.matchesSelector ||
11165 HTMLElement.prototype.webkitMatchesSelector ||
11166 HTMLElement.prototype.mozMatchesSelector ||
11167 HTMLElement.prototype.msMatchesSelector;
11168
11169 var observer = new MutationObserver(handler);
11170
11171 // observe the given root for loadable elements
11172 function observe(root) {
11173 observer.observe(root, {childList: true, subtree: true});
11174 }
11175
11176 // exports
11177 // TODO(sorvell): factor so can put on scope
11178 scope.observe = observe;
11179 importer.observe = observe;
11180
11181 })(HTMLImports);
11182
11183 /*
11184 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
11185 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
11186 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
11187 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
11188 * Code distributed by Google as part of the polymer project is also
11189 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
11190 */
11191 (function(){
11192
11193 // bootstrap
11194
11195 // TODO(sorvell): SD polyfill intrusion
11196 var doc = window.ShadowDOMPolyfill ?
11197 window.ShadowDOMPolyfill.wrapIfNeeded(document) : document;
11198
11199 // no need to bootstrap the polyfill when native imports is available.
11200 if (!HTMLImports.useNative) {
11201 function bootstrap() {
11202 HTMLImports.importer.bootDocument(doc);
11203 }
11204
11205 // TODO(sorvell): SD polyfill does *not* generate mutations for nodes added
11206 // by the parser. For this reason, we must wait until the dom exists to
11207 // bootstrap.
11208 if (document.readyState === 'complete' ||
11209 (document.readyState === 'interactive' && !window.attachEvent)) {
11210 bootstrap();
11211 } else {
11212 document.addEventListener('DOMContentLoaded', bootstrap);
11213 }
11214 }
11215
11216 })();
11217
11218 /*
11219 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
11220 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
11221 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
11222 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
11223 * Code distributed by Google as part of the polymer project is also
11224 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
11225 */
11226 window.CustomElements = window.CustomElements || {flags:{}};
11227 /*
11228 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
11229 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
11230 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
11231 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
11232 * Code distributed by Google as part of the polymer project is also
11233 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
11234 */
11235
11236 (function(scope){
11237
11238 var logFlags = window.logFlags || {};
11239 var IMPORT_LINK_TYPE = window.HTMLImports ? HTMLImports.IMPORT_LINK_TYPE : 'none ';
11240
11241 // walk the subtree rooted at node, applying 'find(element, data)' function
11242 // to each element
11243 // if 'find' returns true for 'element', do not search element's subtree
11244 function findAll(node, find, data) {
11245 var e = node.firstElementChild;
11246 if (!e) {
11247 e = node.firstChild;
11248 while (e && e.nodeType !== Node.ELEMENT_NODE) {
11249 e = e.nextSibling;
11250 }
11251 }
11252 while (e) {
11253 if (find(e, data) !== true) {
11254 findAll(e, find, data);
11255 }
11256 e = e.nextElementSibling;
11257 }
11258 return null;
11259 }
11260
11261 // walk all shadowRoots on a given node.
11262 function forRoots(node, cb) {
11263 var root = node.shadowRoot;
11264 while(root) {
11265 forSubtree(root, cb);
11266 root = root.olderShadowRoot;
11267 }
11268 }
11269
11270 // walk the subtree rooted at node, including descent into shadow-roots,
11271 // applying 'cb' to each element
11272 function forSubtree(node, cb) {
11273 //logFlags.dom && node.childNodes && node.childNodes.length && console.group(' subTree: ', node);
11274 findAll(node, function(e) {
11275 if (cb(e)) {
11276 return true;
11277 }
11278 forRoots(e, cb);
11279 });
11280 forRoots(node, cb);
11281 //logFlags.dom && node.childNodes && node.childNodes.length && console.groupEn d();
11282 }
11283
11284 // manage lifecycle on added node
11285 function added(node) {
11286 if (upgrade(node)) {
11287 insertedNode(node);
11288 return true;
11289 }
11290 inserted(node);
11291 }
11292
11293 // manage lifecycle on added node's subtree only
11294 function addedSubtree(node) {
11295 forSubtree(node, function(e) {
11296 if (added(e)) {
11297 return true;
11298 }
11299 });
11300 }
11301
11302 // manage lifecycle on added node and it's subtree
11303 function addedNode(node) {
11304 return added(node) || addedSubtree(node);
11305 }
11306
11307 // upgrade custom elements at node, if applicable
11308 function upgrade(node) {
11309 if (!node.__upgraded__ && node.nodeType === Node.ELEMENT_NODE) {
11310 var type = node.getAttribute('is') || node.localName;
11311 var definition = scope.registry[type];
11312 if (definition) {
11313 logFlags.dom && console.group('upgrade:', node.localName);
11314 scope.upgrade(node);
11315 logFlags.dom && console.groupEnd();
11316 return true;
11317 }
11318 }
11319 }
11320
11321 function insertedNode(node) {
11322 inserted(node);
11323 if (inDocument(node)) {
11324 forSubtree(node, function(e) {
11325 inserted(e);
11326 });
11327 }
11328 }
11329
11330 // TODO(sorvell): on platforms without MutationObserver, mutations may not be
11331 // reliable and therefore attached/detached are not reliable.
11332 // To make these callbacks less likely to fail, we defer all inserts and removes
11333 // to give a chance for elements to be inserted into dom.
11334 // This ensures attachedCallback fires for elements that are created and
11335 // immediately added to dom.
11336 var hasPolyfillMutations = (!window.MutationObserver ||
11337 (window.MutationObserver === window.JsMutationObserver));
11338 scope.hasPolyfillMutations = hasPolyfillMutations;
11339
11340 var isPendingMutations = false;
11341 var pendingMutations = [];
11342 function deferMutation(fn) {
11343 pendingMutations.push(fn);
11344 if (!isPendingMutations) {
11345 isPendingMutations = true;
11346 var async = (window.Platform && window.Platform.endOfMicrotask) ||
11347 setTimeout;
11348 async(takeMutations);
11349 }
11350 }
11351
11352 function takeMutations() {
11353 isPendingMutations = false;
11354 var $p = pendingMutations;
11355 for (var i=0, l=$p.length, p; (i<l) && (p=$p[i]); i++) {
11356 p();
11357 }
11358 pendingMutations = [];
11359 }
11360
11361 function inserted(element) {
11362 if (hasPolyfillMutations) {
11363 deferMutation(function() {
11364 _inserted(element);
11365 });
11366 } else {
11367 _inserted(element);
11368 }
11369 }
11370
11371 // TODO(sjmiles): if there are descents into trees that can never have inDocumen t(*) true, fix this
11372 function _inserted(element) {
11373 // TODO(sjmiles): it's possible we were inserted and removed in the space
11374 // of one microtask, in which case we won't be 'inDocument' here
11375 // But there are other cases where we are testing for inserted without
11376 // specific knowledge of mutations, and must test 'inDocument' to determine
11377 // whether to call inserted
11378 // If we can factor these cases into separate code paths we can have
11379 // better diagnostics.
11380 // TODO(sjmiles): when logging, do work on all custom elements so we can
11381 // track behavior even when callbacks not defined
11382 //console.log('inserted: ', element.localName);
11383 if (element.attachedCallback || element.detachedCallback || (element.__upgrade d__ && logFlags.dom)) {
11384 logFlags.dom && console.group('inserted:', element.localName);
11385 if (inDocument(element)) {
11386 element.__inserted = (element.__inserted || 0) + 1;
11387 // if we are in a 'removed' state, bluntly adjust to an 'inserted' state
11388 if (element.__inserted < 1) {
11389 element.__inserted = 1;
11390 }
11391 // if we are 'over inserted', squelch the callback
11392 if (element.__inserted > 1) {
11393 logFlags.dom && console.warn('inserted:', element.localName,
11394 'insert/remove count:', element.__inserted)
11395 } else if (element.attachedCallback) {
11396 logFlags.dom && console.log('inserted:', element.localName);
11397 element.attachedCallback();
11398 }
11399 }
11400 logFlags.dom && console.groupEnd();
11401 }
11402 }
11403
11404 function removedNode(node) {
11405 removed(node);
11406 forSubtree(node, function(e) {
11407 removed(e);
11408 });
11409 }
11410
11411 function removed(element) {
11412 if (hasPolyfillMutations) {
11413 deferMutation(function() {
11414 _removed(element);
11415 });
11416 } else {
11417 _removed(element);
11418 }
11419 }
11420
11421 function _removed(element) {
11422 // TODO(sjmiles): temporary: do work on all custom elements so we can track
11423 // behavior even when callbacks not defined
11424 if (element.attachedCallback || element.detachedCallback || (element.__upgrade d__ && logFlags.dom)) {
11425 logFlags.dom && console.group('removed:', element.localName);
11426 if (!inDocument(element)) {
11427 element.__inserted = (element.__inserted || 0) - 1;
11428 // if we are in a 'inserted' state, bluntly adjust to an 'removed' state
11429 if (element.__inserted > 0) {
11430 element.__inserted = 0;
11431 }
11432 // if we are 'over removed', squelch the callback
11433 if (element.__inserted < 0) {
11434 logFlags.dom && console.warn('removed:', element.localName,
11435 'insert/remove count:', element.__inserted)
11436 } else if (element.detachedCallback) {
11437 element.detachedCallback();
11438 }
11439 }
11440 logFlags.dom && console.groupEnd();
11441 }
11442 }
11443
11444 // SD polyfill intrustion due mainly to the fact that 'document'
11445 // is not entirely wrapped
11446 function wrapIfNeeded(node) {
11447 return window.ShadowDOMPolyfill ? ShadowDOMPolyfill.wrapIfNeeded(node)
11448 : node;
11449 }
11450
11451 function inDocument(element) {
11452 var p = element;
11453 var doc = wrapIfNeeded(document);
11454 while (p) {
11455 if (p == doc) {
11456 return true;
11457 }
11458 p = p.parentNode || p.host;
11459 }
11460 }
11461
11462 function watchShadow(node) {
11463 if (node.shadowRoot && !node.shadowRoot.__watched) {
11464 logFlags.dom && console.log('watching shadow-root for: ', node.localName);
11465 // watch all unwatched roots...
11466 var root = node.shadowRoot;
11467 while (root) {
11468 watchRoot(root);
11469 root = root.olderShadowRoot;
11470 }
11471 }
11472 }
11473
11474 function watchRoot(root) {
11475 observe(root);
11476 }
11477
11478 function handler(mutations) {
11479 //
11480 if (logFlags.dom) {
11481 var mx = mutations[0];
11482 if (mx && mx.type === 'childList' && mx.addedNodes) {
11483 if (mx.addedNodes) {
11484 var d = mx.addedNodes[0];
11485 while (d && d !== document && !d.host) {
11486 d = d.parentNode;
11487 }
11488 var u = d && (d.URL || d._URL || (d.host && d.host.localName)) || '';
11489 u = u.split('/?').shift().split('/').pop();
11490 }
11491 }
11492 console.group('mutations (%d) [%s]', mutations.length, u || '');
11493 }
11494 //
11495 mutations.forEach(function(mx) {
11496 //logFlags.dom && console.group('mutation');
11497 if (mx.type === 'childList') {
11498 forEach(mx.addedNodes, function(n) {
11499 //logFlags.dom && console.log(n.localName);
11500 if (!n.localName) {
11501 return;
11502 }
11503 // nodes added may need lifecycle management
11504 addedNode(n);
11505 });
11506 // removed nodes may need lifecycle management
11507 forEach(mx.removedNodes, function(n) {
11508 //logFlags.dom && console.log(n.localName);
11509 if (!n.localName) {
11510 return;
11511 }
11512 removedNode(n);
11513 });
11514 }
11515 //logFlags.dom && console.groupEnd();
11516 });
11517 logFlags.dom && console.groupEnd();
11518 };
11519
11520 function takeRecords(node) {
11521 // If the optional node is not supplied, assume we mean the whole document.
11522 if (!node) node = wrapIfNeeded(document);
11523
11524 // Find the root of the tree, which will be an Document or ShadowRoot.
11525 while (node.parentNode) {
11526 node = node.parentNode;
11527 }
11528
11529 var observer = node.__observer;
11530 if (observer) {
11531 handler(observer.takeRecords());
11532 takeMutations();
11533 }
11534 }
11535
11536 var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
11537
11538 function observe(inRoot) {
11539 if (inRoot.__observer) return;
11540
11541 // For each ShadowRoot, we create a new MutationObserver, so the root can be
11542 // garbage collected once all references to the `inRoot` node are gone.
11543 var observer = new MutationObserver(handler);
11544 observer.observe(inRoot, {childList: true, subtree: true});
11545 inRoot.__observer = observer;
11546 }
11547
11548 function observeDocument(doc) {
11549 observe(doc);
11550 }
11551
11552 function upgradeDocument(doc) {
11553 logFlags.dom && console.group('upgradeDocument: ', (doc.baseURI).split('/').po p());
11554 addedNode(doc);
11555 logFlags.dom && console.groupEnd();
11556 }
11557
11558 /*
11559 This method is intended to be called when the document tree (including imports)
11560 has pending custom elements to upgrade. It can be called multiple times and
11561 should do nothing if no elements are in need of upgrade.
11562
11563 Note that the import tree can consume itself and therefore special care
11564 must be taken to avoid recursion.
11565 */
11566 var upgradedDocuments;
11567 function upgradeDocumentTree(doc) {
11568 upgradedDocuments = [];
11569 _upgradeDocumentTree(doc);
11570 upgradedDocuments = null;
11571 }
11572
11573
11574 function _upgradeDocumentTree(doc) {
11575 doc = wrapIfNeeded(doc);
11576 if (upgradedDocuments.indexOf(doc) >= 0) {
11577 return;
11578 }
11579 upgradedDocuments.push(doc);
11580 //console.log('upgradeDocumentTree: ', (doc.baseURI).split('/').pop());
11581 // upgrade contained imported documents
11582 var imports = doc.querySelectorAll('link[rel=' + IMPORT_LINK_TYPE + ']');
11583 for (var i=0, l=imports.length, n; (i<l) && (n=imports[i]); i++) {
11584 if (n.import && n.import.__parsed) {
11585 _upgradeDocumentTree(n.import);
11586 }
11587 }
11588 upgradeDocument(doc);
11589 }
11590
11591 // exports
11592 scope.IMPORT_LINK_TYPE = IMPORT_LINK_TYPE;
11593 scope.watchShadow = watchShadow;
11594 scope.upgradeDocumentTree = upgradeDocumentTree;
11595 scope.upgradeAll = addedNode;
11596 scope.upgradeSubtree = addedSubtree;
11597 scope.insertedNode = insertedNode;
11598
11599 scope.observeDocument = observeDocument;
11600 scope.upgradeDocument = upgradeDocument;
11601
11602 scope.takeRecords = takeRecords;
11603
11604 })(window.CustomElements);
11605
11606 /*
11607 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
11608 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
11609 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
11610 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
11611 * Code distributed by Google as part of the polymer project is also
11612 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
11613 */
11614
11615 /**
11616 * Implements `document.registerElement`
11617 * @module CustomElements
11618 */
11619
11620 /**
11621 * Polyfilled extensions to the `document` object.
11622 * @class Document
11623 */
11624
11625 (function(scope) {
11626
11627 // imports
11628
11629 if (!scope) {
11630 scope = window.CustomElements = {flags:{}};
11631 }
11632 var flags = scope.flags;
11633
11634 // native document.registerElement?
11635
11636 var hasNative = Boolean(document.registerElement);
11637 // For consistent timing, use native custom elements only when not polyfilling
11638 // other key related web components features.
11639 var useNative = !flags.register && hasNative && !window.ShadowDOMPolyfill && (!w indow.HTMLImports || HTMLImports.useNative);
11640
11641 if (useNative) {
11642
11643 // stub
11644 var nop = function() {};
11645
11646 // exports
11647 scope.registry = {};
11648 scope.upgradeElement = nop;
11649
11650 scope.watchShadow = nop;
11651 scope.upgrade = nop;
11652 scope.upgradeAll = nop;
11653 scope.upgradeSubtree = nop;
11654 scope.observeDocument = nop;
11655 scope.upgradeDocument = nop;
11656 scope.upgradeDocumentTree = nop;
11657 scope.takeRecords = nop;
11658 scope.reservedTagList = [];
11659
11660 } else {
11661
11662 /**
11663 * Registers a custom tag name with the document.
11664 *
11665 * When a registered element is created, a `readyCallback` method is called
11666 * in the scope of the element. The `readyCallback` method can be specified on
11667 * either `options.prototype` or `options.lifecycle` with the latter taking
11668 * precedence.
11669 *
11670 * @method register
11671 * @param {String} name The tag name to register. Must include a dash ('-'),
11672 * for example 'x-component'.
11673 * @param {Object} options
11674 * @param {String} [options.extends]
11675 * (_off spec_) Tag name of an element to extend (or blank for a new
11676 * element). This parameter is not part of the specification, but instead
11677 * is a hint for the polyfill because the extendee is difficult to infer.
11678 * Remember that the input prototype must chain to the extended element's
11679 * prototype (or HTMLElement.prototype) regardless of the value of
11680 * `extends`.
11681 * @param {Object} options.prototype The prototype to use for the new
11682 * element. The prototype must inherit from HTMLElement.
11683 * @param {Object} [options.lifecycle]
11684 * Callbacks that fire at important phases in the life of the custom
11685 * element.
11686 *
11687 * @example
11688 * FancyButton = document.registerElement("fancy-button", {
11689 * extends: 'button',
11690 * prototype: Object.create(HTMLButtonElement.prototype, {
11691 * readyCallback: {
11692 * value: function() {
11693 * console.log("a fancy-button was created",
11694 * }
11695 * }
11696 * })
11697 * });
11698 * @return {Function} Constructor for the newly registered type.
11699 */
11700 function register(name, options) {
11701 //console.warn('document.registerElement("' + name + '", ', options, ')');
11702 // construct a defintion out of options
11703 // TODO(sjmiles): probably should clone options instead of mutating it
11704 var definition = options || {};
11705 if (!name) {
11706 // TODO(sjmiles): replace with more appropriate error (EricB can probably
11707 // offer guidance)
11708 throw new Error('document.registerElement: first argument `name` must not be empty');
11709 }
11710 if (name.indexOf('-') < 0) {
11711 // TODO(sjmiles): replace with more appropriate error (EricB can probably
11712 // offer guidance)
11713 throw new Error('document.registerElement: first argument (\'name\') must contain a dash (\'-\'). Argument provided was \'' + String(name) + '\'.');
11714 }
11715 // prevent registering reserved names
11716 if (isReservedTag(name)) {
11717 throw new Error('Failed to execute \'registerElement\' on \'Document\': Re gistration failed for type \'' + String(name) + '\'. The type name is invalid.') ;
11718 }
11719 // elements may only be registered once
11720 if (getRegisteredDefinition(name)) {
11721 throw new Error('DuplicateDefinitionError: a type with name \'' + String(n ame) + '\' is already registered');
11722 }
11723 // must have a prototype, default to an extension of HTMLElement
11724 // TODO(sjmiles): probably should throw if no prototype, check spec
11725 if (!definition.prototype) {
11726 // TODO(sjmiles): replace with more appropriate error (EricB can probably
11727 // offer guidance)
11728 throw new Error('Options missing required prototype property');
11729 }
11730 // record name
11731 definition.__name = name.toLowerCase();
11732 // ensure a lifecycle object so we don't have to null test it
11733 definition.lifecycle = definition.lifecycle || {};
11734 // build a list of ancestral custom elements (for native base detection)
11735 // TODO(sjmiles): we used to need to store this, but current code only
11736 // uses it in 'resolveTagName': it should probably be inlined
11737 definition.ancestry = ancestry(definition.extends);
11738 // extensions of native specializations of HTMLElement require localName
11739 // to remain native, and use secondary 'is' specifier for extension type
11740 resolveTagName(definition);
11741 // some platforms require modifications to the user-supplied prototype
11742 // chain
11743 resolvePrototypeChain(definition);
11744 // overrides to implement attributeChanged callback
11745 overrideAttributeApi(definition.prototype);
11746 // 7.1.5: Register the DEFINITION with DOCUMENT
11747 registerDefinition(definition.__name, definition);
11748 // 7.1.7. Run custom element constructor generation algorithm with PROTOTYPE
11749 // 7.1.8. Return the output of the previous step.
11750 definition.ctor = generateConstructor(definition);
11751 definition.ctor.prototype = definition.prototype;
11752 // force our .constructor to be our actual constructor
11753 definition.prototype.constructor = definition.ctor;
11754 // if initial parsing is complete
11755 if (scope.ready) {
11756 // upgrade any pre-existing nodes of this type
11757 scope.upgradeDocumentTree(document);
11758 }
11759 return definition.ctor;
11760 }
11761
11762 function isReservedTag(name) {
11763 for (var i = 0; i < reservedTagList.length; i++) {
11764 if (name === reservedTagList[i]) {
11765 return true;
11766 }
11767 }
11768 }
11769
11770 var reservedTagList = [
11771 'annotation-xml', 'color-profile', 'font-face', 'font-face-src',
11772 'font-face-uri', 'font-face-format', 'font-face-name', 'missing-glyph'
11773 ];
11774
11775 function ancestry(extnds) {
11776 var extendee = getRegisteredDefinition(extnds);
11777 if (extendee) {
11778 return ancestry(extendee.extends).concat([extendee]);
11779 }
11780 return [];
11781 }
11782
11783 function resolveTagName(definition) {
11784 // if we are explicitly extending something, that thing is our
11785 // baseTag, unless it represents a custom component
11786 var baseTag = definition.extends;
11787 // if our ancestry includes custom components, we only have a
11788 // baseTag if one of them does
11789 for (var i=0, a; (a=definition.ancestry[i]); i++) {
11790 baseTag = a.is && a.tag;
11791 }
11792 // our tag is our baseTag, if it exists, and otherwise just our name
11793 definition.tag = baseTag || definition.__name;
11794 if (baseTag) {
11795 // if there is a base tag, use secondary 'is' specifier
11796 definition.is = definition.__name;
11797 }
11798 }
11799
11800 function resolvePrototypeChain(definition) {
11801 // if we don't support __proto__ we need to locate the native level
11802 // prototype for precise mixing in
11803 if (!Object.__proto__) {
11804 // default prototype
11805 var nativePrototype = HTMLElement.prototype;
11806 // work out prototype when using type-extension
11807 if (definition.is) {
11808 var inst = document.createElement(definition.tag);
11809 var expectedPrototype = Object.getPrototypeOf(inst);
11810 // only set nativePrototype if it will actually appear in the definition 's chain
11811 if (expectedPrototype === definition.prototype) {
11812 nativePrototype = expectedPrototype;
11813 }
11814 }
11815 // ensure __proto__ reference is installed at each point on the prototype
11816 // chain.
11817 // NOTE: On platforms without __proto__, a mixin strategy is used instead
11818 // of prototype swizzling. In this case, this generated __proto__ provides
11819 // limited support for prototype traversal.
11820 var proto = definition.prototype, ancestor;
11821 while (proto && (proto !== nativePrototype)) {
11822 ancestor = Object.getPrototypeOf(proto);
11823 proto.__proto__ = ancestor;
11824 proto = ancestor;
11825 }
11826 // cache this in case of mixin
11827 definition.native = nativePrototype;
11828 }
11829 }
11830
11831 // SECTION 4
11832
11833 function instantiate(definition) {
11834 // 4.a.1. Create a new object that implements PROTOTYPE
11835 // 4.a.2. Let ELEMENT by this new object
11836 //
11837 // the custom element instantiation algorithm must also ensure that the
11838 // output is a valid DOM element with the proper wrapper in place.
11839 //
11840 return upgrade(domCreateElement(definition.tag), definition);
11841 }
11842
11843 function upgrade(element, definition) {
11844 // some definitions specify an 'is' attribute
11845 if (definition.is) {
11846 element.setAttribute('is', definition.is);
11847 }
11848 // make 'element' implement definition.prototype
11849 implement(element, definition);
11850 // flag as upgraded
11851 element.__upgraded__ = true;
11852 // lifecycle management
11853 created(element);
11854 // attachedCallback fires in tree order, call before recursing
11855 scope.insertedNode(element);
11856 // there should never be a shadow root on element at this point
11857 scope.upgradeSubtree(element);
11858 // OUTPUT
11859 return element;
11860 }
11861
11862 function implement(element, definition) {
11863 // prototype swizzling is best
11864 if (Object.__proto__) {
11865 element.__proto__ = definition.prototype;
11866 } else {
11867 // where above we can re-acquire inPrototype via
11868 // getPrototypeOf(Element), we cannot do so when
11869 // we use mixin, so we install a magic reference
11870 customMixin(element, definition.prototype, definition.native);
11871 element.__proto__ = definition.prototype;
11872 }
11873 }
11874
11875 function customMixin(inTarget, inSrc, inNative) {
11876 // TODO(sjmiles): 'used' allows us to only copy the 'youngest' version of
11877 // any property. This set should be precalculated. We also need to
11878 // consider this for supporting 'super'.
11879 var used = {};
11880 // start with inSrc
11881 var p = inSrc;
11882 // The default is HTMLElement.prototype, so we add a test to avoid mixing in
11883 // native prototypes
11884 while (p !== inNative && p !== HTMLElement.prototype) {
11885 var keys = Object.getOwnPropertyNames(p);
11886 for (var i=0, k; k=keys[i]; i++) {
11887 if (!used[k]) {
11888 Object.defineProperty(inTarget, k,
11889 Object.getOwnPropertyDescriptor(p, k));
11890 used[k] = 1;
11891 }
11892 }
11893 p = Object.getPrototypeOf(p);
11894 }
11895 }
11896
11897 function created(element) {
11898 // invoke createdCallback
11899 if (element.createdCallback) {
11900 element.createdCallback();
11901 }
11902 }
11903
11904 // attribute watching
11905
11906 function overrideAttributeApi(prototype) {
11907 // overrides to implement callbacks
11908 // TODO(sjmiles): should support access via .attributes NamedNodeMap
11909 // TODO(sjmiles): preserves user defined overrides, if any
11910 if (prototype.setAttribute._polyfilled) {
11911 return;
11912 }
11913 var setAttribute = prototype.setAttribute;
11914 prototype.setAttribute = function(name, value) {
11915 changeAttribute.call(this, name, value, setAttribute);
11916 }
11917 var removeAttribute = prototype.removeAttribute;
11918 prototype.removeAttribute = function(name) {
11919 changeAttribute.call(this, name, null, removeAttribute);
11920 }
11921 prototype.setAttribute._polyfilled = true;
11922 }
11923
11924 // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/
11925 // index.html#dfn-attribute-changed-callback
11926 function changeAttribute(name, value, operation) {
11927 name = name.toLowerCase();
11928 var oldValue = this.getAttribute(name);
11929 operation.apply(this, arguments);
11930 var newValue = this.getAttribute(name);
11931 if (this.attributeChangedCallback
11932 && (newValue !== oldValue)) {
11933 this.attributeChangedCallback(name, oldValue, newValue);
11934 }
11935 }
11936
11937 // element registry (maps tag names to definitions)
11938
11939 var registry = {};
11940
11941 function getRegisteredDefinition(name) {
11942 if (name) {
11943 return registry[name.toLowerCase()];
11944 }
11945 }
11946
11947 function registerDefinition(name, definition) {
11948 registry[name] = definition;
11949 }
11950
11951 function generateConstructor(definition) {
11952 return function() {
11953 return instantiate(definition);
11954 };
11955 }
11956
11957 var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
11958 function createElementNS(namespace, tag, typeExtension) {
11959 // NOTE: we do not support non-HTML elements,
11960 // just call createElementNS for non HTML Elements
11961 if (namespace === HTML_NAMESPACE) {
11962 return createElement(tag, typeExtension);
11963 } else {
11964 return domCreateElementNS(namespace, tag);
11965 }
11966 }
11967
11968 function createElement(tag, typeExtension) {
11969 // TODO(sjmiles): ignore 'tag' when using 'typeExtension', we could
11970 // error check it, or perhaps there should only ever be one argument
11971 var definition = getRegisteredDefinition(typeExtension || tag);
11972 if (definition) {
11973 if (tag == definition.tag && typeExtension == definition.is) {
11974 return new definition.ctor();
11975 }
11976 // Handle empty string for type extension.
11977 if (!typeExtension && !definition.is) {
11978 return new definition.ctor();
11979 }
11980 }
11981
11982 if (typeExtension) {
11983 var element = createElement(tag);
11984 element.setAttribute('is', typeExtension);
11985 return element;
11986 }
11987 var element = domCreateElement(tag);
11988 // Custom tags should be HTMLElements even if not upgraded.
11989 if (tag.indexOf('-') >= 0) {
11990 implement(element, HTMLElement);
11991 }
11992 return element;
11993 }
11994
11995 function upgradeElement(element) {
11996 if (!element.__upgraded__ && (element.nodeType === Node.ELEMENT_NODE)) {
11997 var is = element.getAttribute('is');
11998 var definition = getRegisteredDefinition(is || element.localName);
11999 if (definition) {
12000 if (is && definition.tag == element.localName) {
12001 return upgrade(element, definition);
12002 } else if (!is && !definition.extends) {
12003 return upgrade(element, definition);
12004 }
12005 }
12006 }
12007 }
12008
12009 function cloneNode(deep) {
12010 // call original clone
12011 var n = domCloneNode.call(this, deep);
12012 // upgrade the element and subtree
12013 scope.upgradeAll(n);
12014 // return the clone
12015 return n;
12016 }
12017 // capture native createElement before we override it
12018
12019 var domCreateElement = document.createElement.bind(document);
12020 var domCreateElementNS = document.createElementNS.bind(document);
12021
12022 // capture native cloneNode before we override it
12023
12024 var domCloneNode = Node.prototype.cloneNode;
12025
12026 // exports
12027
12028 document.registerElement = register;
12029 document.createElement = createElement; // override
12030 document.createElementNS = createElementNS; // override
12031 Node.prototype.cloneNode = cloneNode; // override
12032
12033 scope.registry = registry;
12034
12035 /**
12036 * Upgrade an element to a custom element. Upgrading an element
12037 * causes the custom prototype to be applied, an `is` attribute
12038 * to be attached (as needed), and invocation of the `readyCallback`.
12039 * `upgrade` does nothing if the element is already upgraded, or
12040 * if it matches no registered custom tag name.
12041 *
12042 * @method ugprade
12043 * @param {Element} element The element to upgrade.
12044 * @return {Element} The upgraded element.
12045 */
12046 scope.upgrade = upgradeElement;
12047 }
12048
12049 // Create a custom 'instanceof'. This is necessary when CustomElements
12050 // are implemented via a mixin strategy, as for example on IE10.
12051 var isInstance;
12052 if (!Object.__proto__ && !useNative) {
12053 isInstance = function(obj, ctor) {
12054 var p = obj;
12055 while (p) {
12056 // NOTE: this is not technically correct since we're not checking if
12057 // an object is an instance of a constructor; however, this should
12058 // be good enough for the mixin strategy.
12059 if (p === ctor.prototype) {
12060 return true;
12061 }
12062 p = p.__proto__;
12063 }
12064 return false;
12065 }
12066 } else {
12067 isInstance = function(obj, base) {
12068 return obj instanceof base;
12069 }
12070 }
12071
12072 // exports
12073 scope.instanceof = isInstance;
12074 scope.reservedTagList = reservedTagList;
12075
12076 // bc
12077 document.register = document.registerElement;
12078
12079 scope.hasNative = hasNative;
12080 scope.useNative = useNative;
12081
12082 })(window.CustomElements);
12083
12084 /*
12085 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
12086 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
12087 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
12088 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
12089 * Code distributed by Google as part of the polymer project is also
12090 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
12091 */
12092
12093 (function(scope) {
12094
12095 // import
12096
12097 var IMPORT_LINK_TYPE = scope.IMPORT_LINK_TYPE;
12098
12099 // highlander object for parsing a document tree
12100
12101 var parser = {
12102 selectors: [
12103 'link[rel=' + IMPORT_LINK_TYPE + ']'
12104 ],
12105 map: {
12106 link: 'parseLink'
12107 },
12108 parse: function(inDocument) {
12109 if (!inDocument.__parsed) {
12110 // only parse once
12111 inDocument.__parsed = true;
12112 // all parsable elements in inDocument (depth-first pre-order traversal)
12113 var elts = inDocument.querySelectorAll(parser.selectors);
12114 // for each parsable node type, call the mapped parsing method
12115 forEach(elts, function(e) {
12116 parser[parser.map[e.localName]](e);
12117 });
12118 // upgrade all upgradeable static elements, anything dynamically
12119 // created should be caught by observer
12120 CustomElements.upgradeDocument(inDocument);
12121 // observe document for dom changes
12122 CustomElements.observeDocument(inDocument);
12123 }
12124 },
12125 parseLink: function(linkElt) {
12126 // imports
12127 if (isDocumentLink(linkElt)) {
12128 this.parseImport(linkElt);
12129 }
12130 },
12131 parseImport: function(linkElt) {
12132 if (linkElt.import) {
12133 parser.parse(linkElt.import);
12134 }
12135 }
12136 };
12137
12138 function isDocumentLink(inElt) {
12139 return (inElt.localName === 'link'
12140 && inElt.getAttribute('rel') === IMPORT_LINK_TYPE);
12141 }
12142
12143 var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
12144
12145 // exports
12146
12147 scope.parser = parser;
12148 scope.IMPORT_LINK_TYPE = IMPORT_LINK_TYPE;
12149
12150 })(window.CustomElements);
12151 /*
12152 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
12153 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
12154 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
12155 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
12156 * Code distributed by Google as part of the polymer project is also
12157 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
12158 */
12159 (function(scope){
12160
12161 // bootstrap parsing
12162 function bootstrap() {
12163 // parse document
12164 CustomElements.parser.parse(document);
12165 // one more pass before register is 'live'
12166 CustomElements.upgradeDocument(document);
12167 // install upgrade hook if HTMLImports are available
12168 if (window.HTMLImports) {
12169 HTMLImports.__importsParsingHook = function(elt) {
12170 CustomElements.parser.parse(elt.import);
12171 }
12172 }
12173 // set internal 'ready' flag, now document.registerElement will trigger
12174 // synchronous upgrades
12175 CustomElements.ready = true;
12176 // async to ensure *native* custom elements upgrade prior to this
12177 // DOMContentLoaded can fire before elements upgrade (e.g. when there's
12178 // an external script)
12179 setTimeout(function() {
12180 // capture blunt profiling data
12181 CustomElements.readyTime = Date.now();
12182 if (window.HTMLImports) {
12183 CustomElements.elapsed = CustomElements.readyTime - HTMLImports.readyTime;
12184 }
12185 // notify the system that we are bootstrapped
12186 document.dispatchEvent(
12187 new CustomEvent('WebComponentsReady', {bubbles: true})
12188 );
12189 });
12190 }
12191
12192 // CustomEvent shim for IE
12193 if (typeof window.CustomEvent !== 'function') {
12194 window.CustomEvent = function(inType, params) {
12195 params = params || {};
12196 var e = document.createEvent('CustomEvent');
12197 e.initCustomEvent(inType, Boolean(params.bubbles), Boolean(params.cancelable ), params.detail);
12198 return e;
12199 };
12200 window.CustomEvent.prototype = window.Event.prototype;
12201 }
12202
12203 // When loading at readyState complete time (or via flag), boot custom elements
12204 // immediately.
12205 // If relevant, HTMLImports must already be loaded.
12206 if (document.readyState === 'complete' || scope.flags.eager) {
12207 bootstrap();
12208 // When loading at readyState interactive time, bootstrap only if HTMLImports
12209 // are not pending. Also avoid IE as the semantics of this state are unreliable.
12210 } else if (document.readyState === 'interactive' && !window.attachEvent &&
12211 (!window.HTMLImports || window.HTMLImports.ready)) {
12212 bootstrap();
12213 // When loading at other readyStates, wait for the appropriate DOM event to
12214 // bootstrap.
12215 } else {
12216 var loadEvent = window.HTMLImports && !HTMLImports.ready ?
12217 'HTMLImportsLoaded' : 'DOMContentLoaded';
12218 window.addEventListener(loadEvent, bootstrap);
12219 }
12220
12221 })(window.CustomElements);
12222
12223 /*
12224 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
12225 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
12226 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
12227 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
12228 * Code distributed by Google as part of the polymer project is also
12229 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
12230 */
12231
12232 (function() {
12233
12234 if (window.ShadowDOMPolyfill) {
12235
12236 // ensure wrapped inputs for these functions
12237 var fns = ['upgradeAll', 'upgradeSubtree', 'observeDocument',
12238 'upgradeDocument'];
12239
12240 // cache originals
12241 var original = {};
12242 fns.forEach(function(fn) {
12243 original[fn] = CustomElements[fn];
12244 });
12245
12246 // override
12247 fns.forEach(function(fn) {
12248 CustomElements[fn] = function(inNode) {
12249 return original[fn](wrap(inNode));
12250 };
12251 });
12252
12253 }
12254
12255 })();
12256
12257 /*
12258 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
12259 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
12260 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
12261 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
12262 * Code distributed by Google as part of the polymer project is also
12263 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
12264 */
12265
12266 (function(scope) {
12267
12268 'use strict';
12269
12270 // polyfill performance.now
12271
12272 if (!window.performance) {
12273 var start = Date.now();
12274 // only at millisecond precision
12275 window.performance = {now: function(){ return Date.now() - start }};
12276 }
12277
12278 // polyfill for requestAnimationFrame
12279
12280 if (!window.requestAnimationFrame) {
12281 window.requestAnimationFrame = (function() {
12282 var nativeRaf = window.webkitRequestAnimationFrame ||
12283 window.mozRequestAnimationFrame;
12284
12285 return nativeRaf ?
12286 function(callback) {
12287 return nativeRaf(function() {
12288 callback(performance.now());
12289 });
12290 } :
12291 function( callback ){
12292 return window.setTimeout(callback, 1000 / 60);
12293 };
12294 })();
12295 }
12296
12297 if (!window.cancelAnimationFrame) {
12298 window.cancelAnimationFrame = (function() {
12299 return window.webkitCancelAnimationFrame ||
12300 window.mozCancelAnimationFrame ||
12301 function(id) {
12302 clearTimeout(id);
12303 };
12304 })();
12305 }
12306
12307 // Make a stub for Polymer() for polyfill purposes; under the HTMLImports
12308 // polyfill, scripts in the main document run before imports. That means
12309 // if (1) polymer is imported and (2) Polymer() is called in the main document
12310 // in a script after the import, 2 occurs before 1. We correct this here
12311 // by specfiically patching Polymer(); this is not necessary under native
12312 // HTMLImports.
12313 var elementDeclarations = [];
12314
12315 var polymerStub = function(name, dictionary) {
12316 if ((typeof name !== 'string') && (arguments.length === 1)) {
12317 Array.prototype.push.call(arguments, document._currentScript);
12318 }
12319 elementDeclarations.push(arguments);
12320 };
12321 window.Polymer = polymerStub;
12322
12323 // deliver queued delcarations
12324 scope.consumeDeclarations = function(callback) {
12325 scope.consumeDeclarations = function() {
12326 throw 'Possible attempt to load Polymer twice';
12327 };
12328 if (callback) {
12329 callback(elementDeclarations);
12330 }
12331 elementDeclarations = null;
12332 };
12333
12334 function installPolymerWarning() {
12335 if (window.Polymer === polymerStub) {
12336 window.Polymer = function() {
12337 throw new Error('You tried to use polymer without loading it first. To ' +
12338 'load polymer, <link rel="import" href="' +
12339 'components/polymer/polymer.html">');
12340 };
12341 }
12342 }
12343
12344 // Once DOMContent has loaded, any main document scripts that depend on
12345 // Polymer() should have run. Calling Polymer() now is an error until
12346 // polymer is imported.
12347 if (HTMLImports.useNative) {
12348 installPolymerWarning();
12349 } else {
12350 addEventListener('DOMContentLoaded', installPolymerWarning);
12351 }
12352
12353 })(window.Platform);
12354
12355 /*
12356 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
12357 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
12358 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
12359 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
12360 * Code distributed by Google as part of the polymer project is also
12361 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
12362 */
12363
12364 (function(scope) {
12365
12366 // It's desireable to provide a default stylesheet
12367 // that's convenient for styling unresolved elements, but
12368 // it's cumbersome to have to include this manually in every page.
12369 // It would make sense to put inside some HTMLImport but
12370 // the HTMLImports polyfill does not allow loading of stylesheets
12371 // that block rendering. Therefore this injection is tolerated here.
12372 //
12373 // NOTE: position: relative fixes IE's failure to inherit opacity
12374 // when a child is not statically positioned.
12375 var style = document.createElement('style');
12376 style.textContent = ''
12377 + 'body {'
12378 + 'transition: opacity ease-in 0.2s;'
12379 + ' } \n'
12380 + 'body[unresolved] {'
12381 + 'opacity: 0; display: block; overflow: hidden; position: relative;'
12382 + ' } \n'
12383 ;
12384 var head = document.querySelector('head');
12385 head.insertBefore(style, head.firstChild);
12386
12387 })(Platform);
12388
12389 /*
12390 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
12391 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
12392 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
12393 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
12394 * Code distributed by Google as part of the polymer project is also
12395 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
12396 */
12397
12398 (function(scope) {
12399
12400 function withDependencies(task, depends) {
12401 depends = depends || [];
12402 if (!depends.map) {
12403 depends = [depends];
12404 }
12405 return task.apply(this, depends.map(marshal));
12406 }
12407
12408 function module(name, dependsOrFactory, moduleFactory) {
12409 var module;
12410 switch (arguments.length) {
12411 case 0:
12412 return;
12413 case 1:
12414 module = null;
12415 break;
12416 case 2:
12417 // dependsOrFactory is `factory` in this case
12418 module = dependsOrFactory.apply(this);
12419 break;
12420 default:
12421 // dependsOrFactory is `depends` in this case
12422 module = withDependencies(moduleFactory, dependsOrFactory);
12423 break;
12424 }
12425 modules[name] = module;
12426 };
12427
12428 function marshal(name) {
12429 return modules[name];
12430 }
12431
12432 var modules = {};
12433
12434 function using(depends, task) {
12435 HTMLImports.whenImportsReady(function() {
12436 withDependencies(task, depends);
12437 });
12438 };
12439
12440 // exports
12441
12442 scope.marshal = marshal;
12443 // `module` confuses commonjs detectors
12444 scope.modularize = module;
12445 scope.using = using;
12446
12447 })(window);
12448
12449 //# sourceMappingURL=platform.concat.js.map
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698