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

Side by Side Diff: pkg/web_components/lib/platform.concat.js

Issue 335943003: merge to trunk all changes from 36817 until 37378 under the packages: polymer, (Closed) Base URL: http://dart.googlecode.com/svn/trunk/dart/
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/web_components/lib/platform.js ('k') | pkg/web_components/pubspec.yaml » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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.warn('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
1 /* 69 /*
2 * Copyright 2012 The Polymer Authors. All rights reserved. 70 * Copyright 2012 The Polymer Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style 71 * Use of this source code is governed by a BSD-style
4 * license that can be found in the LICENSE file. 72 * license that can be found in the LICENSE file.
5 */ 73 */
6 74
7 if (typeof WeakMap === 'undefined') { 75 if (typeof WeakMap === 'undefined') {
8 (function() { 76 (function() {
9 var defineProperty = Object.defineProperty; 77 var defineProperty = Object.defineProperty;
10 var counter = Date.now() % 1e9; 78 var counter = Date.now() % 1e9;
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 157
90 Object.unobserve(test, callback); 158 Object.unobserve(test, callback);
91 Array.unobserve(arr, callback); 159 Array.unobserve(arr, callback);
92 160
93 return true; 161 return true;
94 } 162 }
95 163
96 var hasObserve = detectObjectObserve(); 164 var hasObserve = detectObjectObserve();
97 165
98 function detectEval() { 166 function detectEval() {
99 // don't test for eval if document has CSP securityPolicy object and we can see that 167 // Don't test for eval if we're running in a Chrome App environment.
100 // eval is not supported. This avoids an error message in console even when the exception 168 // We check for APIs set that only exist in a Chrome App context.
101 // is caught 169 if (typeof chrome !== 'undefined' && chrome.app && chrome.app.runtime) {
102 if (global.document &&
103 'securityPolicy' in global.document &&
104 !global.document.securityPolicy.allowsEval) {
105 return false; 170 return false;
106 } 171 }
107 172
108 try { 173 try {
109 var f = new Function('', 'return true;'); 174 var f = new Function('', 'return true;');
110 return f(); 175 return f();
111 } catch (ex) { 176 } catch (ex) {
112 return false; 177 return false;
113 } 178 }
114 } 179 }
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
242 } 307 }
243 return obj; 308 return obj;
244 }, 309 },
245 310
246 iterateObjects: function(obj, observe) { 311 iterateObjects: function(obj, observe) {
247 for (var i = 0; i < this.length; i++) { 312 for (var i = 0; i < this.length; i++) {
248 if (i) 313 if (i)
249 obj = obj[this[i - 1]]; 314 obj = obj[this[i - 1]];
250 if (!isObject(obj)) 315 if (!isObject(obj))
251 return; 316 return;
252 observe(obj); 317 observe(obj, this[0]);
253 } 318 }
254 }, 319 },
255 320
256 compiledGetValueFromFn: function() { 321 compiledGetValueFromFn: function() {
257 var accessors = this.map(function(ident) { 322 var accessors = this.map(function(ident) {
258 return isIndex(ident) ? '["' + ident + '"]' : '.' + ident; 323 return isIndex(ident) ? '["' + ident + '"]' : '.' + ident;
259 }); 324 });
260 325
261 var str = ''; 326 var str = '';
262 var pathString = 'obj'; 327 var pathString = 'obj';
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after
431 discardRecords = false; 496 discardRecords = false;
432 }, 497 },
433 close: function() { 498 close: function() {
434 observer = undefined; 499 observer = undefined;
435 Object.unobserve(object, callback); 500 Object.unobserve(object, callback);
436 observedObjectCache.push(this); 501 observedObjectCache.push(this);
437 } 502 }
438 }; 503 };
439 } 504 }
440 505
506 /*
507 * The observedSet abstraction is a perf optimization which reduces the total
508 * number of Object.observe observations of a set of objects. The idea is that
509 * groups of Observers will have some object dependencies in common and this
510 * observed set ensures that each object in the transitive closure of
511 * dependencies is only observed once. The observedSet acts as a write barrier
512 * such that whenever any change comes through, all Observers are checked for
513 * changed values.
514 *
515 * Note that this optimization is explicitly moving work from setup-time to
516 * change-time.
517 *
518 * TODO(rafaelw): Implement "garbage collection". In order to move work off
519 * the critical path, when Observers are closed, their observed objects are
520 * not Object.unobserve(d). As a result, it's possible that if the observedSet
521 * is kept open, but some Observers have been closed, it could cause "leaks"
522 * (prevent otherwise collectable objects from being collected). At some
523 * point, we should implement incremental "gc" which keeps a list of
524 * observedSets which may need clean-up and does small amounts of cleanup on a
525 * timeout until all is clean.
526 */
527
441 function getObservedObject(observer, object, arrayObserve) { 528 function getObservedObject(observer, object, arrayObserve) {
442 var dir = observedObjectCache.pop() || newObservedObject(); 529 var dir = observedObjectCache.pop() || newObservedObject();
443 dir.open(observer); 530 dir.open(observer);
444 dir.observe(object, arrayObserve); 531 dir.observe(object, arrayObserve);
445 return dir; 532 return dir;
446 } 533 }
447 534
448 var emptyArray = [];
449 var observedSetCache = []; 535 var observedSetCache = [];
450 536
451 function newObservedSet() { 537 function newObservedSet() {
538 var observerCount = 0;
452 var observers = []; 539 var observers = [];
453 var observerCount = 0;
454 var objects = []; 540 var objects = [];
455 var toRemove = emptyArray; 541 var rootObj;
456 var resetNeeded = false; 542 var rootObjProps;
457 var resetScheduled = false;
458 543
459 function observe(obj) { 544 function observe(obj, prop) {
460 if (!obj) 545 if (!obj)
461 return; 546 return;
462 547
463 var index = toRemove.indexOf(obj); 548 if (obj === rootObj)
464 if (index >= 0) { 549 rootObjProps[prop] = true;
465 toRemove[index] = undefined; 550
466 objects.push(obj); 551 if (objects.indexOf(obj) < 0) {
467 } else if (objects.indexOf(obj) < 0) {
468 objects.push(obj); 552 objects.push(obj);
469 Object.observe(obj, callback); 553 Object.observe(obj, callback);
470 } 554 }
471 555
472 observe(Object.getPrototypeOf(obj)); 556 observe(Object.getPrototypeOf(obj), prop);
473 } 557 }
474 558
475 function reset() { 559 function allRootObjNonObservedProps(recs) {
476 var objs = toRemove === emptyArray ? [] : toRemove; 560 for (var i = 0; i < recs.length; i++) {
477 toRemove = objects; 561 var rec = recs[i];
478 objects = objs; 562 if (rec.object !== rootObj ||
563 rootObjProps[rec.name] ||
564 rec.type === 'setPrototype') {
565 return false;
566 }
567 }
568 return true;
569 }
570
571 function callback(recs) {
572 if (allRootObjNonObservedProps(recs))
573 return;
479 574
480 var observer; 575 var observer;
481 for (var id in observers) { 576 for (var i = 0; i < observers.length; i++) {
482 observer = observers[id]; 577 observer = observers[i];
483 if (!observer || observer.state_ != OPENED) 578 if (observer.state_ == OPENED) {
484 continue; 579 observer.iterateObjects_(observe);
485 580 }
486 observer.iterateObjects_(observe);
487 } 581 }
488 582
489 for (var i = 0; i < toRemove.length; i++) { 583 for (var i = 0; i < observers.length; i++) {
490 var obj = toRemove[i]; 584 observer = observers[i];
491 if (obj) 585 if (observer.state_ == OPENED) {
492 Object.unobserve(obj, callback); 586 observer.check_();
493 } 587 }
494
495 toRemove.length = 0;
496 }
497
498 function scheduledReset() {
499 resetScheduled = false;
500 if (!resetNeeded)
501 return;
502
503 reset();
504 }
505
506 function scheduleReset() {
507 if (resetScheduled)
508 return;
509
510 resetNeeded = true;
511 resetScheduled = true;
512 runEOM(scheduledReset);
513 }
514
515 function callback() {
516 reset();
517
518 var observer;
519
520 for (var id in observers) {
521 observer = observers[id];
522 if (!observer || observer.state_ != OPENED)
523 continue;
524
525 observer.check_();
526 } 588 }
527 } 589 }
528 590
529 var record = { 591 var record = {
530 object: undefined, 592 object: undefined,
531 objects: objects, 593 objects: objects,
532 open: function(obs) { 594 open: function(obs, object) {
533 observers[obs.id_] = obs; 595 if (!rootObj) {
596 rootObj = object;
597 rootObjProps = {};
598 }
599
600 observers.push(obs);
534 observerCount++; 601 observerCount++;
535 obs.iterateObjects_(observe); 602 obs.iterateObjects_(observe);
536 }, 603 },
537 close: function(obs) { 604 close: function(obs) {
538 var anyLeft = false;
539
540 observers[obs.id_] = undefined;
541 observerCount--; 605 observerCount--;
542 606 if (observerCount > 0) {
543 if (observerCount) {
544 scheduleReset();
545 return; 607 return;
546 } 608 }
547 resetNeeded = false;
548 609
549 for (var i = 0; i < objects.length; i++) { 610 for (var i = 0; i < objects.length; i++) {
550 Object.unobserve(objects[i], callback); 611 Object.unobserve(objects[i], callback);
551 Observer.unobservedCount++; 612 Observer.unobservedCount++;
552 } 613 }
553 614
554 observers.length = 0; 615 observers.length = 0;
555 objects.length = 0; 616 objects.length = 0;
617 rootObj = undefined;
618 rootObjProps = undefined;
556 observedSetCache.push(this); 619 observedSetCache.push(this);
557 }, 620 }
558 reset: scheduleReset
559 }; 621 };
560 622
561 return record; 623 return record;
562 } 624 }
563 625
564 var lastObservedSet; 626 var lastObservedSet;
565 627
566 function getObservedSet(observer, obj) { 628 function getObservedSet(observer, obj) {
567 if (!lastObservedSet || lastObservedSet.object !== obj) { 629 if (!lastObservedSet || lastObservedSet.object !== obj) {
568 lastObservedSet = observedSetCache.pop() || newObservedSet(); 630 lastObservedSet = observedSetCache.pop() || newObservedSet();
569 lastObservedSet.object = obj; 631 lastObservedSet.object = obj;
570 } 632 }
571 lastObservedSet.open(observer); 633 lastObservedSet.open(observer, obj);
572 return lastObservedSet; 634 return lastObservedSet;
573 } 635 }
574 636
575 var UNOPENED = 0; 637 var UNOPENED = 0;
576 var OPENED = 1; 638 var OPENED = 1;
577 var CLOSED = 2; 639 var CLOSED = 2;
578 var RESETTING = 3; 640 var RESETTING = 3;
579 641
580 var nextObserverId = 1; 642 var nextObserverId = 1;
581 643
582 function Observer() { 644 function Observer() {
583 this.state_ = UNOPENED; 645 this.state_ = UNOPENED;
584 this.callback_ = undefined; 646 this.callback_ = undefined;
585 this.target_ = undefined; // TODO(rafaelw): Should be WeakRef 647 this.target_ = undefined; // TODO(rafaelw): Should be WeakRef
586 this.directObserver_ = undefined; 648 this.directObserver_ = undefined;
587 this.value_ = undefined; 649 this.value_ = undefined;
588 this.id_ = nextObserverId++; 650 this.id_ = nextObserverId++;
589 } 651 }
590 652
591 Observer.prototype = { 653 Observer.prototype = {
592 open: function(callback, target) { 654 open: function(callback, target) {
593 if (this.state_ != UNOPENED) 655 if (this.state_ != UNOPENED)
594 throw Error('Observer has already been opened.'); 656 throw Error('Observer has already been opened.');
595 657
596 addToAll(this); 658 addToAll(this);
597 this.callback_ = callback; 659 this.callback_ = callback;
598 this.target_ = target; 660 this.target_ = target;
661 this.connect_();
599 this.state_ = OPENED; 662 this.state_ = OPENED;
600 this.connect_();
601 return this.value_; 663 return this.value_;
602 }, 664 },
603 665
604 close: function() { 666 close: function() {
605 if (this.state_ != OPENED) 667 if (this.state_ != OPENED)
606 return; 668 return;
607 669
608 removeFromAll(this); 670 removeFromAll(this);
609 this.state_ = CLOSED;
610 this.disconnect_(); 671 this.disconnect_();
611 this.value_ = undefined; 672 this.value_ = undefined;
612 this.callback_ = undefined; 673 this.callback_ = undefined;
613 this.target_ = undefined; 674 this.target_ = undefined;
675 this.state_ = CLOSED;
614 }, 676 },
615 677
616 deliver: function() { 678 deliver: function() {
617 if (this.state_ != OPENED) 679 if (this.state_ != OPENED)
618 return; 680 return;
619 681
620 dirtyCheck(this); 682 dirtyCheck(this);
621 }, 683 },
622 684
623 report_: function(changes) { 685 report_: function(changes) {
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after
859 } 921 }
860 922
861 Array.prototype.splice.apply(previous, spliceArgs); 923 Array.prototype.splice.apply(previous, spliceArgs);
862 }); 924 });
863 }; 925 };
864 926
865 function PathObserver(object, path) { 927 function PathObserver(object, path) {
866 Observer.call(this); 928 Observer.call(this);
867 929
868 this.object_ = object; 930 this.object_ = object;
869 this.path_ = path instanceof Path ? path : getPath(path); 931 this.path_ = getPath(path);
870 this.directObserver_ = undefined; 932 this.directObserver_ = undefined;
871 } 933 }
872 934
873 PathObserver.prototype = createObject({ 935 PathObserver.prototype = createObject({
874 __proto__: Observer.prototype, 936 __proto__: Observer.prototype,
875 937
876 connect_: function() { 938 connect_: function() {
877 if (hasObserve) 939 if (hasObserve)
878 this.directObserver_ = getObservedSet(this, this.object_); 940 this.directObserver_ = getObservedSet(this, this.object_);
879 941
(...skipping 22 matching lines...) Expand all
902 this.report_([this.value_, oldValue]); 964 this.report_([this.value_, oldValue]);
903 return true; 965 return true;
904 }, 966 },
905 967
906 setValue: function(newValue) { 968 setValue: function(newValue) {
907 if (this.path_) 969 if (this.path_)
908 this.path_.setValueFrom(this.object_, newValue); 970 this.path_.setValueFrom(this.object_, newValue);
909 } 971 }
910 }); 972 });
911 973
912 function CompoundObserver() { 974 function CompoundObserver(reportChangesOnOpen) {
913 Observer.call(this); 975 Observer.call(this);
914 976
977 this.reportChangesOnOpen_ = reportChangesOnOpen;
915 this.value_ = []; 978 this.value_ = [];
916 this.directObserver_ = undefined; 979 this.directObserver_ = undefined;
917 this.observed_ = []; 980 this.observed_ = [];
918 } 981 }
919 982
920 var observerSentinel = {}; 983 var observerSentinel = {};
921 984
922 CompoundObserver.prototype = createObject({ 985 CompoundObserver.prototype = createObject({
923 __proto__: Observer.prototype, 986 __proto__: Observer.prototype,
924 987
925 connect_: function() { 988 connect_: function() {
926 this.check_(undefined, true); 989 if (hasObserve) {
990 var object;
991 var needsDirectObserver = false;
992 for (var i = 0; i < this.observed_.length; i += 2) {
993 object = this.observed_[i]
994 if (object !== observerSentinel) {
995 needsDirectObserver = true;
996 break;
997 }
998 }
927 999
928 if (!hasObserve) 1000 if (needsDirectObserver)
929 return; 1001 this.directObserver_ = getObservedSet(this, object);
930
931 var object;
932 var needsDirectObserver = false;
933 for (var i = 0; i < this.observed_.length; i += 2) {
934 object = this.observed_[i]
935 if (object !== observerSentinel) {
936 needsDirectObserver = true;
937 break;
938 }
939 } 1002 }
940 1003
941 if (this.directObserver_) { 1004 this.check_(undefined, !this.reportChangesOnOpen_);
942 if (needsDirectObserver) {
943 this.directObserver_.reset();
944 return;
945 }
946 this.directObserver_.close();
947 this.directObserver_ = undefined;
948 return;
949 }
950
951 if (needsDirectObserver)
952 this.directObserver_ = getObservedSet(this, object);
953 }, 1005 },
954 1006
955 closeObservers_: function() { 1007 disconnect_: function() {
956 for (var i = 0; i < this.observed_.length; i += 2) { 1008 for (var i = 0; i < this.observed_.length; i += 2) {
957 if (this.observed_[i] === observerSentinel) 1009 if (this.observed_[i] === observerSentinel)
958 this.observed_[i + 1].close(); 1010 this.observed_[i + 1].close();
959 } 1011 }
960 this.observed_.length = 0; 1012 this.observed_.length = 0;
961 }, 1013 this.value_.length = 0;
962
963 disconnect_: function() {
964 this.value_ = undefined;
965 1014
966 if (this.directObserver_) { 1015 if (this.directObserver_) {
967 this.directObserver_.close(this); 1016 this.directObserver_.close(this);
968 this.directObserver_ = undefined; 1017 this.directObserver_ = undefined;
969 } 1018 }
970
971 this.closeObservers_();
972 }, 1019 },
973 1020
974 addPath: function(object, path) { 1021 addPath: function(object, path) {
975 if (this.state_ != UNOPENED && this.state_ != RESETTING) 1022 if (this.state_ != UNOPENED && this.state_ != RESETTING)
976 throw Error('Cannot add paths once started.'); 1023 throw Error('Cannot add paths once started.');
977 1024
978 this.observed_.push(object, path instanceof Path ? path : getPath(path)); 1025 var path = getPath(path);
1026 this.observed_.push(object, path);
1027 if (!this.reportChangesOnOpen_)
1028 return;
1029 var index = this.observed_.length / 2 - 1;
1030 this.value_[index] = path.getValueFrom(object);
979 }, 1031 },
980 1032
981 addObserver: function(observer) { 1033 addObserver: function(observer) {
982 if (this.state_ != UNOPENED && this.state_ != RESETTING) 1034 if (this.state_ != UNOPENED && this.state_ != RESETTING)
983 throw Error('Cannot add observers once started.'); 1035 throw Error('Cannot add observers once started.');
984 1036
985 observer.open(this.deliver, this);
986 this.observed_.push(observerSentinel, observer); 1037 this.observed_.push(observerSentinel, observer);
1038 if (!this.reportChangesOnOpen_)
1039 return;
1040 var index = this.observed_.length / 2 - 1;
1041 this.value_[index] = observer.open(this.deliver, this);
987 }, 1042 },
988 1043
989 startReset: function() { 1044 startReset: function() {
990 if (this.state_ != OPENED) 1045 if (this.state_ != OPENED)
991 throw Error('Can only reset while open'); 1046 throw Error('Can only reset while open');
992 1047
993 this.state_ = RESETTING; 1048 this.state_ = RESETTING;
994 this.closeObservers_(); 1049 this.disconnect_();
995 }, 1050 },
996 1051
997 finishReset: function() { 1052 finishReset: function() {
998 if (this.state_ != RESETTING) 1053 if (this.state_ != RESETTING)
999 throw Error('Can only finishReset after startReset'); 1054 throw Error('Can only finishReset after startReset');
1000 this.state_ = OPENED; 1055 this.state_ = OPENED;
1001 this.connect_(); 1056 this.connect_();
1002 1057
1003 return this.value_; 1058 return this.value_;
1004 }, 1059 },
1005 1060
1006 iterateObjects_: function(observe) { 1061 iterateObjects_: function(observe) {
1007 var object; 1062 var object;
1008 for (var i = 0; i < this.observed_.length; i += 2) { 1063 for (var i = 0; i < this.observed_.length; i += 2) {
1009 object = this.observed_[i] 1064 object = this.observed_[i]
1010 if (object !== observerSentinel) 1065 if (object !== observerSentinel)
1011 this.observed_[i + 1].iterateObjects(object, observe) 1066 this.observed_[i + 1].iterateObjects(object, observe)
1012 } 1067 }
1013 }, 1068 },
1014 1069
1015 check_: function(changeRecords, skipChanges) { 1070 check_: function(changeRecords, skipChanges) {
1016 var oldValues; 1071 var oldValues;
1017 for (var i = 0; i < this.observed_.length; i += 2) { 1072 for (var i = 0; i < this.observed_.length; i += 2) {
1018 var pathOrObserver = this.observed_[i+1];
1019 var object = this.observed_[i]; 1073 var object = this.observed_[i];
1020 var value = object === observerSentinel ? 1074 var path = this.observed_[i+1];
1021 pathOrObserver.discardChanges() : 1075 var value;
1022 pathOrObserver.getValueFrom(object) 1076 if (object === observerSentinel) {
1077 var observable = path;
1078 value = this.state_ === UNOPENED ?
1079 observable.open(this.deliver, this) :
1080 observable.discardChanges();
1081 } else {
1082 value = path.getValueFrom(object);
1083 }
1023 1084
1024 if (skipChanges) { 1085 if (skipChanges) {
1025 this.value_[i / 2] = value; 1086 this.value_[i / 2] = value;
1026 continue; 1087 continue;
1027 } 1088 }
1028 1089
1029 if (areSameValue(value, this.value_[i / 2])) 1090 if (areSameValue(value, this.value_[i / 2]))
1030 continue; 1091 continue;
1031 1092
1032 oldValues = oldValues || []; 1093 oldValues = oldValues || [];
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
1103 this.setValueFn_ = undefined; 1164 this.setValueFn_ = undefined;
1104 } 1165 }
1105 } 1166 }
1106 1167
1107 var expectedRecordTypes = { 1168 var expectedRecordTypes = {
1108 add: true, 1169 add: true,
1109 update: true, 1170 update: true,
1110 delete: true 1171 delete: true
1111 }; 1172 };
1112 1173
1113 function notifyFunction(object, name) { 1174 var updateRecord = {
1114 if (typeof Object.observe !== 'function') 1175 object: undefined,
1176 type: 'update',
1177 name: undefined,
1178 oldValue: undefined
1179 };
1180
1181 function notify(object, name, value, oldValue) {
1182 if (areSameValue(value, oldValue))
1115 return; 1183 return;
1116 1184
1117 var notifier = Object.getNotifier(object); 1185 // TODO(rafaelw): Hack hack hack. This entire code really needs to move
1118 return function(type, oldValue) { 1186 // out of observe-js into polymer.
1119 var changeRecord = { 1187 if (typeof object.propertyChanged_ == 'function')
1120 object: object, 1188 object.propertyChanged_(name, value, oldValue);
1121 type: type, 1189
1122 name: name 1190 if (!hasObserve)
1123 }; 1191 return;
1124 if (arguments.length === 2) 1192
1125 changeRecord.oldValue = oldValue; 1193 var notifier = object.notifier_;
1126 notifier.notify(changeRecord); 1194 if (!notifier)
1127 } 1195 notifier = object.notifier_ = Object.getNotifier(object);
1196
1197 updateRecord.object = object;
1198 updateRecord.name = name;
1199 updateRecord.oldValue = oldValue;
1200
1201 notifier.notify(updateRecord);
1128 } 1202 }
1129 1203
1130 Observer.defineComputedProperty = function(target, name, observable) { 1204 Observer.createBindablePrototypeAccessor = function(proto, name) {
1131 var notify = notifyFunction(target, name); 1205 var privateName = name + '_';
1132 var value = observable.open(function(newValue, oldValue) { 1206 var privateObservable = name + 'Observable_';
1133 value = newValue;
1134 if (notify)
1135 notify('update', oldValue);
1136 });
1137 1207
1138 Object.defineProperty(target, name, { 1208 proto[privateName] = proto[name];
1209
1210 Object.defineProperty(proto, name, {
1139 get: function() { 1211 get: function() {
1140 observable.deliver(); 1212 var observable = this[privateObservable];
1213 if (observable)
1214 observable.deliver();
1215
1216 return this[privateName];
1217 },
1218 set: function(value) {
1219 var observable = this[privateObservable];
1220 if (observable) {
1221 observable.setValue(value);
1222 return;
1223 }
1224
1225 var oldValue = this[privateName];
1226 this[privateName] = value;
1227 notify(this, name, value, oldValue);
1228
1141 return value; 1229 return value;
1142 }, 1230 },
1143 set: function(newValue) {
1144 observable.setValue(newValue);
1145 return newValue;
1146 },
1147 configurable: true 1231 configurable: true
1148 }); 1232 });
1233 }
1234
1235 Observer.bindToInstance = function(instance, name, observable, resolveFn) {
1236 var privateName = name + '_';
1237 var privateObservable = name + 'Observable_';
1238
1239 instance[privateObservable] = observable;
1240 var oldValue = instance[privateName];
1241 var value = observable.open(function(value, oldValue) {
1242 instance[privateName] = value;
1243 notify(instance, name, value, oldValue);
1244 });
1245
1246 if (resolveFn && !areSameValue(oldValue, value)) {
1247 var resolvedValue = resolveFn(oldValue, value);
1248 if (!areSameValue(value, resolvedValue)) {
1249 value = resolvedValue;
1250 if (observable.setValue)
1251 observable.setValue(value);
1252 }
1253 }
1254
1255 instance[privateName] = value;
1256 notify(instance, name, value, oldValue);
1149 1257
1150 return { 1258 return {
1151 close: function() { 1259 close: function() {
1152 observable.close(); 1260 observable.close();
1153 Object.defineProperty(target, name, { 1261 instance[privateObservable] = undefined;
1154 value: value,
1155 writable: true,
1156 configurable: true
1157 });
1158 } 1262 }
1159 }; 1263 };
1160 } 1264 }
1161 1265
1162 function diffObjectFromChangeRecords(object, changeRecords, oldValues) { 1266 function diffObjectFromChangeRecords(object, changeRecords, oldValues) {
1163 var added = {}; 1267 var added = {};
1164 var removed = {}; 1268 var removed = {};
1165 1269
1166 for (var i = 0; i < changeRecords.length; i++) { 1270 for (var i = 0; i < changeRecords.length; i++) {
1167 var record = changeRecords[i]; 1271 var record = changeRecords[i];
(...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after
1609 1713
1610 splices = splices.concat(calcSplices(array, splice.index, splice.index + s plice.addedCount, 1714 splices = splices.concat(calcSplices(array, splice.index, splice.index + s plice.addedCount,
1611 splice.removed, 0, splice.removed.len gth)); 1715 splice.removed, 0, splice.removed.len gth));
1612 }); 1716 });
1613 1717
1614 return splices; 1718 return splices;
1615 } 1719 }
1616 1720
1617 global.Observer = Observer; 1721 global.Observer = Observer;
1618 global.Observer.runEOM_ = runEOM; 1722 global.Observer.runEOM_ = runEOM;
1723 global.Observer.observerSentinel_ = observerSentinel; // for testing.
1619 global.Observer.hasObjectObserve = hasObserve; 1724 global.Observer.hasObjectObserve = hasObserve;
1620 global.ArrayObserver = ArrayObserver; 1725 global.ArrayObserver = ArrayObserver;
1621 global.ArrayObserver.calculateSplices = function(current, previous) { 1726 global.ArrayObserver.calculateSplices = function(current, previous) {
1622 return arraySplice.calculateSplices(current, previous); 1727 return arraySplice.calculateSplices(current, previous);
1623 }; 1728 };
1624 1729
1625 global.ArraySplice = ArraySplice; 1730 global.ArraySplice = ArraySplice;
1626 global.ObjectObserver = ObjectObserver; 1731 global.ObjectObserver = ObjectObserver;
1627 global.PathObserver = PathObserver; 1732 global.PathObserver = PathObserver;
1628 global.CompoundObserver = CompoundObserver; 1733 global.CompoundObserver = CompoundObserver;
1629 global.Path = Path; 1734 global.Path = Path;
1630 global.ObserverTransform = ObserverTransform; 1735 global.ObserverTransform = ObserverTransform;
1631 })(typeof global !== 'undefined' && global && typeof module !== 'undefined' && m odule ? global : this || window); 1736 })(typeof global !== 'undefined' && global && typeof module !== 'undefined' && m odule ? global : this || window);
1632 1737
1633 // prepoulate window.Platform.flags for default controls
1634 window.Platform = window.Platform || {};
1635 // prepopulate window.logFlags if necessary
1636 window.logFlags = window.logFlags || {};
1637 // process flags
1638 (function(scope){
1639 // import
1640 var flags = scope.flags || {};
1641 // populate flags from location
1642 location.search.slice(1).split('&').forEach(function(o) {
1643 o = o.split('=');
1644 o[0] && (flags[o[0]] = o[1] || true);
1645 });
1646 var entryPoint = document.currentScript ||
1647 document.querySelector('script[src*="platform.js"]');
1648 if (entryPoint) {
1649 var a = entryPoint.attributes;
1650 for (var i = 0, n; i < a.length; i++) {
1651 n = a[i];
1652 if (n.name !== 'src') {
1653 flags[n.name] = n.value || true;
1654 }
1655 }
1656 }
1657 if (flags.log) {
1658 flags.log.split(',').forEach(function(f) {
1659 window.logFlags[f] = true;
1660 });
1661 }
1662 // If any of these flags match 'native', then force native ShadowDOM; any
1663 // other truthy value, or failure to detect native
1664 // ShadowDOM, results in polyfill
1665 flags.shadow = flags.shadow || flags.shadowdom || flags.polyfill;
1666 if (flags.shadow === 'native') {
1667 flags.shadow = false;
1668 } else {
1669 flags.shadow = flags.shadow || !HTMLElement.prototype.createShadowRoot;
1670 }
1671
1672 if (flags.shadow && document.querySelectorAll('script').length > 1) {
1673 console.warn('platform.js is not the first script on the page. ' +
1674 'See http://www.polymer-project.org/docs/start/platform.html#setup ' +
1675 'for details.');
1676 }
1677
1678 // CustomElements polyfill flag
1679 if (flags.register) {
1680 window.CustomElements = window.CustomElements || {flags: {}};
1681 window.CustomElements.flags.register = flags.register;
1682 }
1683
1684 if (flags.imports) {
1685 window.HTMLImports = window.HTMLImports || {flags: {}};
1686 window.HTMLImports.flags.imports = flags.imports;
1687 }
1688
1689 // export
1690 scope.flags = flags;
1691 })(Platform);
1692
1693 // select ShadowDOM impl 1738 // select ShadowDOM impl
1694 if (Platform.flags.shadow) { 1739 if (Platform.flags.shadow) {
1695 1740
1696 // Copyright 2012 The Polymer Authors. All rights reserved. 1741 // Copyright 2012 The Polymer Authors. All rights reserved.
1697 // Use of this source code is goverened by a BSD-style 1742 // Use of this source code is goverened by a BSD-style
1698 // license that can be found in the LICENSE file. 1743 // license that can be found in the LICENSE file.
1699 1744
1700 window.ShadowDOMPolyfill = {}; 1745 window.ShadowDOMPolyfill = {};
1701 1746
1702 (function(scope) { 1747 (function(scope) {
1703 'use strict'; 1748 'use strict';
1704 1749
1705 var constructorTable = new WeakMap(); 1750 var constructorTable = new WeakMap();
1706 var nativePrototypeTable = new WeakMap(); 1751 var nativePrototypeTable = new WeakMap();
1707 var wrappers = Object.create(null); 1752 var wrappers = Object.create(null);
1708 1753
1709 // Don't test for eval if document has CSP securityPolicy object and we can 1754 function detectEval() {
1710 // see that eval is not supported. This avoids an error message in console 1755 // Don't test for eval if we're running in a Chrome App environment.
1711 // even when the exception is caught 1756 // We check for APIs set that only exist in a Chrome App context.
1712 var hasEval = !('securityPolicy' in document) || 1757 if (typeof chrome !== 'undefined' && chrome.app && chrome.app.runtime) {
1713 document.securityPolicy.allowsEval; 1758 return false;
1714 if (hasEval) { 1759 }
1760
1715 try { 1761 try {
1716 var f = new Function('', 'return true;'); 1762 var f = new Function('return true;');
1717 hasEval = f(); 1763 return f();
1718 } catch (ex) { 1764 } catch (ex) {
1719 hasEval = false; 1765 return false;
1720 } 1766 }
1721 } 1767 }
1722 1768
1769 var hasEval = detectEval();
1770
1723 function assert(b) { 1771 function assert(b) {
1724 if (!b) 1772 if (!b)
1725 throw new Error('Assertion failed'); 1773 throw new Error('Assertion failed');
1726 }; 1774 };
1727 1775
1728 var defineProperty = Object.defineProperty; 1776 var defineProperty = Object.defineProperty;
1729 var getOwnPropertyNames = Object.getOwnPropertyNames; 1777 var getOwnPropertyNames = Object.getOwnPropertyNames;
1730 var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; 1778 var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
1731 1779
1732 function mixin(to, from) { 1780 function mixin(to, from) {
1733 getOwnPropertyNames(from).forEach(function(name) { 1781 var names = getOwnPropertyNames(from);
1782 for (var i = 0; i < names.length; i++) {
1783 var name = names[i];
1734 defineProperty(to, name, getOwnPropertyDescriptor(from, name)); 1784 defineProperty(to, name, getOwnPropertyDescriptor(from, name));
1735 }); 1785 }
1736 return to; 1786 return to;
1737 }; 1787 };
1738 1788
1739 function mixinStatics(to, from) { 1789 function mixinStatics(to, from) {
1740 getOwnPropertyNames(from).forEach(function(name) { 1790 var names = getOwnPropertyNames(from);
1791 for (var i = 0; i < names.length; i++) {
1792 var name = names[i];
1741 switch (name) { 1793 switch (name) {
1742 case 'arguments': 1794 case 'arguments':
1743 case 'caller': 1795 case 'caller':
1744 case 'length': 1796 case 'length':
1745 case 'name': 1797 case 'name':
1746 case 'prototype': 1798 case 'prototype':
1747 case 'toString': 1799 case 'toString':
1748 return; 1800 continue;
1749 } 1801 }
1750 defineProperty(to, name, getOwnPropertyDescriptor(from, name)); 1802 defineProperty(to, name, getOwnPropertyDescriptor(from, name));
1751 }); 1803 }
1752 return to; 1804 return to;
1753 }; 1805 };
1754 1806
1755 function oneOf(object, propertyNames) { 1807 function oneOf(object, propertyNames) {
1756 for (var i = 0; i < propertyNames.length; i++) { 1808 for (var i = 0; i < propertyNames.length; i++) {
1757 if (propertyNames[i] in object) 1809 if (propertyNames[i] in object)
1758 return propertyNames[i]; 1810 return propertyNames[i];
1759 } 1811 }
1760 } 1812 }
1761 1813
1814 var nonEnumerableDataDescriptor = {
1815 value: undefined,
1816 configurable: true,
1817 enumerable: false,
1818 writable: true
1819 };
1820
1821 function defineNonEnumerableDataProperty(object, name, value) {
1822 nonEnumerableDataDescriptor.value = value;
1823 defineProperty(object, name, nonEnumerableDataDescriptor);
1824 }
1825
1762 // Mozilla's old DOM bindings are bretty busted: 1826 // Mozilla's old DOM bindings are bretty busted:
1763 // https://bugzilla.mozilla.org/show_bug.cgi?id=855844 1827 // https://bugzilla.mozilla.org/show_bug.cgi?id=855844
1764 // Make sure they are create before we start modifying things. 1828 // Make sure they are create before we start modifying things.
1765 getOwnPropertyNames(window); 1829 getOwnPropertyNames(window);
1766 1830
1767 function getWrapperConstructor(node) { 1831 function getWrapperConstructor(node) {
1768 var nativePrototype = node.__proto__ || Object.getPrototypeOf(node); 1832 var nativePrototype = node.__proto__ || Object.getPrototypeOf(node);
1769 var wrapperConstructor = constructorTable.get(nativePrototype); 1833 var wrapperConstructor = constructorTable.get(nativePrototype);
1770 if (wrapperConstructor) 1834 if (wrapperConstructor)
1771 return wrapperConstructor; 1835 return wrapperConstructor;
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
1896 function registerInternal(nativePrototype, wrapperConstructor, opt_instance) { 1960 function registerInternal(nativePrototype, wrapperConstructor, opt_instance) {
1897 var wrapperPrototype = wrapperConstructor.prototype; 1961 var wrapperPrototype = wrapperConstructor.prototype;
1898 assert(constructorTable.get(nativePrototype) === undefined); 1962 assert(constructorTable.get(nativePrototype) === undefined);
1899 1963
1900 constructorTable.set(nativePrototype, wrapperConstructor); 1964 constructorTable.set(nativePrototype, wrapperConstructor);
1901 nativePrototypeTable.set(wrapperPrototype, nativePrototype); 1965 nativePrototypeTable.set(wrapperPrototype, nativePrototype);
1902 1966
1903 addForwardingProperties(nativePrototype, wrapperPrototype); 1967 addForwardingProperties(nativePrototype, wrapperPrototype);
1904 if (opt_instance) 1968 if (opt_instance)
1905 registerInstanceProperties(wrapperPrototype, opt_instance); 1969 registerInstanceProperties(wrapperPrototype, opt_instance);
1906 defineProperty(wrapperPrototype, 'constructor', { 1970
1907 value: wrapperConstructor, 1971 defineNonEnumerableDataProperty(
1908 configurable: true, 1972 wrapperPrototype, 'constructor', wrapperConstructor);
1909 enumerable: false,
1910 writable: true
1911 });
1912 // Set it again. Some VMs optimizes objects that are used as prototypes. 1973 // Set it again. Some VMs optimizes objects that are used as prototypes.
1913 wrapperConstructor.prototype = wrapperPrototype; 1974 wrapperConstructor.prototype = wrapperPrototype;
1914 } 1975 }
1915 1976
1916 function isWrapperFor(wrapperConstructor, nativeConstructor) { 1977 function isWrapperFor(wrapperConstructor, nativeConstructor) {
1917 return constructorTable.get(nativeConstructor.prototype) === 1978 return constructorTable.get(nativeConstructor.prototype) ===
1918 wrapperConstructor; 1979 wrapperConstructor;
1919 } 1980 }
1920 1981
1921 /** 1982 /**
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
2031 * needed next time someone wraps the node. 2092 * needed next time someone wraps the node.
2032 */ 2093 */
2033 function rewrap(node, wrapper) { 2094 function rewrap(node, wrapper) {
2034 if (wrapper === null) 2095 if (wrapper === null)
2035 return; 2096 return;
2036 assert(isNative(node)); 2097 assert(isNative(node));
2037 assert(wrapper === undefined || isWrapper(wrapper)); 2098 assert(wrapper === undefined || isWrapper(wrapper));
2038 node.polymerWrapper_ = wrapper; 2099 node.polymerWrapper_ = wrapper;
2039 } 2100 }
2040 2101
2102 var getterDescriptor = {
2103 get: undefined,
2104 configurable: true,
2105 enumerable: true
2106 };
2107
2041 function defineGetter(constructor, name, getter) { 2108 function defineGetter(constructor, name, getter) {
2042 defineProperty(constructor.prototype, name, { 2109 getterDescriptor.get = getter;
2043 get: getter, 2110 defineProperty(constructor.prototype, name, getterDescriptor);
2044 configurable: true,
2045 enumerable: true
2046 });
2047 } 2111 }
2048 2112
2049 function defineWrapGetter(constructor, name) { 2113 function defineWrapGetter(constructor, name) {
2050 defineGetter(constructor, name, function() { 2114 defineGetter(constructor, name, function() {
2051 return wrap(this.impl[name]); 2115 return wrap(this.impl[name]);
2052 }); 2116 });
2053 } 2117 }
2054 2118
2055 /** 2119 /**
2056 * Forwards existing methods on the native object to the wrapper methods. 2120 * Forwards existing methods on the native object to the wrapper methods.
(...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after
2520 * license that can be found in the LICENSE file. 2584 * license that can be found in the LICENSE file.
2521 */ 2585 */
2522 2586
2523 (function(scope) { 2587 (function(scope) {
2524 'use strict'; 2588 'use strict';
2525 2589
2526 /** 2590 /**
2527 * A tree scope represents the root of a tree. All nodes in a tree point to 2591 * A tree scope represents the root of a tree. All nodes in a tree point to
2528 * the same TreeScope object. The tree scope of a node get set the first time 2592 * the same TreeScope object. The tree scope of a node get set the first time
2529 * it is accessed or when a node is added or remove to a tree. 2593 * it is accessed or when a node is added or remove to a tree.
2594 *
2595 * The root is a Node that has no parent.
2596 *
2597 * The parent is another TreeScope. For ShadowRoots, it is the TreeScope of
2598 * the host of the ShadowRoot.
2599 *
2600 * @param {!Node} root
2601 * @param {TreeScope} parent
2530 * @constructor 2602 * @constructor
2531 */ 2603 */
2532 function TreeScope(root, parent) { 2604 function TreeScope(root, parent) {
2605 /** @type {!Node} */
2533 this.root = root; 2606 this.root = root;
2607
2608 /** @type {TreeScope} */
2534 this.parent = parent; 2609 this.parent = parent;
2535 } 2610 }
2536 2611
2537 TreeScope.prototype = { 2612 TreeScope.prototype = {
2538 get renderer() { 2613 get renderer() {
2539 if (this.root instanceof scope.wrappers.ShadowRoot) { 2614 if (this.root instanceof scope.wrappers.ShadowRoot) {
2540 return scope.getRendererForHost(this.root.host); 2615 return scope.getRendererForHost(this.root.host);
2541 } 2616 }
2542 return null; 2617 return null;
2543 }, 2618 },
(...skipping 13 matching lines...) Expand all
2557 for (var sr = node.shadowRoot; sr; sr = sr.olderShadowRoot) { 2632 for (var sr = node.shadowRoot; sr; sr = sr.olderShadowRoot) {
2558 sr.treeScope_.parent = treeScope; 2633 sr.treeScope_.parent = treeScope;
2559 } 2634 }
2560 for (var child = node.firstChild; child; child = child.nextSibling) { 2635 for (var child = node.firstChild; child; child = child.nextSibling) {
2561 setTreeScope(child, treeScope); 2636 setTreeScope(child, treeScope);
2562 } 2637 }
2563 } 2638 }
2564 } 2639 }
2565 2640
2566 function getTreeScope(node) { 2641 function getTreeScope(node) {
2642 if (node instanceof scope.wrappers.Window) {
2643 debugger;
2644 }
2645
2567 if (node.treeScope_) 2646 if (node.treeScope_)
2568 return node.treeScope_; 2647 return node.treeScope_;
2569 var parent = node.parentNode; 2648 var parent = node.parentNode;
2570 var treeScope; 2649 var treeScope;
2571 if (parent) 2650 if (parent)
2572 treeScope = getTreeScope(parent); 2651 treeScope = getTreeScope(parent);
2573 else 2652 else
2574 treeScope = new TreeScope(node, null); 2653 treeScope = new TreeScope(node, null);
2575 return node.treeScope_ = treeScope; 2654 return node.treeScope_ = treeScope;
2576 } 2655 }
(...skipping 29 matching lines...) Expand all
2606 var eventPhaseTable = new WeakMap(); 2685 var eventPhaseTable = new WeakMap();
2607 var stopPropagationTable = new WeakMap(); 2686 var stopPropagationTable = new WeakMap();
2608 var stopImmediatePropagationTable = new WeakMap(); 2687 var stopImmediatePropagationTable = new WeakMap();
2609 var eventHandlersTable = new WeakMap(); 2688 var eventHandlersTable = new WeakMap();
2610 var eventPathTable = new WeakMap(); 2689 var eventPathTable = new WeakMap();
2611 2690
2612 function isShadowRoot(node) { 2691 function isShadowRoot(node) {
2613 return node instanceof wrappers.ShadowRoot; 2692 return node instanceof wrappers.ShadowRoot;
2614 } 2693 }
2615 2694
2616 function isInsertionPoint(node) { 2695 function rootOfNode(node) {
2617 var localName = node.localName; 2696 return getTreeScope(node).root;
2618 return localName === 'content' || localName === 'shadow'; 2697 }
2619 } 2698
2620 2699 // http://w3c.github.io/webcomponents/spec/shadow/#event-paths
2621 function isShadowHost(node) { 2700 function getEventPath(node, event) {
2622 return !!node.shadowRoot; 2701 var path = [];
2623 } 2702 var current = node;
2624 2703 path.push(current);
2625 function getEventParent(node) { 2704 while (current) {
2626 var dv; 2705 // 4.1.
2627 return node.parentNode || (dv = node.defaultView) && wrap(dv) || null; 2706 var destinationInsertionPoints = getDestinationInsertionPoints(current);
2628 } 2707 if (destinationInsertionPoints && destinationInsertionPoints.length > 0) {
2629 2708 // 4.1.1
2630 // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#df n-adjusted-parent 2709 for (var i = 0; i < destinationInsertionPoints.length; i++) {
2631 function calculateParents(node, context, ancestors) { 2710 var insertionPoint = destinationInsertionPoints[i];
2632 if (ancestors.length) 2711 // 4.1.1.1
2633 return ancestors.shift(); 2712 if (isShadowInsertionPoint(insertionPoint)) {
2634 2713 var shadowRoot = rootOfNode(insertionPoint);
2635 // 1. 2714 // 4.1.1.1.2
2636 if (isShadowRoot(node)) 2715 var olderShadowRoot = shadowRoot.olderShadowRoot;
2637 return getInsertionParent(node) || node.host; 2716 if (olderShadowRoot)
2638 2717 path.push(olderShadowRoot);
2639 // 2. 2718 }
2640 var eventParents = scope.eventParentsTable.get(node); 2719
2641 if (eventParents) { 2720 // 4.1.1.2
2642 // Copy over the remaining event parents for next iteration. 2721 path.push(insertionPoint);
2643 for (var i = 1; i < eventParents.length; i++) {
2644 ancestors[i - 1] = eventParents[i];
2645 }
2646 return eventParents[0];
2647 }
2648
2649 // 3.
2650 if (context && isInsertionPoint(node)) {
2651 var parentNode = node.parentNode;
2652 if (parentNode && isShadowHost(parentNode)) {
2653 var trees = scope.getShadowTrees(parentNode);
2654 var p = getInsertionParent(context);
2655 for (var i = 0; i < trees.length; i++) {
2656 if (trees[i].contains(p))
2657 return p;
2658 } 2722 }
2659 } 2723
2660 } 2724 // 4.1.2
2661 2725 current = destinationInsertionPoints[
2662 return getEventParent(node); 2726 destinationInsertionPoints.length - 1];
2663 } 2727
2664 2728 // 4.2
2665 // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#ev ent-retargeting 2729 } else {
2666 function retarget(node) { 2730 if (isShadowRoot(current)) {
2667 var stack = []; // 1. 2731 if (inSameTree(node, current) && eventMustBeStopped(event)) {
2668 var ancestor = node; // 2. 2732 // Stop this algorithm
2669 var targets = []; 2733 break;
2734 }
2735 current = current.host;
2736 path.push(current);
2737
2738 // 4.2.2
2739 } else {
2740 current = current.parentNode;
2741 if (current)
2742 path.push(current);
2743 }
2744 }
2745 }
2746
2747 return path;
2748 }
2749
2750 // http://w3c.github.io/webcomponents/spec/shadow/#dfn-events-always-stopped
2751 function eventMustBeStopped(event) {
2752 if (!event)
2753 return false;
2754
2755 switch (event.type) {
2756 case 'abort':
2757 case 'error':
2758 case 'select':
2759 case 'change':
2760 case 'load':
2761 case 'reset':
2762 case 'resize':
2763 case 'scroll':
2764 case 'selectstart':
2765 return true;
2766 }
2767 return false;
2768 }
2769
2770 // http://w3c.github.io/webcomponents/spec/shadow/#dfn-shadow-insertion-point
2771 function isShadowInsertionPoint(node) {
2772 return node instanceof HTMLShadowElement;
2773 // and make sure that there are no shadow precing this?
2774 // and that there is no content ancestor?
2775 }
2776
2777 function getDestinationInsertionPoints(node) {
2778 return scope.getDestinationInsertionPoints(node);
2779 }
2780
2781 // http://w3c.github.io/webcomponents/spec/shadow/#event-retargeting
2782 function eventRetargetting(path, currentTarget) {
2783 if (path.length === 0)
2784 return currentTarget;
2785
2786 // The currentTarget might be the window object. Use its document for the
2787 // purpose of finding the retargetted node.
2788 if (currentTarget instanceof wrappers.Window)
2789 currentTarget = currentTarget.document;
2790
2791 var currentTargetTree = getTreeScope(currentTarget);
2792 var originalTarget = path[0];
2793 var originalTargetTree = getTreeScope(originalTarget);
2794 var relativeTargetTree =
2795 lowestCommonInclusiveAncestor(currentTargetTree, originalTargetTree);
2796
2797 for (var i = 0; i < path.length; i++) {
2798 var node = path[i];
2799 if (getTreeScope(node) === relativeTargetTree)
2800 return node;
2801 }
2802
2803 return path[path.length - 1];
2804 }
2805
2806 function getTreeScopeAncestors(treeScope) {
2670 var ancestors = []; 2807 var ancestors = [];
2671 while (ancestor) { // 3. 2808 for (;treeScope; treeScope = treeScope.parent) {
2672 var context = null; // 3.2. 2809 ancestors.push(treeScope);
2673 // TODO(arv): Change order of these. If the stack is empty we always end 2810 }
2674 // up pushing ancestor, no matter what. 2811 return ancestors;
2675 if (isInsertionPoint(ancestor)) { // 3.1. 2812 }
2676 context = topMostNotInsertionPoint(stack); // 3.1.1. 2813
2677 var top = stack[stack.length - 1] || ancestor; // 3.1.2. 2814 function lowestCommonInclusiveAncestor(tsA, tsB) {
2678 stack.push(top); 2815 var ancestorsA = getTreeScopeAncestors(tsA);
2679 } else if (!stack.length) { 2816 var ancestorsB = getTreeScopeAncestors(tsB);
2680 stack.push(ancestor); // 3.3. 2817
2681 } 2818 var result = null;
2682 var target = stack[stack.length - 1]; // 3.4. 2819 while (ancestorsA.length > 0 && ancestorsB.length > 0) {
2683 targets.push({target: target, currentTarget: ancestor}); // 3.5. 2820 var a = ancestorsA.pop();
2684 if (isShadowRoot(ancestor)) // 3.6. 2821 var b = ancestorsB.pop();
2685 stack.pop(); // 3.6.1. 2822 if (a === b)
2686 2823 result = a;
2687 ancestor = calculateParents(ancestor, context, ancestors); // 3.7. 2824 else
2688 } 2825 break;
2689 return targets; 2826 }
2690 } 2827 return result;
2691 2828 }
2692 function topMostNotInsertionPoint(stack) { 2829
2693 for (var i = stack.length - 1; i >= 0; i--) { 2830 function getTreeScopeRoot(ts) {
2694 if (!isInsertionPoint(stack[i])) 2831 if (!ts.parent)
2695 return stack[i]; 2832 return ts;
2696 } 2833 return getTreeScopeRoot(ts.parent);
2834 }
2835
2836 function relatedTargetResolution(event, currentTarget, relatedTarget) {
2837 // In case the current target is a window use its document for the purpose
2838 // of retargetting the related target.
2839 if (currentTarget instanceof wrappers.Window)
2840 currentTarget = currentTarget.document;
2841
2842 var currentTargetTree = getTreeScope(currentTarget);
2843 var relatedTargetTree = getTreeScope(relatedTarget);
2844
2845 var relatedTargetEventPath = getEventPath(relatedTarget, event);
2846
2847 var lowestCommonAncestorTree;
2848
2849 // 4
2850 var lowestCommonAncestorTree =
2851 lowestCommonInclusiveAncestor(currentTargetTree, relatedTargetTree);
2852
2853 // 5
2854 if (!lowestCommonAncestorTree)
2855 lowestCommonAncestorTree = relatedTargetTree.root;
2856
2857 // 6
2858 for (var commonAncestorTree = lowestCommonAncestorTree;
2859 commonAncestorTree;
2860 commonAncestorTree = commonAncestorTree.parent) {
2861 // 6.1
2862 var adjustedRelatedTarget;
2863 for (var i = 0; i < relatedTargetEventPath.length; i++) {
2864 var node = relatedTargetEventPath[i];
2865 if (getTreeScope(node) === commonAncestorTree)
2866 return node;
2867 }
2868 }
2869
2697 return null; 2870 return null;
2698 } 2871 }
2699 2872
2700 // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#df n-adjusted-related-target
2701 function adjustRelatedTarget(target, related) {
2702 var ancestors = [];
2703 while (target) { // 3.
2704 var stack = []; // 3.1.
2705 var ancestor = related; // 3.2.
2706 var last = undefined; // 3.3. Needs to be reset every iteration.
2707 while (ancestor) {
2708 var context = null;
2709 if (!stack.length) {
2710 stack.push(ancestor);
2711 } else {
2712 if (isInsertionPoint(ancestor)) { // 3.4.3.
2713 context = topMostNotInsertionPoint(stack);
2714 // isDistributed is more general than checking whether last is
2715 // assigned into ancestor.
2716 if (isDistributed(last)) { // 3.4.3.2.
2717 var head = stack[stack.length - 1];
2718 stack.push(head);
2719 }
2720 }
2721 }
2722
2723 if (inSameTree(ancestor, target)) // 3.4.4.
2724 return stack[stack.length - 1];
2725
2726 if (isShadowRoot(ancestor)) // 3.4.5.
2727 stack.pop();
2728
2729 last = ancestor; // 3.4.6.
2730 ancestor = calculateParents(ancestor, context, ancestors); // 3.4.7.
2731 }
2732 if (isShadowRoot(target)) // 3.5.
2733 target = target.host;
2734 else
2735 target = target.parentNode; // 3.6.
2736 }
2737 }
2738
2739 function getInsertionParent(node) {
2740 return scope.insertionParentTable.get(node);
2741 }
2742
2743 function isDistributed(node) {
2744 return getInsertionParent(node);
2745 }
2746
2747 function inSameTree(a, b) { 2873 function inSameTree(a, b) {
2748 return getTreeScope(a) === getTreeScope(b); 2874 return getTreeScope(a) === getTreeScope(b);
2749 } 2875 }
2750 2876
2877 var NONE = 0;
2878 var CAPTURING_PHASE = 1;
2879 var AT_TARGET = 2;
2880 var BUBBLING_PHASE = 3;
2881
2882 // pendingError is used to rethrow the first error we got during an event
2883 // dispatch. The browser actually reports all errors but to do that we would
2884 // need to rethrow the error asynchronously.
2885 var pendingError;
2886
2751 function dispatchOriginalEvent(originalEvent) { 2887 function dispatchOriginalEvent(originalEvent) {
2752 // Make sure this event is only dispatched once. 2888 // Make sure this event is only dispatched once.
2753 if (handledEventsTable.get(originalEvent)) 2889 if (handledEventsTable.get(originalEvent))
2754 return; 2890 return;
2755 handledEventsTable.set(originalEvent, true); 2891 handledEventsTable.set(originalEvent, true);
2756 dispatchEvent(wrap(originalEvent), wrap(originalEvent.target)); 2892 dispatchEvent(wrap(originalEvent), wrap(originalEvent.target));
2757 } 2893 if (pendingError) {
2758 2894 var err = pendingError;
2759 function isLoadLikeEvent(event) { 2895 pendingError = null;
2760 switch (event.type) { 2896 throw err;
2761 case 'beforeunload': 2897 }
2762 case 'load':
2763 case 'unload':
2764 return true;
2765 }
2766 return false;
2767 } 2898 }
2768 2899
2769 function dispatchEvent(event, originalWrapperTarget) { 2900 function dispatchEvent(event, originalWrapperTarget) {
2770 if (currentlyDispatchingEvents.get(event)) 2901 if (currentlyDispatchingEvents.get(event))
2771 throw new Error('InvalidStateError') 2902 throw new Error('InvalidStateError');
2903
2772 currentlyDispatchingEvents.set(event, true); 2904 currentlyDispatchingEvents.set(event, true);
2773 2905
2774 // Render to ensure that the event path is correct. 2906 // Render to ensure that the event path is correct.
2775 scope.renderAllPending(); 2907 scope.renderAllPending();
2776 var eventPath = retarget(originalWrapperTarget); 2908 var eventPath;
2777 2909
2778 // For window "load" events the "load" event is dispatched at the window but 2910 // http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.ht ml#events-and-the-window-object
2779 // the target is set to the document. 2911 // All events dispatched on Nodes with a default view, except load events,
2780 // 2912 // should propagate to the Window.
2913
2781 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html# the-end 2914 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html# the-end
2782 // 2915 var overrideTarget;
2783 // TODO(arv): Find a less hacky way to do this. 2916 var win;
2784 if (eventPath.length === 2 && 2917 var type = event.type;
2785 eventPath[0].target instanceof wrappers.Document && 2918
2786 isLoadLikeEvent(event)) { 2919 // Should really be not cancelable too but since Firefox has a bug there
2787 eventPath.shift(); 2920 // we skip that check.
2921 // https://bugzilla.mozilla.org/show_bug.cgi?id=999456
2922 if (type === 'load' && !event.bubbles) {
2923 var doc = originalWrapperTarget;
2924 if (doc instanceof wrappers.Document && (win = doc.defaultView)) {
2925 overrideTarget = doc;
2926 eventPath = [];
2927 }
2928 }
2929
2930 if (!eventPath) {
2931 if (originalWrapperTarget instanceof wrappers.Window) {
2932 win = originalWrapperTarget;
2933 eventPath = [];
2934 } else {
2935 eventPath = getEventPath(originalWrapperTarget, event);
2936
2937 if (event.type !== 'load') {
2938 var doc = eventPath[eventPath.length - 1];
2939 if (doc instanceof wrappers.Document)
2940 win = doc.defaultView;
2941 }
2942 }
2788 } 2943 }
2789 2944
2790 eventPathTable.set(event, eventPath); 2945 eventPathTable.set(event, eventPath);
2791 2946
2792 if (dispatchCapturing(event, eventPath)) { 2947 if (dispatchCapturing(event, eventPath, win, overrideTarget)) {
2793 if (dispatchAtTarget(event, eventPath)) { 2948 if (dispatchAtTarget(event, eventPath, win, overrideTarget)) {
2794 dispatchBubbling(event, eventPath); 2949 dispatchBubbling(event, eventPath, win, overrideTarget);
2795 } 2950 }
2796 } 2951 }
2797 2952
2798 eventPhaseTable.set(event, Event.NONE); 2953 eventPhaseTable.set(event, NONE);
2799 currentTargetTable.delete(event, null); 2954 currentTargetTable.delete(event, null);
2800 currentlyDispatchingEvents.delete(event); 2955 currentlyDispatchingEvents.delete(event);
2801 2956
2802 return event.defaultPrevented; 2957 return event.defaultPrevented;
2803 } 2958 }
2804 2959
2805 function dispatchCapturing(event, eventPath) { 2960 function dispatchCapturing(event, eventPath, win, overrideTarget) {
2806 var phase; 2961 var phase = CAPTURING_PHASE;
2962
2963 if (win) {
2964 if (!invoke(win, event, phase, eventPath, overrideTarget))
2965 return false;
2966 }
2807 2967
2808 for (var i = eventPath.length - 1; i > 0; i--) { 2968 for (var i = eventPath.length - 1; i > 0; i--) {
2809 var target = eventPath[i].target; 2969 if (!invoke(eventPath[i], event, phase, eventPath, overrideTarget))
2810 var currentTarget = eventPath[i].currentTarget;
2811 if (target === currentTarget)
2812 continue;
2813
2814 phase = Event.CAPTURING_PHASE;
2815 if (!invoke(eventPath[i], event, phase))
2816 return false; 2970 return false;
2817 } 2971 }
2818 2972
2819 return true; 2973 return true;
2820 } 2974 }
2821 2975
2822 function dispatchAtTarget(event, eventPath) { 2976 function dispatchAtTarget(event, eventPath, win, overrideTarget) {
2823 var phase = Event.AT_TARGET; 2977 var phase = AT_TARGET;
2824 return invoke(eventPath[0], event, phase); 2978 var currentTarget = eventPath[0] || win;
2825 } 2979 return invoke(currentTarget, event, phase, eventPath, overrideTarget);
2826 2980 }
2827 function dispatchBubbling(event, eventPath) { 2981
2828 var bubbles = event.bubbles; 2982 function dispatchBubbling(event, eventPath, win, overrideTarget) {
2829 var phase; 2983 var phase = BUBBLING_PHASE;
2830
2831 for (var i = 1; i < eventPath.length; i++) { 2984 for (var i = 1; i < eventPath.length; i++) {
2832 var target = eventPath[i].target; 2985 if (!invoke(eventPath[i], event, phase, eventPath, overrideTarget))
2833 var currentTarget = eventPath[i].currentTarget;
2834 if (target === currentTarget)
2835 phase = Event.AT_TARGET;
2836 else if (bubbles && !stopImmediatePropagationTable.get(event))
2837 phase = Event.BUBBLING_PHASE;
2838 else
2839 continue;
2840
2841 if (!invoke(eventPath[i], event, phase))
2842 return; 2986 return;
2843 } 2987 }
2844 } 2988
2845 2989 if (win && eventPath.length > 0) {
2846 function invoke(tuple, event, phase) { 2990 invoke(win, event, phase, eventPath, overrideTarget);
2847 var target = tuple.target; 2991 }
2848 var currentTarget = tuple.currentTarget; 2992 }
2849 2993
2994 function invoke(currentTarget, event, phase, eventPath, overrideTarget) {
2850 var listeners = listenersTable.get(currentTarget); 2995 var listeners = listenersTable.get(currentTarget);
2851 if (!listeners) 2996 if (!listeners)
2852 return true; 2997 return true;
2853 2998
2999 var target = overrideTarget || eventRetargetting(eventPath, currentTarget);
3000
3001 if (target === currentTarget) {
3002 if (phase === CAPTURING_PHASE)
3003 return true;
3004
3005 if (phase === BUBBLING_PHASE)
3006 phase = AT_TARGET;
3007
3008 } else if (phase === BUBBLING_PHASE && !event.bubbles) {
3009 return true;
3010 }
3011
2854 if ('relatedTarget' in event) { 3012 if ('relatedTarget' in event) {
2855 var originalEvent = unwrap(event); 3013 var originalEvent = unwrap(event);
2856 var unwrappedRelatedTarget = originalEvent.relatedTarget; 3014 var unwrappedRelatedTarget = originalEvent.relatedTarget;
2857 3015
2858 // X-Tag sets relatedTarget on a CustomEvent. If they do that there is no 3016 // X-Tag sets relatedTarget on a CustomEvent. If they do that there is no
2859 // way to have relatedTarget return the adjusted target but worse is that 3017 // way to have relatedTarget return the adjusted target but worse is that
2860 // the originalEvent might not have a relatedTarget so we hit an assert 3018 // the originalEvent might not have a relatedTarget so we hit an assert
2861 // when we try to wrap it. 3019 // when we try to wrap it.
2862 if (unwrappedRelatedTarget) { 3020 if (unwrappedRelatedTarget) {
2863 // In IE we can get objects that are not EventTargets at this point. 3021 // In IE we can get objects that are not EventTargets at this point.
2864 // Safari does not have an EventTarget interface so revert to checking 3022 // Safari does not have an EventTarget interface so revert to checking
2865 // for addEventListener as an approximation. 3023 // for addEventListener as an approximation.
2866 if (unwrappedRelatedTarget instanceof Object && 3024 if (unwrappedRelatedTarget instanceof Object &&
2867 unwrappedRelatedTarget.addEventListener) { 3025 unwrappedRelatedTarget.addEventListener) {
2868 var relatedTarget = wrap(unwrappedRelatedTarget); 3026 var relatedTarget = wrap(unwrappedRelatedTarget);
2869 3027
2870 var adjusted = adjustRelatedTarget(currentTarget, relatedTarget); 3028 var adjusted =
3029 relatedTargetResolution(event, currentTarget, relatedTarget);
2871 if (adjusted === target) 3030 if (adjusted === target)
2872 return true; 3031 return true;
2873 } else { 3032 } else {
2874 adjusted = null; 3033 adjusted = null;
2875 } 3034 }
2876 relatedTargetTable.set(event, adjusted); 3035 relatedTargetTable.set(event, adjusted);
2877 } 3036 }
2878 } 3037 }
2879 3038
2880 eventPhaseTable.set(event, phase); 3039 eventPhaseTable.set(event, phase);
2881 var type = event.type; 3040 var type = event.type;
2882 3041
2883 var anyRemoved = false; 3042 var anyRemoved = false;
3043 // targetTable.set(event, target);
2884 targetTable.set(event, target); 3044 targetTable.set(event, target);
2885 currentTargetTable.set(event, currentTarget); 3045 currentTargetTable.set(event, currentTarget);
2886 3046
2887 for (var i = 0; i < listeners.length; i++) { 3047 for (var i = 0; i < listeners.length; i++) {
2888 var listener = listeners[i]; 3048 var listener = listeners[i];
2889 if (listener.removed) { 3049 if (listener.removed) {
2890 anyRemoved = true; 3050 anyRemoved = true;
2891 continue; 3051 continue;
2892 } 3052 }
2893 3053
2894 if (listener.type !== type || 3054 if (listener.type !== type ||
2895 !listener.capture && phase === Event.CAPTURING_PHASE || 3055 !listener.capture && phase === CAPTURING_PHASE ||
2896 listener.capture && phase === Event.BUBBLING_PHASE) { 3056 listener.capture && phase === BUBBLING_PHASE) {
2897 continue; 3057 continue;
2898 } 3058 }
2899 3059
2900 try { 3060 try {
2901 if (typeof listener.handler === 'function') 3061 if (typeof listener.handler === 'function')
2902 listener.handler.call(currentTarget, event); 3062 listener.handler.call(currentTarget, event);
2903 else 3063 else
2904 listener.handler.handleEvent(event); 3064 listener.handler.handleEvent(event);
2905 3065
2906 if (stopImmediatePropagationTable.get(event)) 3066 if (stopImmediatePropagationTable.get(event))
2907 return false; 3067 return false;
2908 3068
2909 } catch (ex) { 3069 } catch (ex) {
2910 if (window.onerror) 3070 if (!pendingError)
2911 window.onerror(ex.message); 3071 pendingError = ex;
2912 else
2913 console.error(ex, ex.stack);
2914 } 3072 }
2915 } 3073 }
2916 3074
2917 if (anyRemoved) { 3075 if (anyRemoved) {
2918 var copy = listeners.slice(); 3076 var copy = listeners.slice();
2919 listeners.length = 0; 3077 listeners.length = 0;
2920 for (var i = 0; i < copy.length; i++) { 3078 for (var i = 0; i < copy.length; i++) {
2921 if (!copy[i].removed) 3079 if (!copy[i].removed)
2922 listeners.push(copy[i]); 3080 listeners.push(copy[i]);
2923 } 3081 }
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
2980 }, 3138 },
2981 get path() { 3139 get path() {
2982 var nodeList = new wrappers.NodeList(); 3140 var nodeList = new wrappers.NodeList();
2983 var eventPath = eventPathTable.get(this); 3141 var eventPath = eventPathTable.get(this);
2984 if (eventPath) { 3142 if (eventPath) {
2985 var index = 0; 3143 var index = 0;
2986 var lastIndex = eventPath.length - 1; 3144 var lastIndex = eventPath.length - 1;
2987 var baseRoot = getTreeScope(currentTargetTable.get(this)); 3145 var baseRoot = getTreeScope(currentTargetTable.get(this));
2988 3146
2989 for (var i = 0; i <= lastIndex; i++) { 3147 for (var i = 0; i <= lastIndex; i++) {
2990 var currentTarget = eventPath[i].currentTarget; 3148 var currentTarget = eventPath[i];
2991 var currentRoot = getTreeScope(currentTarget); 3149 var currentRoot = getTreeScope(currentTarget);
2992 if (currentRoot.contains(baseRoot) && 3150 if (currentRoot.contains(baseRoot) &&
2993 // Make sure we do not add Window to the path. 3151 // Make sure we do not add Window to the path.
2994 (i !== lastIndex || currentTarget instanceof wrappers.Node)) { 3152 (i !== lastIndex || currentTarget instanceof wrappers.Node)) {
2995 nodeList[index++] = currentTarget; 3153 nodeList[index++] = currentTarget;
2996 } 3154 }
2997 } 3155 }
2998 nodeList.length = index; 3156 nodeList.length = index;
2999 } 3157 }
3000 return nodeList; 3158 return nodeList;
(...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after
3323 function wrapEventTargetMethods(constructors) { 3481 function wrapEventTargetMethods(constructors) {
3324 forwardMethodsToWrapper(constructors, methodNames); 3482 forwardMethodsToWrapper(constructors, methodNames);
3325 } 3483 }
3326 3484
3327 var originalElementFromPoint = document.elementFromPoint; 3485 var originalElementFromPoint = document.elementFromPoint;
3328 3486
3329 function elementFromPoint(self, document, x, y) { 3487 function elementFromPoint(self, document, x, y) {
3330 scope.renderAllPending(); 3488 scope.renderAllPending();
3331 3489
3332 var element = wrap(originalElementFromPoint.call(document.impl, x, y)); 3490 var element = wrap(originalElementFromPoint.call(document.impl, x, y));
3333 var targets = retarget(element, this) 3491 if (!element)
3334 for (var i = 0; i < targets.length; i++) { 3492 return null;
3335 var target = targets[i]; 3493 var path = getEventPath(element, null);
3336 if (target.currentTarget === self) 3494 return eventRetargetting(path, self);
3337 return target.target;
3338 }
3339 return null;
3340 } 3495 }
3341 3496
3342 /** 3497 /**
3343 * Returns a function that is to be used as a getter for `onfoo` properties. 3498 * Returns a function that is to be used as a getter for `onfoo` properties.
3344 * @param {string} name 3499 * @param {string} name
3345 * @return {Function} 3500 * @return {Function}
3346 */ 3501 */
3347 function getEventHandlerGetter(name) { 3502 function getEventHandlerGetter(name) {
3348 return function() { 3503 return function() {
3349 var inlineEventHandlers = eventHandlersTable.get(this); 3504 var inlineEventHandlers = eventHandlersTable.get(this);
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
3383 3538
3384 this.addEventListener(eventType, wrapped, false); 3539 this.addEventListener(eventType, wrapped, false);
3385 inlineEventHandlers[name] = { 3540 inlineEventHandlers[name] = {
3386 value: value, 3541 value: value,
3387 wrapped: wrapped 3542 wrapped: wrapped
3388 }; 3543 };
3389 } 3544 }
3390 }; 3545 };
3391 } 3546 }
3392 3547
3393 scope.adjustRelatedTarget = adjustRelatedTarget;
3394 scope.elementFromPoint = elementFromPoint; 3548 scope.elementFromPoint = elementFromPoint;
3395 scope.getEventHandlerGetter = getEventHandlerGetter; 3549 scope.getEventHandlerGetter = getEventHandlerGetter;
3396 scope.getEventHandlerSetter = getEventHandlerSetter; 3550 scope.getEventHandlerSetter = getEventHandlerSetter;
3397 scope.wrapEventTargetMethods = wrapEventTargetMethods; 3551 scope.wrapEventTargetMethods = wrapEventTargetMethods;
3398 scope.wrappers.BeforeUnloadEvent = BeforeUnloadEvent; 3552 scope.wrappers.BeforeUnloadEvent = BeforeUnloadEvent;
3399 scope.wrappers.CustomEvent = CustomEvent; 3553 scope.wrappers.CustomEvent = CustomEvent;
3400 scope.wrappers.Event = Event; 3554 scope.wrappers.Event = Event;
3401 scope.wrappers.EventTarget = EventTarget; 3555 scope.wrappers.EventTarget = EventTarget;
3402 scope.wrappers.FocusEvent = FocusEvent; 3556 scope.wrappers.FocusEvent = FocusEvent;
3403 scope.wrappers.MouseEvent = MouseEvent; 3557 scope.wrappers.MouseEvent = MouseEvent;
3404 scope.wrappers.UIEvent = UIEvent; 3558 scope.wrappers.UIEvent = UIEvent;
3405 3559
3406 })(window.ShadowDOMPolyfill); 3560 })(window.ShadowDOMPolyfill);
3407 3561
3562 /*
3563 * Copyright 2014 The Polymer Authors. All rights reserved.
3564 * Use of this source code is goverened by a BSD-style
3565 * license that can be found in the LICENSE file.
3566 */
3567
3568 (function(scope) {
3569 'use strict';
3570
3571 var UIEvent = scope.wrappers.UIEvent;
3572 var mixin = scope.mixin;
3573 var registerWrapper = scope.registerWrapper;
3574 var unwrap = scope.unwrap;
3575 var wrap = scope.wrap;
3576
3577 // TouchEvent is WebKit/Blink only.
3578 var OriginalTouchEvent = window.TouchEvent;
3579 if (!OriginalTouchEvent)
3580 return;
3581
3582 var nativeEvent;
3583 try {
3584 nativeEvent = document.createEvent('TouchEvent');
3585 } catch (ex) {
3586 // In Chrome creating a TouchEvent fails if the feature is not turned on
3587 // which it isn't on desktop Chrome.
3588 return;
3589 }
3590
3591 var nonEnumDescriptor = {enumerable: false};
3592
3593 function nonEnum(obj, prop) {
3594 Object.defineProperty(obj, prop, nonEnumDescriptor);
3595 }
3596
3597 function Touch(impl) {
3598 this.impl = impl;
3599 }
3600
3601 Touch.prototype = {
3602 get target() {
3603 return wrap(this.impl.target);
3604 }
3605 };
3606
3607 var descr = {
3608 configurable: true,
3609 enumerable: true,
3610 get: null
3611 };
3612
3613 [
3614 'clientX',
3615 'clientY',
3616 'screenX',
3617 'screenY',
3618 'pageX',
3619 'pageY',
3620 'identifier',
3621 'webkitRadiusX',
3622 'webkitRadiusY',
3623 'webkitRotationAngle',
3624 'webkitForce'
3625 ].forEach(function(name) {
3626 descr.get = function() {
3627 return this.impl[name];
3628 };
3629 Object.defineProperty(Touch.prototype, name, descr);
3630 });
3631
3632 function TouchList() {
3633 this.length = 0;
3634 nonEnum(this, 'length');
3635 }
3636
3637 TouchList.prototype = {
3638 item: function(index) {
3639 return this[index];
3640 }
3641 };
3642
3643 function wrapTouchList(nativeTouchList) {
3644 var list = new TouchList();
3645 for (var i = 0; i < nativeTouchList.length; i++) {
3646 list[i] = new Touch(nativeTouchList[i]);
3647 }
3648 list.length = i;
3649 return list;
3650 }
3651
3652 function TouchEvent(impl) {
3653 UIEvent.call(this, impl);
3654 }
3655
3656 TouchEvent.prototype = Object.create(UIEvent.prototype);
3657
3658 mixin(TouchEvent.prototype, {
3659 get touches() {
3660 return wrapTouchList(unwrap(this).touches);
3661 },
3662
3663 get targetTouches() {
3664 return wrapTouchList(unwrap(this).targetTouches);
3665 },
3666
3667 get changedTouches() {
3668 return wrapTouchList(unwrap(this).changedTouches);
3669 },
3670
3671 initTouchEvent: function() {
3672 // The only way to use this is to reuse the TouchList from an existing
3673 // TouchEvent. Since this is WebKit/Blink proprietary API we will not
3674 // implement this until someone screams.
3675 throw new Error('Not implemented');
3676 }
3677 });
3678
3679 registerWrapper(OriginalTouchEvent, TouchEvent, nativeEvent);
3680
3681 scope.wrappers.Touch = Touch;
3682 scope.wrappers.TouchEvent = TouchEvent;
3683 scope.wrappers.TouchList = TouchList;
3684
3685 })(window.ShadowDOMPolyfill);
3686
3687
3408 // Copyright 2012 The Polymer Authors. All rights reserved. 3688 // Copyright 2012 The Polymer Authors. All rights reserved.
3409 // Use of this source code is goverened by a BSD-style 3689 // Use of this source code is goverened by a BSD-style
3410 // license that can be found in the LICENSE file. 3690 // license that can be found in the LICENSE file.
3411 3691
3412 (function(scope) { 3692 (function(scope) {
3413 'use strict'; 3693 'use strict';
3414 3694
3415 var wrap = scope.wrap; 3695 var wrap = scope.wrap;
3416 3696
3697 var nonEnumDescriptor = {enumerable: false};
3698
3417 function nonEnum(obj, prop) { 3699 function nonEnum(obj, prop) {
3418 Object.defineProperty(obj, prop, {enumerable: false}); 3700 Object.defineProperty(obj, prop, nonEnumDescriptor);
3419 } 3701 }
3420 3702
3421 function NodeList() { 3703 function NodeList() {
3422 this.length = 0; 3704 this.length = 0;
3423 nonEnum(this, 'length'); 3705 nonEnum(this, 'length');
3424 } 3706 }
3425 NodeList.prototype = { 3707 NodeList.prototype = {
3426 item: function(index) { 3708 item: function(index) {
3427 return this[index]; 3709 return this[index];
3428 } 3710 }
(...skipping 435 matching lines...) Expand 10 before | Expand all | Expand 10 after
3864 else 4146 else
3865 nodes = collectNodes(childWrapper, this, previousNode, refWrapper); 4147 nodes = collectNodes(childWrapper, this, previousNode, refWrapper);
3866 4148
3867 if (useNative) { 4149 if (useNative) {
3868 ensureSameOwnerDocument(this, childWrapper); 4150 ensureSameOwnerDocument(this, childWrapper);
3869 clearChildNodes(this); 4151 clearChildNodes(this);
3870 originalInsertBefore.call(this.impl, unwrap(childWrapper), refNode); 4152 originalInsertBefore.call(this.impl, unwrap(childWrapper), refNode);
3871 } else { 4153 } else {
3872 if (!previousNode) 4154 if (!previousNode)
3873 this.firstChild_ = nodes[0]; 4155 this.firstChild_ = nodes[0];
3874 if (!refWrapper) 4156 if (!refWrapper) {
3875 this.lastChild_ = nodes[nodes.length - 1]; 4157 this.lastChild_ = nodes[nodes.length - 1];
4158 if (this.firstChild_ === undefined)
4159 this.firstChild_ = this.firstChild;
4160 }
3876 4161
3877 var parentNode = refNode ? refNode.parentNode : this.impl; 4162 var parentNode = refNode ? refNode.parentNode : this.impl;
3878 4163
3879 // insertBefore refWrapper no matter what the parent is? 4164 // insertBefore refWrapper no matter what the parent is?
3880 if (parentNode) { 4165 if (parentNode) {
3881 originalInsertBefore.call(parentNode, 4166 originalInsertBefore.call(parentNode,
3882 unwrapNodesForInsertion(this, nodes), refNode); 4167 unwrapNodesForInsertion(this, nodes), refNode);
3883 } else { 4168 } else {
3884 adoptNodesIfNeeded(this, nodes); 4169 adoptNodesIfNeeded(this, nodes);
3885 } 4170 }
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after
4201 4486
4202 })(window.ShadowDOMPolyfill); 4487 })(window.ShadowDOMPolyfill);
4203 4488
4204 // Copyright 2013 The Polymer Authors. All rights reserved. 4489 // Copyright 2013 The Polymer Authors. All rights reserved.
4205 // Use of this source code is governed by a BSD-style 4490 // Use of this source code is governed by a BSD-style
4206 // license that can be found in the LICENSE file. 4491 // license that can be found in the LICENSE file.
4207 4492
4208 (function(scope) { 4493 (function(scope) {
4209 'use strict'; 4494 'use strict';
4210 4495
4496 var HTMLCollection = scope.wrappers.HTMLCollection;
4497 var NodeList = scope.wrappers.NodeList;
4498
4211 function findOne(node, selector) { 4499 function findOne(node, selector) {
4212 var m, el = node.firstElementChild; 4500 var m, el = node.firstElementChild;
4213 while (el) { 4501 while (el) {
4214 if (el.matches(selector)) 4502 if (el.matches(selector))
4215 return el; 4503 return el;
4216 m = findOne(el, selector); 4504 m = findOne(el, selector);
4217 if (m) 4505 if (m)
4218 return m; 4506 return m;
4219 el = el.nextElementSibling; 4507 el = el.nextElementSibling;
4220 } 4508 }
4221 return null; 4509 return null;
4222 } 4510 }
4223 4511
4224 function findAll(node, selector, results) { 4512 function matchesSelector(el, selector) {
4513 return el.matches(selector);
4514 }
4515
4516 var XHTML_NS = 'http://www.w3.org/1999/xhtml';
4517
4518 function matchesTagName(el, localName, localNameLowerCase) {
4519 var ln = el.localName;
4520 return ln === localName ||
4521 ln === localNameLowerCase && el.namespaceURI === XHTML_NS;
4522 }
4523
4524 function matchesEveryThing() {
4525 return true;
4526 }
4527
4528 function matchesLocalName(el, localName) {
4529 return el.localName === localName;
4530 }
4531
4532 function matchesNameSpace(el, ns) {
4533 return el.namespaceURI === ns;
4534 }
4535
4536 function matchesLocalNameNS(el, ns, localName) {
4537 return el.namespaceURI === ns && el.localName === localName;
4538 }
4539
4540 function findElements(node, result, p, arg0, arg1) {
4225 var el = node.firstElementChild; 4541 var el = node.firstElementChild;
4226 while (el) { 4542 while (el) {
4227 if (el.matches(selector)) 4543 if (p(el, arg0, arg1))
4228 results[results.length++] = el; 4544 result[result.length++] = el;
4229 findAll(el, selector, results); 4545 findElements(el, result, p, arg0, arg1);
4230 el = el.nextElementSibling; 4546 el = el.nextElementSibling;
4231 } 4547 }
4232 return results; 4548 return result;
4233 } 4549 }
4234 4550
4235 // find and findAll will only match Simple Selectors, 4551 // find and findAll will only match Simple Selectors,
4236 // Structural Pseudo Classes are not guarenteed to be correct 4552 // Structural Pseudo Classes are not guarenteed to be correct
4237 // http://www.w3.org/TR/css3-selectors/#simple-selectors 4553 // http://www.w3.org/TR/css3-selectors/#simple-selectors
4238 4554
4239 var SelectorsInterface = { 4555 var SelectorsInterface = {
4240 querySelector: function(selector) { 4556 querySelector: function(selector) {
4241 return findOne(this, selector); 4557 return findOne(this, selector);
4242 }, 4558 },
4243 querySelectorAll: function(selector) { 4559 querySelectorAll: function(selector) {
4244 return findAll(this, selector, new NodeList()) 4560 return findElements(this, new NodeList(), matchesSelector, selector);
4245 } 4561 }
4246 }; 4562 };
4247 4563
4248 var GetElementsByInterface = { 4564 var GetElementsByInterface = {
4249 getElementsByTagName: function(tagName) { 4565 getElementsByTagName: function(localName) {
4250 // TODO(arv): Check tagName? 4566 var result = new HTMLCollection();
4251 return this.querySelectorAll(tagName); 4567 if (localName === '*')
4568 return findElements(this, result, matchesEveryThing);
4569
4570 return findElements(this, result,
4571 matchesTagName,
4572 localName,
4573 localName.toLowerCase());
4252 }, 4574 },
4575
4253 getElementsByClassName: function(className) { 4576 getElementsByClassName: function(className) {
4254 // TODO(arv): Check className? 4577 // TODO(arv): Check className?
4255 return this.querySelectorAll('.' + className); 4578 return this.querySelectorAll('.' + className);
4256 }, 4579 },
4257 getElementsByTagNameNS: function(ns, tagName) {
4258 if (ns === '*')
4259 return this.getElementsByTagName(tagName);
4260 4580
4261 // TODO(arv): Check tagName? 4581 getElementsByTagNameNS: function(ns, localName) {
4262 var result = new NodeList; 4582 var result = new HTMLCollection();
4263 var els = this.getElementsByTagName(tagName); 4583
4264 for (var i = 0, j = 0; i < els.length; i++) { 4584 if (ns === '') {
4265 if (els[i].namespaceURI === ns) 4585 ns = null;
4266 result[j++] = els[i]; 4586 } else if (ns === '*') {
4587 if (localName === '*')
4588 return findElements(this, result, matchesEveryThing);
4589 return findElements(this, result, matchesLocalName, localName);
4267 } 4590 }
4268 result.length = j; 4591
4269 return result; 4592 if (localName === '*')
4593 return findElements(this, result, matchesNameSpace, ns);
4594
4595 return findElements(this, result, matchesLocalNameNS, ns, localName);
4270 } 4596 }
4271 }; 4597 };
4272 4598
4273 scope.GetElementsByInterface = GetElementsByInterface; 4599 scope.GetElementsByInterface = GetElementsByInterface;
4274 scope.SelectorsInterface = SelectorsInterface; 4600 scope.SelectorsInterface = SelectorsInterface;
4275 4601
4276 })(window.ShadowDOMPolyfill); 4602 })(window.ShadowDOMPolyfill);
4277 4603
4278 // Copyright 2013 The Polymer Authors. All rights reserved. 4604 // Copyright 2013 The Polymer Authors. All rights reserved.
4279 // Use of this source code is goverened by a BSD-style 4605 // Use of this source code is goverened by a BSD-style
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
4508 var renderer = scope.getRendererForHost(this); 4834 var renderer = scope.getRendererForHost(this);
4509 renderer.invalidate(); 4835 renderer.invalidate();
4510 4836
4511 return newShadowRoot; 4837 return newShadowRoot;
4512 }, 4838 },
4513 4839
4514 get shadowRoot() { 4840 get shadowRoot() {
4515 return this.impl.polymerShadowRoot_ || null; 4841 return this.impl.polymerShadowRoot_ || null;
4516 }, 4842 },
4517 4843
4844 // getDestinationInsertionPoints added in ShadowRenderer.js
4845
4518 setAttribute: function(name, value) { 4846 setAttribute: function(name, value) {
4519 var oldValue = this.impl.getAttribute(name); 4847 var oldValue = this.impl.getAttribute(name);
4520 this.impl.setAttribute(name, value); 4848 this.impl.setAttribute(name, value);
4521 enqueAttributeChange(this, name, oldValue); 4849 enqueAttributeChange(this, name, oldValue);
4522 invalidateRendererBasedOnAttribute(this, name); 4850 invalidateRendererBasedOnAttribute(this, name);
4523 }, 4851 },
4524 4852
4525 removeAttribute: function(name) { 4853 removeAttribute: function(name) {
4526 var oldValue = this.impl.getAttribute(name); 4854 var oldValue = this.impl.getAttribute(name);
4527 this.impl.removeAttribute(name); 4855 this.impl.removeAttribute(name);
(...skipping 428 matching lines...) Expand 10 before | Expand all | Expand 10 after
4956 this.setAttribute('select', value); 5284 this.setAttribute('select', value);
4957 }, 5285 },
4958 5286
4959 setAttribute: function(n, v) { 5287 setAttribute: function(n, v) {
4960 HTMLElement.prototype.setAttribute.call(this, n, v); 5288 HTMLElement.prototype.setAttribute.call(this, n, v);
4961 if (String(n).toLowerCase() === 'select') 5289 if (String(n).toLowerCase() === 'select')
4962 this.invalidateShadowRenderer(true); 5290 this.invalidateShadowRenderer(true);
4963 } 5291 }
4964 5292
4965 // getDistributedNodes is added in ShadowRenderer 5293 // getDistributedNodes is added in ShadowRenderer
4966
4967 // TODO: attribute boolean resetStyleInheritance;
4968 }); 5294 });
4969 5295
4970 if (OriginalHTMLContentElement) 5296 if (OriginalHTMLContentElement)
4971 registerWrapper(OriginalHTMLContentElement, HTMLContentElement); 5297 registerWrapper(OriginalHTMLContentElement, HTMLContentElement);
4972 5298
4973 scope.wrappers.HTMLContentElement = HTMLContentElement; 5299 scope.wrappers.HTMLContentElement = HTMLContentElement;
4974 })(window.ShadowDOMPolyfill); 5300 })(window.ShadowDOMPolyfill);
4975 5301
4976 // Copyright 2013 The Polymer Authors. All rights reserved. 5302 // Copyright 2013 The Polymer Authors. All rights reserved.
4977 // Use of this source code is goverened by a BSD-style 5303 // Use of this source code is goverened by a BSD-style
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
5019 5345
5020 // Copyright 2013 The Polymer Authors. All rights reserved. 5346 // Copyright 2013 The Polymer Authors. All rights reserved.
5021 // Use of this source code is goverened by a BSD-style 5347 // Use of this source code is goverened by a BSD-style
5022 // license that can be found in the LICENSE file. 5348 // license that can be found in the LICENSE file.
5023 5349
5024 (function(scope) { 5350 (function(scope) {
5025 'use strict'; 5351 'use strict';
5026 5352
5027 var HTMLElement = scope.wrappers.HTMLElement; 5353 var HTMLElement = scope.wrappers.HTMLElement;
5028 var mixin = scope.mixin; 5354 var mixin = scope.mixin;
5355 var NodeList = scope.wrappers.NodeList;
5029 var registerWrapper = scope.registerWrapper; 5356 var registerWrapper = scope.registerWrapper;
5030 5357
5031 var OriginalHTMLShadowElement = window.HTMLShadowElement; 5358 var OriginalHTMLShadowElement = window.HTMLShadowElement;
5032 5359
5033 function HTMLShadowElement(node) { 5360 function HTMLShadowElement(node) {
5034 HTMLElement.call(this, node); 5361 HTMLElement.call(this, node);
5035 } 5362 }
5036 HTMLShadowElement.prototype = Object.create(HTMLElement.prototype); 5363 HTMLShadowElement.prototype = Object.create(HTMLElement.prototype);
5037 mixin(HTMLShadowElement.prototype, { 5364
5038 // TODO: attribute boolean resetStyleInheritance; 5365 // getDistributedNodes is added in ShadowRenderer
5039 });
5040 5366
5041 if (OriginalHTMLShadowElement) 5367 if (OriginalHTMLShadowElement)
5042 registerWrapper(OriginalHTMLShadowElement, HTMLShadowElement); 5368 registerWrapper(OriginalHTMLShadowElement, HTMLShadowElement);
5043 5369
5044 scope.wrappers.HTMLShadowElement = HTMLShadowElement; 5370 scope.wrappers.HTMLShadowElement = HTMLShadowElement;
5045 })(window.ShadowDOMPolyfill); 5371 })(window.ShadowDOMPolyfill);
5046 5372
5047 // Copyright 2013 The Polymer Authors. All rights reserved. 5373 // Copyright 2013 The Polymer Authors. All rights reserved.
5048 // Use of this source code is goverened by a BSD-style 5374 // Use of this source code is goverened by a BSD-style
5049 // license that can be found in the LICENSE file. 5375 // license that can be found in the LICENSE file.
(...skipping 787 matching lines...) Expand 10 before | Expand all | Expand 10 after
5837 var spaceCharRe = /[ \t\n\r\f]/; 6163 var spaceCharRe = /[ \t\n\r\f]/;
5838 6164
5839 function ShadowRoot(hostWrapper) { 6165 function ShadowRoot(hostWrapper) {
5840 var node = unwrap(hostWrapper.impl.ownerDocument.createDocumentFragment()); 6166 var node = unwrap(hostWrapper.impl.ownerDocument.createDocumentFragment());
5841 DocumentFragment.call(this, node); 6167 DocumentFragment.call(this, node);
5842 6168
5843 // createDocumentFragment associates the node with a wrapper 6169 // createDocumentFragment associates the node with a wrapper
5844 // DocumentFragment instance. Override that. 6170 // DocumentFragment instance. Override that.
5845 rewrap(node, this); 6171 rewrap(node, this);
5846 6172
5847 this.treeScope_ = new TreeScope(this, getTreeScope(hostWrapper));
5848
5849 var oldShadowRoot = hostWrapper.shadowRoot; 6173 var oldShadowRoot = hostWrapper.shadowRoot;
5850 nextOlderShadowTreeTable.set(this, oldShadowRoot); 6174 nextOlderShadowTreeTable.set(this, oldShadowRoot);
5851 6175
6176 this.treeScope_ =
6177 new TreeScope(this, getTreeScope(oldShadowRoot || hostWrapper));
6178
5852 shadowHostTable.set(this, hostWrapper); 6179 shadowHostTable.set(this, hostWrapper);
5853 } 6180 }
5854 ShadowRoot.prototype = Object.create(DocumentFragment.prototype); 6181 ShadowRoot.prototype = Object.create(DocumentFragment.prototype);
5855 mixin(ShadowRoot.prototype, { 6182 mixin(ShadowRoot.prototype, {
5856 get innerHTML() { 6183 get innerHTML() {
5857 return getInnerHTML(this); 6184 return getInnerHTML(this);
5858 }, 6185 },
5859 set innerHTML(value) { 6186 set innerHTML(value) {
5860 setInnerHTML(this, value); 6187 setInnerHTML(this, value);
5861 this.invalidateShadowRenderer(); 6188 this.invalidateShadowRenderer();
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
5980 nodeWrapper.nextSibling.previousSibling_ = nodeWrapper; 6307 nodeWrapper.nextSibling.previousSibling_ = nodeWrapper;
5981 6308
5982 if (parentNodeWrapper.lastChild === nodeWrapper) 6309 if (parentNodeWrapper.lastChild === nodeWrapper)
5983 parentNodeWrapper.lastChild_ = nodeWrapper; 6310 parentNodeWrapper.lastChild_ = nodeWrapper;
5984 if (parentNodeWrapper.firstChild === nodeWrapper) 6311 if (parentNodeWrapper.firstChild === nodeWrapper)
5985 parentNodeWrapper.firstChild_ = nodeWrapper; 6312 parentNodeWrapper.firstChild_ = nodeWrapper;
5986 6313
5987 parentNode.removeChild(node); 6314 parentNode.removeChild(node);
5988 } 6315 }
5989 6316
5990 var distributedChildNodesTable = new WeakMap(); 6317 var distributedNodesTable = new WeakMap();
5991 var eventParentsTable = new WeakMap(); 6318 var destinationInsertionPointsTable = new WeakMap();
5992 var insertionParentTable = new WeakMap();
5993 var rendererForHostTable = new WeakMap(); 6319 var rendererForHostTable = new WeakMap();
5994 6320
5995 function distributeChildToInsertionPoint(child, insertionPoint) { 6321 function resetDistributedNodes(insertionPoint) {
5996 getDistributedChildNodes(insertionPoint).push(child); 6322 distributedNodesTable.set(insertionPoint, []);
5997 assignToInsertionPoint(child, insertionPoint);
5998
5999 var eventParents = eventParentsTable.get(child);
6000 if (!eventParents)
6001 eventParentsTable.set(child, eventParents = []);
6002 eventParents.push(insertionPoint);
6003 } 6323 }
6004 6324
6005 function resetDistributedChildNodes(insertionPoint) { 6325 function getDistributedNodes(insertionPoint) {
6006 distributedChildNodesTable.set(insertionPoint, []); 6326 var rv = distributedNodesTable.get(insertionPoint);
6007 }
6008
6009 function getDistributedChildNodes(insertionPoint) {
6010 var rv = distributedChildNodesTable.get(insertionPoint);
6011 if (!rv) 6327 if (!rv)
6012 distributedChildNodesTable.set(insertionPoint, rv = []); 6328 distributedNodesTable.set(insertionPoint, rv = []);
6013 return rv; 6329 return rv;
6014 } 6330 }
6015 6331
6016 function getChildNodesSnapshot(node) { 6332 function getChildNodesSnapshot(node) {
6017 var result = [], i = 0; 6333 var result = [], i = 0;
6018 for (var child = node.firstChild; child; child = child.nextSibling) { 6334 for (var child = node.firstChild; child; child = child.nextSibling) {
6019 result[i++] = child; 6335 result[i++] = child;
6020 } 6336 }
6021 return result; 6337 return result;
6022 } 6338 }
6023 6339
6024 /**
6025 * Visits all nodes in the tree that fulfils the |predicate|. If the |visitor|
6026 * function returns |false| the traversal is aborted.
6027 * @param {!Node} tree
6028 * @param {function(!Node) : boolean} predicate
6029 * @param {function(!Node) : *} visitor
6030 */
6031 function visit(tree, predicate, visitor) {
6032 // This operates on logical DOM.
6033 for (var node = tree.firstChild; node; node = node.nextSibling) {
6034 if (predicate(node)) {
6035 if (visitor(node) === false)
6036 return;
6037 } else {
6038 visit(node, predicate, visitor);
6039 }
6040 }
6041 }
6042
6043 // Matching Insertion Points
6044 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#mat ching-insertion-points
6045
6046 // TODO(arv): Verify this... I don't remember why I picked this regexp.
6047 var selectorMatchRegExp = /^[*.:#[a-zA-Z_|]/;
6048
6049 var allowedPseudoRegExp = new RegExp('^:(' + [
6050 'link',
6051 'visited',
6052 'target',
6053 'enabled',
6054 'disabled',
6055 'checked',
6056 'indeterminate',
6057 'nth-child',
6058 'nth-last-child',
6059 'nth-of-type',
6060 'nth-last-of-type',
6061 'first-child',
6062 'last-child',
6063 'first-of-type',
6064 'last-of-type',
6065 'only-of-type',
6066 ].join('|') + ')');
6067
6068
6069 /**
6070 * @param {Element} node
6071 * @oaram {Element} point The insertion point element.
6072 * @return {boolean} Whether the node matches the insertion point.
6073 */
6074 function matchesCriteria(node, point) {
6075 var select = point.getAttribute('select');
6076 if (!select)
6077 return true;
6078
6079 // Here we know the select attribute is a non empty string.
6080 select = select.trim();
6081 if (!select)
6082 return true;
6083
6084 if (!(node instanceof Element))
6085 return false;
6086
6087 // The native matches function in IE9 does not correctly work with elements
6088 // that are not in the document.
6089 // TODO(arv): Implement matching in JS.
6090 // https://github.com/Polymer/ShadowDOM/issues/361
6091 if (select === '*' || select === node.localName)
6092 return true;
6093
6094 // TODO(arv): This does not seem right. Need to check for a simple selector.
6095 if (!selectorMatchRegExp.test(select))
6096 return false;
6097
6098 // TODO(arv): This no longer matches the spec.
6099 if (select[0] === ':' && !allowedPseudoRegExp.test(select))
6100 return false;
6101
6102 try {
6103 return node.matches(select);
6104 } catch (ex) {
6105 // Invalid selector.
6106 return false;
6107 }
6108 }
6109
6110 var request = oneOf(window, [ 6340 var request = oneOf(window, [
6111 'requestAnimationFrame', 6341 'requestAnimationFrame',
6112 'mozRequestAnimationFrame', 6342 'mozRequestAnimationFrame',
6113 'webkitRequestAnimationFrame', 6343 'webkitRequestAnimationFrame',
6114 'setTimeout' 6344 'setTimeout'
6115 ]); 6345 ]);
6116 6346
6117 var pendingDirtyRenderers = []; 6347 var pendingDirtyRenderers = [];
6118 var renderTimer; 6348 var renderTimer;
6119 6349
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
6244 } 6474 }
6245 6475
6246 ShadowRenderer.prototype = { 6476 ShadowRenderer.prototype = {
6247 6477
6248 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#r endering-shadow-trees 6478 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#r endering-shadow-trees
6249 render: function(opt_renderNode) { 6479 render: function(opt_renderNode) {
6250 if (!this.dirty) 6480 if (!this.dirty)
6251 return; 6481 return;
6252 6482
6253 this.invalidateAttributes(); 6483 this.invalidateAttributes();
6254 this.treeComposition();
6255 6484
6256 var host = this.host; 6485 var host = this.host;
6257 var shadowRoot = host.shadowRoot;
6258 6486
6259 this.associateNode(host); 6487 this.distribution(host);
6260 var topMostRenderer = !renderNode;
6261 var renderNode = opt_renderNode || new RenderNode(host); 6488 var renderNode = opt_renderNode || new RenderNode(host);
6489 this.buildRenderTree(renderNode, host);
6262 6490
6263 for (var node = shadowRoot.firstChild; node; node = node.nextSibling) { 6491 var topMostRenderer = !opt_renderNode;
6264 this.renderNode(shadowRoot, renderNode, node, false);
6265 }
6266
6267 if (topMostRenderer) 6492 if (topMostRenderer)
6268 renderNode.sync(); 6493 renderNode.sync();
6269 6494
6270 this.dirty = false; 6495 this.dirty = false;
6271 }, 6496 },
6272 6497
6273 get parentRenderer() { 6498 get parentRenderer() {
6274 return getTreeScope(this.host).renderer; 6499 return getTreeScope(this.host).renderer;
6275 }, 6500 },
6276 6501
6277 invalidate: function() { 6502 invalidate: function() {
6278 if (!this.dirty) { 6503 if (!this.dirty) {
6279 this.dirty = true; 6504 this.dirty = true;
6280 pendingDirtyRenderers.push(this); 6505 pendingDirtyRenderers.push(this);
6281 if (renderTimer) 6506 if (renderTimer)
6282 return; 6507 return;
6283 renderTimer = window[request](handleRequestAnimationFrame, 0); 6508 renderTimer = window[request](handleRequestAnimationFrame, 0);
6284 } 6509 }
6285 }, 6510 },
6286 6511
6287 renderNode: function(shadowRoot, renderNode, node, isNested) { 6512 // http://w3c.github.io/webcomponents/spec/shadow/#distribution-algorithms
6513 distribution: function(root) {
6514 this.resetAll(root);
6515 this.distributionResolution(root);
6516 },
6517
6518 resetAll: function(node) {
6519 if (isInsertionPoint(node))
6520 resetDistributedNodes(node);
6521 else
6522 resetDestinationInsertionPoints(node);
6523
6524 for (var child = node.firstChild; child; child = child.nextSibling) {
6525 this.resetAll(child);
6526 }
6527
6528 if (node.shadowRoot)
6529 this.resetAll(node.shadowRoot);
6530
6531 if (node.olderShadowRoot)
6532 this.resetAll(node.olderShadowRoot);
6533 },
6534
6535 // http://w3c.github.io/webcomponents/spec/shadow/#distribution-results
6536 distributionResolution: function(node) {
6288 if (isShadowHost(node)) { 6537 if (isShadowHost(node)) {
6289 renderNode = renderNode.append(node); 6538 var shadowHost = node;
6290 var renderer = getRendererForHost(node); 6539 // 1.1
6291 renderer.dirty = true; // Need to rerender due to reprojection. 6540 var pool = poolPopulation(shadowHost);
6292 renderer.render(renderNode); 6541
6293 } else if (isInsertionPoint(node)) { 6542 var shadowTrees = getShadowTrees(shadowHost);
6294 this.renderInsertionPoint(shadowRoot, renderNode, node, isNested); 6543
6295 } else if (isShadowInsertionPoint(node)) { 6544 // 1.2
6296 this.renderShadowInsertionPoint(shadowRoot, renderNode, node); 6545 for (var i = 0; i < shadowTrees.length; i++) {
6297 } else { 6546 // 1.2.1
6298 this.renderAsAnyDomTree(shadowRoot, renderNode, node, isNested); 6547 this.poolDistribution(shadowTrees[i], pool);
6548 }
6549
6550 // 1.3
6551 for (var i = shadowTrees.length - 1; i >= 0; i--) {
6552 var shadowTree = shadowTrees[i];
6553
6554 // 1.3.1
6555 // TODO(arv): We should keep the shadow insertion points on the
6556 // shadow root (or renderer) so we don't have to search the tree
6557 // every time.
6558 var shadow = getShadowInsertionPoint(shadowTree);
6559
6560 // 1.3.2
6561 if (shadow) {
6562
6563 // 1.3.2.1
6564 var olderShadowRoot = shadowTree.olderShadowRoot;
6565 if (olderShadowRoot) {
6566 // 1.3.2.1.1
6567 pool = poolPopulation(olderShadowRoot);
6568 }
6569
6570 // 1.3.2.2
6571 for (var j = 0; j < pool.length; j++) {
6572 // 1.3.2.2.1
6573 destributeNodeInto(pool[j], shadow);
6574 }
6575 }
6576
6577 // 1.3.3
6578 this.distributionResolution(shadowTree);
6579 }
6580 }
6581
6582 for (var child = node.firstChild; child; child = child.nextSibling) {
6583 this.distributionResolution(child);
6299 } 6584 }
6300 }, 6585 },
6301 6586
6302 renderAsAnyDomTree: function(shadowRoot, renderNode, node, isNested) { 6587 // http://w3c.github.io/webcomponents/spec/shadow/#dfn-pool-distribution-alg orithm
6303 renderNode = renderNode.append(node); 6588 poolDistribution: function (node, pool) {
6589 if (node instanceof HTMLShadowElement)
6590 return;
6591
6592 if (node instanceof HTMLContentElement) {
6593 var content = node;
6594 this.updateDependentAttributes(content.getAttribute('select'));
6595
6596 var anyDistributed = false;
6597
6598 // 1.1
6599 for (var i = 0; i < pool.length; i++) {
6600 var node = pool[i];
6601 if (!node)
6602 continue;
6603 if (matches(node, content)) {
6604 destributeNodeInto(node, content);
6605 pool[i] = undefined;
6606 anyDistributed = true;
6607 }
6608 }
6609
6610 // 1.2
6611 // Fallback content
6612 if (!anyDistributed) {
6613 for (var child = content.firstChild;
6614 child;
6615 child = child.nextSibling) {
6616 destributeNodeInto(child, content);
6617 }
6618 }
6619
6620 return;
6621 }
6622
6623 for (var child = node.firstChild; child; child = child.nextSibling) {
6624 this.poolDistribution(child, pool);
6625 }
6626 },
6627
6628 buildRenderTree: function(renderNode, node) {
6629 var children = this.compose(node);
6630 for (var i = 0; i < children.length; i++) {
6631 var child = children[i];
6632 var childRenderNode = renderNode.append(child);
6633 this.buildRenderTree(childRenderNode, child);
6634 }
6304 6635
6305 if (isShadowHost(node)) { 6636 if (isShadowHost(node)) {
6306 var renderer = getRendererForHost(node); 6637 var renderer = getRendererForHost(node);
6307 renderNode.skip = !renderer.dirty; 6638 renderer.dirty = false;
6308 renderer.render(renderNode); 6639 }
6309 } else { 6640
6310 for (var child = node.firstChild; child; child = child.nextSibling) { 6641 },
6311 this.renderNode(shadowRoot, renderNode, child, isNested); 6642
6643 compose: function(node) {
6644 var children = [];
6645 var p = node.shadowRoot || node;
6646 for (var child = p.firstChild; child; child = child.nextSibling) {
6647 if (isInsertionPoint(child)) {
6648 this.associateNode(p);
6649 var distributedNodes = getDistributedNodes(child);
6650 for (var j = 0; j < distributedNodes.length; j++) {
6651 var distributedNode = distributedNodes[j];
6652 if (isFinalDestination(child, distributedNode))
6653 children.push(distributedNode);
6654 }
6655 } else {
6656 children.push(child);
6312 } 6657 }
6313 } 6658 }
6314 }, 6659 return children;
6315
6316 renderInsertionPoint: function(shadowRoot, renderNode, insertionPoint,
6317 isNested) {
6318 var distributedChildNodes = getDistributedChildNodes(insertionPoint);
6319 if (distributedChildNodes.length) {
6320 this.associateNode(insertionPoint);
6321
6322 for (var i = 0; i < distributedChildNodes.length; i++) {
6323 var child = distributedChildNodes[i];
6324 if (isInsertionPoint(child) && isNested)
6325 this.renderInsertionPoint(shadowRoot, renderNode, child, isNested);
6326 else
6327 this.renderAsAnyDomTree(shadowRoot, renderNode, child, isNested);
6328 }
6329 } else {
6330 this.renderFallbackContent(shadowRoot, renderNode, insertionPoint);
6331 }
6332 this.associateNode(insertionPoint.parentNode);
6333 },
6334
6335 renderShadowInsertionPoint: function(shadowRoot, renderNode,
6336 shadowInsertionPoint) {
6337 var nextOlderTree = shadowRoot.olderShadowRoot;
6338 if (nextOlderTree) {
6339 assignToInsertionPoint(nextOlderTree, shadowInsertionPoint);
6340 this.associateNode(shadowInsertionPoint.parentNode);
6341 for (var node = nextOlderTree.firstChild;
6342 node;
6343 node = node.nextSibling) {
6344 this.renderNode(nextOlderTree, renderNode, node, true);
6345 }
6346 } else {
6347 this.renderFallbackContent(shadowRoot, renderNode,
6348 shadowInsertionPoint);
6349 }
6350 },
6351
6352 renderFallbackContent: function(shadowRoot, renderNode, fallbackHost) {
6353 this.associateNode(fallbackHost);
6354 this.associateNode(fallbackHost.parentNode);
6355 for (var node = fallbackHost.firstChild; node; node = node.nextSibling) {
6356 this.renderAsAnyDomTree(shadowRoot, renderNode, node, false);
6357 }
6358 }, 6660 },
6359 6661
6360 /** 6662 /**
6361 * Invalidates the attributes used to keep track of which attributes may 6663 * Invalidates the attributes used to keep track of which attributes may
6362 * cause the renderer to be invalidated. 6664 * cause the renderer to be invalidated.
6363 */ 6665 */
6364 invalidateAttributes: function() { 6666 invalidateAttributes: function() {
6365 this.attributes = Object.create(null); 6667 this.attributes = Object.create(null);
6366 }, 6668 },
6367 6669
(...skipping 20 matching lines...) Expand all
6388 attributes[name] = true; 6690 attributes[name] = true;
6389 }); 6691 });
6390 6692
6391 // Pseudo selectors have been removed from the spec. 6693 // Pseudo selectors have been removed from the spec.
6392 }, 6694 },
6393 6695
6394 dependsOnAttribute: function(name) { 6696 dependsOnAttribute: function(name) {
6395 return this.attributes[name]; 6697 return this.attributes[name];
6396 }, 6698 },
6397 6699
6398 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#d fn-distribution-algorithm
6399 distribute: function(tree, pool) {
6400 var self = this;
6401
6402 visit(tree, isActiveInsertionPoint,
6403 function(insertionPoint) {
6404 resetDistributedChildNodes(insertionPoint);
6405 self.updateDependentAttributes(
6406 insertionPoint.getAttribute('select'));
6407
6408 for (var i = 0; i < pool.length; i++) { // 1.2
6409 var node = pool[i]; // 1.2.1
6410 if (node === undefined) // removed
6411 continue;
6412 if (matchesCriteria(node, insertionPoint)) { // 1.2.2
6413 distributeChildToInsertionPoint(node, insertionPoint); // 1.2.2 .1
6414 pool[i] = undefined; // 1.2.2.2
6415 }
6416 }
6417 });
6418 },
6419
6420 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#d fn-tree-composition
6421 treeComposition: function () {
6422 var shadowHost = this.host;
6423 var tree = shadowHost.shadowRoot; // 1.
6424 var pool = []; // 2.
6425
6426 for (var child = shadowHost.firstChild;
6427 child;
6428 child = child.nextSibling) { // 3.
6429 if (isInsertionPoint(child)) { // 3.2.
6430 var reprojected = getDistributedChildNodes(child); // 3.2.1.
6431 // if reprojected is undef... reset it?
6432 if (!reprojected || !reprojected.length) // 3.2.2.
6433 reprojected = getChildNodesSnapshot(child);
6434 pool.push.apply(pool, reprojected); // 3.2.3.
6435 } else {
6436 pool.push(child); // 3.3.
6437 }
6438 }
6439
6440 var shadowInsertionPoint, point;
6441 while (tree) { // 4.
6442 // 4.1.
6443 shadowInsertionPoint = undefined; // Reset every iteration.
6444 visit(tree, isActiveShadowInsertionPoint, function(point) {
6445 shadowInsertionPoint = point;
6446 return false;
6447 });
6448 point = shadowInsertionPoint;
6449
6450 this.distribute(tree, pool); // 4.2.
6451 if (point) { // 4.3.
6452 var nextOlderTree = tree.olderShadowRoot; // 4.3.1.
6453 if (!nextOlderTree) {
6454 break; // 4.3.1.1.
6455 } else {
6456 tree = nextOlderTree; // 4.3.2.2.
6457 assignToInsertionPoint(tree, point); // 4.3.2.2.
6458 continue; // 4.3.2.3.
6459 }
6460 } else {
6461 break; // 4.4.
6462 }
6463 }
6464 },
6465
6466 associateNode: function(node) { 6700 associateNode: function(node) {
6467 node.impl.polymerShadowRenderer_ = this; 6701 node.impl.polymerShadowRenderer_ = this;
6468 } 6702 }
6469 }; 6703 };
6470 6704
6471 function isInsertionPoint(node) { 6705 // http://w3c.github.io/webcomponents/spec/shadow/#dfn-pool-population-algorit hm
6472 // Should this include <shadow>? 6706 function poolPopulation(node) {
6473 return node instanceof HTMLContentElement; 6707 var pool = [];
6708 for (var child = node.firstChild; child; child = child.nextSibling) {
6709 if (isInsertionPoint(child)) {
6710 pool.push.apply(pool, getDistributedNodes(child));
6711 } else {
6712 pool.push(child);
6713 }
6714 }
6715 return pool;
6474 } 6716 }
6475 6717
6476 function isActiveInsertionPoint(node) { 6718 function getShadowInsertionPoint(node) {
6477 // <content> inside another <content> or <shadow> is considered inactive. 6719 if (node instanceof HTMLShadowElement)
6478 return node instanceof HTMLContentElement; 6720 return node;
6721 if (node instanceof HTMLContentElement)
6722 return null;
6723 for (var child = node.firstChild; child; child = child.nextSibling) {
6724 var res = getShadowInsertionPoint(child);
6725 if (res)
6726 return res;
6727 }
6728 return null;
6479 } 6729 }
6480 6730
6481 function isShadowInsertionPoint(node) { 6731 function destributeNodeInto(child, insertionPoint) {
6482 return node instanceof HTMLShadowElement; 6732 getDistributedNodes(insertionPoint).push(child);
6733 var points = destinationInsertionPointsTable.get(child);
6734 if (!points)
6735 destinationInsertionPointsTable.set(child, [insertionPoint]);
6736 else
6737 points.push(insertionPoint);
6483 } 6738 }
6484 6739
6485 function isActiveShadowInsertionPoint(node) { 6740 function getDestinationInsertionPoints(node) {
6486 // <shadow> inside another <content> or <shadow> is considered inactive. 6741 return destinationInsertionPointsTable.get(node);
6487 return node instanceof HTMLShadowElement; 6742 }
6743
6744 function resetDestinationInsertionPoints(node) {
6745 // IE11 crashes when delete is used.
6746 destinationInsertionPointsTable.set(node, undefined);
6747 }
6748
6749 // AllowedSelectors :
6750 // TypeSelector
6751 // *
6752 // ClassSelector
6753 // IDSelector
6754 // AttributeSelector
6755 var selectorStartCharRe = /^[*.#[a-zA-Z_|]/;
6756
6757 function matches(node, contentElement) {
6758 var select = contentElement.getAttribute('select');
6759 if (!select)
6760 return true;
6761
6762 // Here we know the select attribute is a non empty string.
6763 select = select.trim();
6764 if (!select)
6765 return true;
6766
6767 if (!(node instanceof Element))
6768 return false;
6769
6770 if (!selectorStartCharRe.test(select))
6771 return false;
6772
6773 try {
6774 return node.matches(select);
6775 } catch (ex) {
6776 // Invalid selector.
6777 return false;
6778 }
6779 }
6780
6781 function isFinalDestination(insertionPoint, node) {
6782 var points = getDestinationInsertionPoints(node);
6783 return points && points[points.length - 1] === insertionPoint;
6784 }
6785
6786 function isInsertionPoint(node) {
6787 return node instanceof HTMLContentElement ||
6788 node instanceof HTMLShadowElement;
6488 } 6789 }
6489 6790
6490 function isShadowHost(shadowHost) { 6791 function isShadowHost(shadowHost) {
6491 return shadowHost.shadowRoot; 6792 return shadowHost.shadowRoot;
6492 } 6793 }
6493 6794
6795 // Returns the shadow trees as an array, with the youngest tree at the
6796 // beginning of the array.
6494 function getShadowTrees(host) { 6797 function getShadowTrees(host) {
6495 var trees = []; 6798 var trees = [];
6496 6799
6497 for (var tree = host.shadowRoot; tree; tree = tree.olderShadowRoot) { 6800 for (var tree = host.shadowRoot; tree; tree = tree.olderShadowRoot) {
6498 trees.push(tree); 6801 trees.push(tree);
6499 } 6802 }
6500 return trees; 6803 return trees;
6501 } 6804 }
6502 6805
6503 function assignToInsertionPoint(tree, point) {
6504 insertionParentTable.set(tree, point);
6505 }
6506
6507 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#ren dering-shadow-trees
6508 function render(host) { 6806 function render(host) {
6509 new ShadowRenderer(host).render(); 6807 new ShadowRenderer(host).render();
6510 }; 6808 };
6511 6809
6512 // Need to rerender shadow host when: 6810 // Need to rerender shadow host when:
6513 // 6811 //
6514 // - a direct child to the ShadowRoot is added or removed 6812 // - a direct child to the ShadowRoot is added or removed
6515 // - a direct child to the host is added or removed 6813 // - a direct child to the host is added or removed
6516 // - a new shadow root is created 6814 // - a new shadow root is created
6517 // - a direct child to a content/shadow element is added or removed 6815 // - a direct child to a content/shadow element is added or removed
6518 // - a sibling to a content/shadow element is added or removed 6816 // - a sibling to a content/shadow element is added or removed
6519 // - content[select] is changed 6817 // - content[select] is changed
6520 // - an attribute in a direct child to a host is modified 6818 // - an attribute in a direct child to a host is modified
6521 6819
6522 /** 6820 /**
6523 * This gets called when a node was added or removed to it. 6821 * This gets called when a node was added or removed to it.
6524 */ 6822 */
6525 Node.prototype.invalidateShadowRenderer = function(force) { 6823 Node.prototype.invalidateShadowRenderer = function(force) {
6526 var renderer = this.impl.polymerShadowRenderer_; 6824 var renderer = this.impl.polymerShadowRenderer_;
6527 if (renderer) { 6825 if (renderer) {
6528 renderer.invalidate(); 6826 renderer.invalidate();
6529 return true; 6827 return true;
6530 } 6828 }
6531 6829
6532 return false; 6830 return false;
6533 }; 6831 };
6534 6832
6535 HTMLContentElement.prototype.getDistributedNodes = function() { 6833 HTMLContentElement.prototype.getDistributedNodes =
6834 HTMLShadowElement.prototype.getDistributedNodes = function() {
6536 // TODO(arv): We should only rerender the dirty ancestor renderers (from 6835 // TODO(arv): We should only rerender the dirty ancestor renderers (from
6537 // the root and down). 6836 // the root and down).
6538 renderAllPending(); 6837 renderAllPending();
6539 return getDistributedChildNodes(this); 6838 return getDistributedNodes(this);
6540 }; 6839 };
6541 6840
6542 HTMLShadowElement.prototype.nodeIsInserted_ = 6841 Element.prototype.getDestinationInsertionPoints = function() {
6543 HTMLContentElement.prototype.nodeIsInserted_ = function() { 6842 renderAllPending();
6843 return getDestinationInsertionPoints(this) || [];
6844 };
6845
6846 HTMLContentElement.prototype.nodeIsInserted_ =
6847 HTMLShadowElement.prototype.nodeIsInserted_ = function() {
6544 // Invalidate old renderer if any. 6848 // Invalidate old renderer if any.
6545 this.invalidateShadowRenderer(); 6849 this.invalidateShadowRenderer();
6546 6850
6547 var shadowRoot = getShadowRootAncestor(this); 6851 var shadowRoot = getShadowRootAncestor(this);
6548 var renderer; 6852 var renderer;
6549 if (shadowRoot) 6853 if (shadowRoot)
6550 renderer = getRendererForShadowRoot(shadowRoot); 6854 renderer = getRendererForShadowRoot(shadowRoot);
6551 this.impl.polymerShadowRenderer_ = renderer; 6855 this.impl.polymerShadowRenderer_ = renderer;
6552 if (renderer) 6856 if (renderer)
6553 renderer.invalidate(); 6857 renderer.invalidate();
6554 }; 6858 };
6555 6859
6556 scope.eventParentsTable = eventParentsTable;
6557 scope.getRendererForHost = getRendererForHost; 6860 scope.getRendererForHost = getRendererForHost;
6558 scope.getShadowTrees = getShadowTrees; 6861 scope.getShadowTrees = getShadowTrees;
6559 scope.insertionParentTable = insertionParentTable;
6560 scope.renderAllPending = renderAllPending; 6862 scope.renderAllPending = renderAllPending;
6561 6863
6864 scope.getDestinationInsertionPoints = getDestinationInsertionPoints;
6865
6562 // Exposed for testing 6866 // Exposed for testing
6563 scope.visual = { 6867 scope.visual = {
6564 insertBefore: insertBefore, 6868 insertBefore: insertBefore,
6565 remove: remove, 6869 remove: remove,
6566 }; 6870 };
6567 6871
6568 })(window.ShadowDOMPolyfill); 6872 })(window.ShadowDOMPolyfill);
6569 6873
6570 // Copyright 2013 The Polymer Authors. All rights reserved. 6874 // Copyright 2013 The Polymer Authors. All rights reserved.
6571 // Use of this source code is goverened by a BSD-style 6875 // Use of this source code is goverened by a BSD-style
(...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after
6949 7253
6950 mixin(Document.prototype, { 7254 mixin(Document.prototype, {
6951 get implementation() { 7255 get implementation() {
6952 var implementation = implementationTable.get(this); 7256 var implementation = implementationTable.get(this);
6953 if (implementation) 7257 if (implementation)
6954 return implementation; 7258 return implementation;
6955 implementation = 7259 implementation =
6956 new DOMImplementation(unwrap(this).implementation); 7260 new DOMImplementation(unwrap(this).implementation);
6957 implementationTable.set(this, implementation); 7261 implementationTable.set(this, implementation);
6958 return implementation; 7262 return implementation;
7263 },
7264
7265 get defaultView() {
7266 return wrap(unwrap(this).defaultView);
6959 } 7267 }
6960 }); 7268 });
6961 7269
6962 registerWrapper(window.Document, Document, 7270 registerWrapper(window.Document, Document,
6963 document.implementation.createHTMLDocument('')); 7271 document.implementation.createHTMLDocument(''));
6964 7272
6965 // Both WebKit and Gecko uses HTMLDocument for document. HTML5/DOM only has 7273 // Both WebKit and Gecko uses HTMLDocument for document. HTML5/DOM only has
6966 // one Document interface and IE implements the standard correctly. 7274 // one Document interface and IE implements the standard correctly.
6967 if (window.HTMLDocument) 7275 if (window.HTMLDocument)
6968 registerWrapper(window.HTMLDocument, Document); 7276 registerWrapper(window.HTMLDocument, Document);
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
7064 mixin(Window.prototype, { 7372 mixin(Window.prototype, {
7065 getComputedStyle: function(el, pseudo) { 7373 getComputedStyle: function(el, pseudo) {
7066 renderAllPending(); 7374 renderAllPending();
7067 return originalGetComputedStyle.call(unwrap(this), unwrapIfNeeded(el), 7375 return originalGetComputedStyle.call(unwrap(this), unwrapIfNeeded(el),
7068 pseudo); 7376 pseudo);
7069 }, 7377 },
7070 getSelection: function() { 7378 getSelection: function() {
7071 renderAllPending(); 7379 renderAllPending();
7072 return new Selection(originalGetSelection.call(unwrap(this))); 7380 return new Selection(originalGetSelection.call(unwrap(this)));
7073 }, 7381 },
7382
7383 get document() {
7384 return wrap(unwrap(this).document);
7385 }
7074 }); 7386 });
7075 7387
7076 registerWrapper(OriginalWindow, Window); 7388 registerWrapper(OriginalWindow, Window, window);
7077 7389
7078 scope.wrappers.Window = Window; 7390 scope.wrappers.Window = Window;
7079 7391
7080 })(window.ShadowDOMPolyfill); 7392 })(window.ShadowDOMPolyfill);
7081 7393
7082 /** 7394 /**
7083 * Copyright 2014 The Polymer Authors. All rights reserved. 7395 * Copyright 2014 The Polymer Authors. All rights reserved.
7084 * Use of this source code is goverened by a BSD-style 7396 * Use of this source code is goverened by a BSD-style
7085 * license that can be found in the LICENSE file. 7397 * license that can be found in the LICENSE file.
7086 */ 7398 */
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
7207 7519
7208 Object.keys(elements).forEach(overrideConstructor); 7520 Object.keys(elements).forEach(overrideConstructor);
7209 7521
7210 Object.getOwnPropertyNames(scope.wrappers).forEach(function(name) { 7522 Object.getOwnPropertyNames(scope.wrappers).forEach(function(name) {
7211 window[name] = scope.wrappers[name] 7523 window[name] = scope.wrappers[name]
7212 }); 7524 });
7213 7525
7214 })(window.ShadowDOMPolyfill); 7526 })(window.ShadowDOMPolyfill);
7215 7527
7216 /* 7528 /*
7217 * Copyright 2013 The Polymer Authors. All rights reserved. 7529 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
7218 * Use of this source code is governed by a BSD-style 7530 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
7219 * license that can be found in the LICENSE file. 7531 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
7532 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
7533 * Code distributed by Google as part of the polymer project is also
7534 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
7220 */ 7535 */
7536
7221 (function() { 7537 (function() {
7222 7538
7223 // convenient global 7539 // convenient global
7224 window.wrap = ShadowDOMPolyfill.wrapIfNeeded; 7540 window.wrap = ShadowDOMPolyfill.wrapIfNeeded;
7225 window.unwrap = ShadowDOMPolyfill.unwrapIfNeeded; 7541 window.unwrap = ShadowDOMPolyfill.unwrapIfNeeded;
7226 7542
7227 // users may want to customize other types 7543 // users may want to customize other types
7228 // TODO(sjmiles): 'button' is now supported by ShadowDOMPolyfill, but 7544 // TODO(sjmiles): 'button' is now supported by ShadowDOMPolyfill, but
7229 // I've left this code here in case we need to temporarily patch another 7545 // I've left this code here in case we need to temporarily patch another
7230 // type 7546 // type
(...skipping 16 matching lines...) Expand all
7247 Element.prototype.createShadowRoot = function() { 7563 Element.prototype.createShadowRoot = function() {
7248 var root = originalCreateShadowRoot.call(this); 7564 var root = originalCreateShadowRoot.call(this);
7249 CustomElements.watchShadow(this); 7565 CustomElements.watchShadow(this);
7250 return root; 7566 return root;
7251 }; 7567 };
7252 7568
7253 Element.prototype.webkitCreateShadowRoot = Element.prototype.createShadowRoot; 7569 Element.prototype.webkitCreateShadowRoot = Element.prototype.createShadowRoot;
7254 })(); 7570 })();
7255 7571
7256 /* 7572 /*
7257 * Copyright 2012 The Polymer Authors. All rights reserved. 7573 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
7258 * Use of this source code is governed by a BSD-style 7574 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
7259 * license that can be found in the LICENSE file. 7575 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
7576 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
7577 * Code distributed by Google as part of the polymer project is also
7578 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
7260 */ 7579 */
7261 7580
7262 /* 7581 /*
7263 This is a limited shim for ShadowDOM css styling. 7582 This is a limited shim for ShadowDOM css styling.
7264 https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#style s 7583 https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#style s
7265 7584
7266 The intention here is to support only the styling features which can be 7585 The intention here is to support only the styling features which can be
7267 relatively simply implemented. The goal is to allow users to avoid the 7586 relatively simply implemented. The goal is to allow users to avoid the
7268 most obvious pitfalls and do so without compromising performance significantly . 7587 most obvious pitfalls and do so without compromising performance significantly .
7269 For ShadowDOM styling that's not covered here, a set of best practices 7588 For ShadowDOM styling that's not covered here, a set of best practices
(...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after
7665 } 7984 }
7666 return cssText; 7985 return cssText;
7667 }, 7986 },
7668 scopeSelector: function(selector, scopeSelector, strict) { 7987 scopeSelector: function(selector, scopeSelector, strict) {
7669 var r = [], parts = selector.split(','); 7988 var r = [], parts = selector.split(',');
7670 parts.forEach(function(p) { 7989 parts.forEach(function(p) {
7671 p = p.trim(); 7990 p = p.trim();
7672 if (this.selectorNeedsScoping(p, scopeSelector)) { 7991 if (this.selectorNeedsScoping(p, scopeSelector)) {
7673 p = (strict && !p.match(polyfillHostNoCombinator)) ? 7992 p = (strict && !p.match(polyfillHostNoCombinator)) ?
7674 this.applyStrictSelectorScope(p, scopeSelector) : 7993 this.applyStrictSelectorScope(p, scopeSelector) :
7675 this.applySimpleSelectorScope(p, scopeSelector); 7994 this.applySelectorScope(p, scopeSelector);
7676 } 7995 }
7677 r.push(p); 7996 r.push(p);
7678 }, this); 7997 }, this);
7679 return r.join(', '); 7998 return r.join(', ');
7680 }, 7999 },
7681 selectorNeedsScoping: function(selector, scopeSelector) { 8000 selectorNeedsScoping: function(selector, scopeSelector) {
8001 if (Array.isArray(scopeSelector)) {
8002 return true;
8003 }
7682 var re = this.makeScopeMatcher(scopeSelector); 8004 var re = this.makeScopeMatcher(scopeSelector);
7683 return !selector.match(re); 8005 return !selector.match(re);
7684 }, 8006 },
7685 makeScopeMatcher: function(scopeSelector) { 8007 makeScopeMatcher: function(scopeSelector) {
7686 scopeSelector = scopeSelector.replace(/\[/g, '\\[').replace(/\[/g, '\\]'); 8008 scopeSelector = scopeSelector.replace(/\[/g, '\\[').replace(/\[/g, '\\]');
7687 return new RegExp('^(' + scopeSelector + ')' + selectorReSuffix, 'm'); 8009 return new RegExp('^(' + scopeSelector + ')' + selectorReSuffix, 'm');
7688 }, 8010 },
8011 applySelectorScope: function(selector, selectorScope) {
8012 return Array.isArray(selectorScope) ?
8013 this.applySelectorScopeList(selector, selectorScope) :
8014 this.applySimpleSelectorScope(selector, selectorScope);
8015 },
8016 // apply an array of selectors
8017 applySelectorScopeList: function(selector, scopeSelectorList) {
8018 var r = [];
8019 for (var i=0, s; (s=scopeSelectorList[i]); i++) {
8020 r.push(this.applySimpleSelectorScope(selector, s));
8021 }
8022 return r.join(', ');
8023 },
7689 // scope via name and [is=name] 8024 // scope via name and [is=name]
7690 applySimpleSelectorScope: function(selector, scopeSelector) { 8025 applySimpleSelectorScope: function(selector, scopeSelector) {
7691 if (selector.match(polyfillHostRe)) { 8026 if (selector.match(polyfillHostRe)) {
7692 selector = selector.replace(polyfillHostNoCombinator, scopeSelector); 8027 selector = selector.replace(polyfillHostNoCombinator, scopeSelector);
7693 return selector.replace(polyfillHostRe, scopeSelector + ' '); 8028 return selector.replace(polyfillHostRe, scopeSelector + ' ');
7694 } else { 8029 } else {
7695 return scopeSelector + ' ' + selector; 8030 return scopeSelector + ' ' + selector;
7696 } 8031 }
7697 }, 8032 },
7698 // return a selector with [name] suffix on each simple selector 8033 // return a selector with [name] suffix on each simple selector
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after
7984 } 8319 }
7985 8320
7986 } 8321 }
7987 }); 8322 });
7988 } 8323 }
7989 8324
7990 // exports 8325 // exports
7991 scope.ShadowCSS = ShadowCSS; 8326 scope.ShadowCSS = ShadowCSS;
7992 8327
7993 })(window.Platform); 8328 })(window.Platform);
8329
7994 } else { 8330 } else {
7995 /* 8331 /*
7996 * Copyright 2013 The Polymer Authors. All rights reserved. 8332 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
7997 * Use of this source code is governed by a BSD-style 8333 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
7998 * license that can be found in the LICENSE file. 8334 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
8335 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
8336 * Code distributed by Google as part of the polymer project is also
8337 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
7999 */ 8338 */
8000 (function() {
8001 8339
8002 // poor man's adapter for template.content on various platform scenarios 8340 (function(scope) {
8003 window.templateContent = window.templateContent || function(inTemplate) {
8004 return inTemplate.content;
8005 };
8006 8341
8007 // so we can call wrap/unwrap without testing for ShadowDOMPolyfill 8342 // so we can call wrap/unwrap without testing for ShadowDOMPolyfill
8008
8009 window.wrap = window.unwrap = function(n){ 8343 window.wrap = window.unwrap = function(n){
8010 return n; 8344 return n;
8011 } 8345 }
8012 8346
8013 addEventListener('DOMContentLoaded', function() { 8347 addEventListener('DOMContentLoaded', function() {
8014 if (CustomElements.useNative === false) { 8348 if (CustomElements.useNative === false) {
8015 var originalCreateShadowRoot = Element.prototype.createShadowRoot; 8349 var originalCreateShadowRoot = Element.prototype.createShadowRoot;
8016 Element.prototype.createShadowRoot = function() { 8350 Element.prototype.createShadowRoot = function() {
8017 var root = originalCreateShadowRoot.call(this); 8351 var root = originalCreateShadowRoot.call(this);
8018 CustomElements.watchShadow(this); 8352 CustomElements.watchShadow(this);
8019 return root; 8353 return root;
8020 }; 8354 };
8021 } 8355 }
8022 }); 8356 });
8023 8357
8024 window.templateContent = function(inTemplate) { 8358 Platform.templateContent = function(inTemplate) {
8025 // if MDV exists, it may need to boostrap this template to reveal content 8359 // if MDV exists, it may need to boostrap this template to reveal content
8026 if (window.HTMLTemplateElement && HTMLTemplateElement.bootstrap) { 8360 if (window.HTMLTemplateElement && HTMLTemplateElement.bootstrap) {
8027 HTMLTemplateElement.bootstrap(inTemplate); 8361 HTMLTemplateElement.bootstrap(inTemplate);
8028 } 8362 }
8029 // fallback when there is no Shadow DOM polyfill, no MDV polyfill, and no 8363 // fallback when there is no Shadow DOM polyfill, no MDV polyfill, and no
8030 // native template support 8364 // native template support
8031 if (!inTemplate.content && !inTemplate._content) { 8365 if (!inTemplate.content && !inTemplate._content) {
8032 var frag = document.createDocumentFragment(); 8366 var frag = document.createDocumentFragment();
8033 while (inTemplate.firstChild) { 8367 while (inTemplate.firstChild) {
8034 frag.appendChild(inTemplate.firstChild); 8368 frag.appendChild(inTemplate.firstChild);
8035 } 8369 }
8036 inTemplate._content = frag; 8370 inTemplate._content = frag;
8037 } 8371 }
8038 return inTemplate.content || inTemplate._content; 8372 return inTemplate.content || inTemplate._content;
8039 }; 8373 };
8040 8374
8041 })(); 8375 })(window.Platform);
8376
8042 } 8377 }
8043 /* Any copyright is dedicated to the Public Domain. 8378 /* Any copyright is dedicated to the Public Domain.
8044 * http://creativecommons.org/publicdomain/zero/1.0/ */ 8379 * http://creativecommons.org/publicdomain/zero/1.0/ */
8045 8380
8046 (function(scope) { 8381 (function(scope) {
8047 'use strict'; 8382 'use strict';
8048 8383
8049 // feature detect for URL constructor 8384 // feature detect for URL constructor
8050 var hasWorkingUrl = false; 8385 var hasWorkingUrl = false;
8051 if (!scope.forceJURL) { 8386 if (!scope.forceJURL) {
(...skipping 548 matching lines...) Expand 10 before | Expand all | Expand 10 after
8600 hash = hash.slice(1); 8935 hash = hash.slice(1);
8601 parse.call(this, hash, 'fragment'); 8936 parse.call(this, hash, 'fragment');
8602 } 8937 }
8603 }; 8938 };
8604 8939
8605 scope.URL = jURL; 8940 scope.URL = jURL;
8606 8941
8607 })(window); 8942 })(window);
8608 8943
8609 /* 8944 /*
8610 * Copyright 2013 The Polymer Authors. All rights reserved. 8945 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
8611 * Use of this source code is governed by a BSD-style 8946 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
8612 * license that can be found in the LICENSE file. 8947 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
8948 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
8949 * Code distributed by Google as part of the polymer project is also
8950 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
8613 */ 8951 */
8614 8952
8615 (function(scope) { 8953 (function(scope) {
8616 8954
8617 // Old versions of iOS do not have bind. 8955 // Old versions of iOS do not have bind.
8618 8956
8619 if (!Function.prototype.bind) { 8957 if (!Function.prototype.bind) {
8620 Function.prototype.bind = function(scope) { 8958 Function.prototype.bind = function(scope) {
8621 var self = this; 8959 var self = this;
8622 var args = Array.prototype.slice.call(arguments, 1); 8960 var args = Array.prototype.slice.call(arguments, 1);
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
8658 var pd = Object.getOwnPropertyDescriptor(inObject, inName); 8996 var pd = Object.getOwnPropertyDescriptor(inObject, inName);
8659 return pd || getPropertyDescriptor(Object.getPrototypeOf(inObject), inName); 8997 return pd || getPropertyDescriptor(Object.getPrototypeOf(inObject), inName);
8660 } 8998 }
8661 } 8999 }
8662 9000
8663 // export 9001 // export
8664 9002
8665 scope.mixin = mixin; 9003 scope.mixin = mixin;
8666 9004
8667 })(window.Platform); 9005 })(window.Platform);
8668 // Copyright 2011 Google Inc. 9006
8669 // 9007 /*
8670 // Licensed under the Apache License, Version 2.0 (the "License"); 9008 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
8671 // you may not use this file except in compliance with the License. 9009 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
8672 // You may obtain a copy of the License at 9010 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
8673 // 9011 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
8674 // http://www.apache.org/licenses/LICENSE-2.0 9012 * Code distributed by Google as part of the polymer project is also
8675 // 9013 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
8676 // Unless required by applicable law or agreed to in writing, software 9014 */
8677 // distributed under the License is distributed on an "AS IS" BASIS,
8678 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8679 // See the License for the specific language governing permissions and
8680 // limitations under the License.
8681 9015
8682 (function(scope) { 9016 (function(scope) {
8683 9017
8684 'use strict'; 9018 'use strict';
8685 9019
8686 // polyfill DOMTokenList 9020 // polyfill DOMTokenList
8687 // * add/remove: allow these methods to take multiple classNames 9021 // * add/remove: allow these methods to take multiple classNames
8688 // * toggle: add a 2nd argument which forces the given state rather 9022 // * toggle: add a 2nd argument which forces the given state rather
8689 // than toggling. 9023 // than toggling.
8690 9024
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
8806 }; 9140 };
8807 } 9141 }
8808 }); 9142 });
8809 9143
8810 // exports 9144 // exports
8811 scope.createDOM = createDOM; 9145 scope.createDOM = createDOM;
8812 9146
8813 })(window.Platform); 9147 })(window.Platform);
8814 9148
8815 /* 9149 /*
8816 * Copyright 2013 The Polymer Authors. All rights reserved. 9150 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
8817 * Use of this source code is governed by a BSD-style 9151 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
8818 * license that can be found in the LICENSE file. 9152 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
9153 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
9154 * Code distributed by Google as part of the polymer project is also
9155 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
8819 */ 9156 */
8820 9157
8821 // poor man's adapter for template.content on various platform scenarios 9158 // poor man's adapter for template.content on various platform scenarios
8822 window.templateContent = window.templateContent || function(inTemplate) { 9159 (function(scope) {
8823 return inTemplate.content; 9160 scope.templateContent = scope.templateContent || function(inTemplate) {
8824 }; 9161 return inTemplate.content;
9162 };
9163 })(window.Platform);
9164
9165 /*
9166 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
9167 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
9168 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
9169 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
9170 * Code distributed by Google as part of the polymer project is also
9171 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
9172 */
9173
8825 (function(scope) { 9174 (function(scope) {
8826 9175
8827 scope = scope || (window.Inspector = {}); 9176 scope = scope || (window.Inspector = {});
8828 9177
8829 var inspector; 9178 var inspector;
8830 9179
8831 window.sinspect = function(inNode, inProxy) { 9180 window.sinspect = function(inNode, inProxy) {
8832 if (!inspector) { 9181 if (!inspector) {
8833 inspector = window.open('', 'ShadowDOM Inspector', null, true); 9182 inspector = window.open('', 'ShadowDOM Inspector', null, true);
8834 inspector.document.write(inspectorHTML); 9183 inspector.document.write(inspectorHTML);
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
9004 console.dir(this); 9353 console.dir(this);
9005 } 9354 }
9006 }; 9355 };
9007 9356
9008 // export 9357 // export
9009 9358
9010 scope.output = output; 9359 scope.output = output;
9011 9360
9012 })(window.Inspector); 9361 })(window.Inspector);
9013 9362
9363 /*
9364 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
9365 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
9366 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
9367 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
9368 * Code distributed by Google as part of the polymer project is also
9369 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
9370 */
9014 9371
9015
9016 /*
9017 * Copyright 2013 The Polymer Authors. All rights reserved.
9018 * Use of this source code is governed by a BSD-style
9019 * license that can be found in the LICENSE file.
9020 */
9021 (function(scope) { 9372 (function(scope) {
9022 9373
9023 // TODO(sorvell): It's desireable to provide a default stylesheet 9374 // TODO(sorvell): It's desireable to provide a default stylesheet
9024 // that's convenient for styling unresolved elements, but 9375 // that's convenient for styling unresolved elements, but
9025 // it's cumbersome to have to include this manually in every page. 9376 // it's cumbersome to have to include this manually in every page.
9026 // It would make sense to put inside some HTMLImport but 9377 // It would make sense to put inside some HTMLImport but
9027 // the HTMLImports polyfill does not allow loading of stylesheets 9378 // the HTMLImports polyfill does not allow loading of stylesheets
9028 // that block rendering. Therefore this injection is tolerated here. 9379 // that block rendering. Therefore this injection is tolerated here.
9029 9380
9030 var style = document.createElement('style'); 9381 var style = document.createElement('style');
9031 style.textContent = '' 9382 style.textContent = ''
9032 + 'body {' 9383 + 'body {'
9033 + 'transition: opacity ease-in 0.2s;' 9384 + 'transition: opacity ease-in 0.2s;'
9034 + ' } \n' 9385 + ' } \n'
9035 + 'body[unresolved] {' 9386 + 'body[unresolved] {'
9036 + 'opacity: 0; display: block; overflow: hidden;' 9387 + 'opacity: 0; display: block; overflow: hidden;'
9037 + ' } \n' 9388 + ' } \n'
9038 ; 9389 ;
9039 var head = document.querySelector('head'); 9390 var head = document.querySelector('head');
9040 head.insertBefore(style, head.firstChild); 9391 head.insertBefore(style, head.firstChild);
9041 9392
9042 })(Platform); 9393 })(Platform);
9043 9394
9395 /*
9396 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
9397 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
9398 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
9399 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
9400 * Code distributed by Google as part of the polymer project is also
9401 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
9402 */
9403
9044 (function(scope) { 9404 (function(scope) {
9045 9405
9046 function withDependencies(task, depends) { 9406 function withDependencies(task, depends) {
9047 depends = depends || []; 9407 depends = depends || [];
9048 if (!depends.map) { 9408 if (!depends.map) {
9049 depends = [depends]; 9409 depends = [depends];
9050 } 9410 }
9051 return task.apply(this, depends.map(marshal)); 9411 return task.apply(this, depends.map(marshal));
9052 } 9412 }
9053 9413
(...skipping 27 matching lines...) Expand all
9081 }); 9441 });
9082 }; 9442 };
9083 9443
9084 // exports 9444 // exports
9085 9445
9086 scope.marshal = marshal; 9446 scope.marshal = marshal;
9087 scope.module = module; 9447 scope.module = module;
9088 scope.using = using; 9448 scope.using = using;
9089 9449
9090 })(window); 9450 })(window);
9451
9091 /* 9452 /*
9092 * Copyright 2013 The Polymer Authors. All rights reserved. 9453 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
9093 * Use of this source code is governed by a BSD-style 9454 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
9094 * license that can be found in the LICENSE file. 9455 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
9456 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
9457 * Code distributed by Google as part of the polymer project is also
9458 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
9095 */ 9459 */
9460
9096 (function(scope) { 9461 (function(scope) {
9097 9462
9098 var iterations = 0; 9463 var iterations = 0;
9099 var callbacks = []; 9464 var callbacks = [];
9100 var twiddle = document.createTextNode(''); 9465 var twiddle = document.createTextNode('');
9101 9466
9102 function endOfMicrotask(callback) { 9467 function endOfMicrotask(callback) {
9103 twiddle.textContent = iterations++; 9468 twiddle.textContent = iterations++;
9104 callbacks.push(callback); 9469 callbacks.push(callback);
9105 } 9470 }
9106 9471
9107 function atEndOfMicrotask() { 9472 function atEndOfMicrotask() {
9108 while (callbacks.length) { 9473 while (callbacks.length) {
9109 callbacks.shift()(); 9474 callbacks.shift()();
9110 } 9475 }
9111 } 9476 }
9112 9477
9113 new (window.MutationObserver || JsMutationObserver)(atEndOfMicrotask) 9478 new (window.MutationObserver || JsMutationObserver)(atEndOfMicrotask)
9114 .observe(twiddle, {characterData: true}) 9479 .observe(twiddle, {characterData: true})
9115 ; 9480 ;
9116 9481
9117 // exports 9482 // exports
9118 9483
9119 scope.endOfMicrotask = endOfMicrotask; 9484 scope.endOfMicrotask = endOfMicrotask;
9120 9485
9121 })(Platform); 9486 })(Platform);
9122 9487
9123 9488
9124 /* 9489 /*
9125 * Copyright 2013 The Polymer Authors. All rights reserved. 9490 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
9126 * Use of this source code is governed by a BSD-style 9491 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
9127 * license that can be found in the LICENSE file. 9492 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
9493 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
9494 * Code distributed by Google as part of the polymer project is also
9495 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
9128 */ 9496 */
9129 9497
9130 (function(scope) { 9498 (function(scope) {
9131 9499
9132 var urlResolver = { 9500 var urlResolver = {
9133 resolveDom: function(root, url) { 9501 resolveDom: function(root, url) {
9134 url = url || root.ownerDocument.baseURI; 9502 url = url || root.ownerDocument.baseURI;
9135 this.resolveAttributes(root, url); 9503 this.resolveAttributes(root, url);
9136 this.resolveStyles(root, url); 9504 this.resolveStyles(root, url);
9137 // handle template.content 9505 // handle template.content
(...skipping 14 matching lines...) Expand all
9152 if (styles) { 9520 if (styles) {
9153 for (var i = 0, l = styles.length, s; (i < l) && (s = styles[i]); i++) { 9521 for (var i = 0, l = styles.length, s; (i < l) && (s = styles[i]); i++) {
9154 this.resolveStyle(s, url); 9522 this.resolveStyle(s, url);
9155 } 9523 }
9156 } 9524 }
9157 }, 9525 },
9158 resolveStyle: function(style, url) { 9526 resolveStyle: function(style, url) {
9159 url = url || style.ownerDocument.baseURI; 9527 url = url || style.ownerDocument.baseURI;
9160 style.textContent = this.resolveCssText(style.textContent, url); 9528 style.textContent = this.resolveCssText(style.textContent, url);
9161 }, 9529 },
9162 resolveCssText: function(cssText, baseUrl) { 9530 resolveCssText: function(cssText, baseUrl, keepAbsolute) {
9163 cssText = replaceUrlsInCssText(cssText, baseUrl, CSS_URL_REGEXP); 9531 cssText = replaceUrlsInCssText(cssText, baseUrl, keepAbsolute, CSS_URL_REGEX P);
9164 return replaceUrlsInCssText(cssText, baseUrl, CSS_IMPORT_REGEXP); 9532 return replaceUrlsInCssText(cssText, baseUrl, keepAbsolute, CSS_IMPORT_REGEX P);
9165 }, 9533 },
9166 resolveAttributes: function(root, url) { 9534 resolveAttributes: function(root, url) {
9167 if (root.hasAttributes && root.hasAttributes()) { 9535 if (root.hasAttributes && root.hasAttributes()) {
9168 this.resolveElementAttributes(root, url); 9536 this.resolveElementAttributes(root, url);
9169 } 9537 }
9170 // search for attributes that host urls 9538 // search for attributes that host urls
9171 var nodes = root && root.querySelectorAll(URL_ATTRS_SELECTOR); 9539 var nodes = root && root.querySelectorAll(URL_ATTRS_SELECTOR);
9172 if (nodes) { 9540 if (nodes) {
9173 for (var i = 0, l = nodes.length, n; (i < l) && (n = nodes[i]); i++) { 9541 for (var i = 0, l = nodes.length, n; (i < l) && (n = nodes[i]); i++) {
9174 this.resolveElementAttributes(n, url); 9542 this.resolveElementAttributes(n, url);
9175 } 9543 }
9176 } 9544 }
9177 }, 9545 },
9178 resolveElementAttributes: function(node, url) { 9546 resolveElementAttributes: function(node, url) {
9179 url = url || node.ownerDocument.baseURI; 9547 url = url || node.ownerDocument.baseURI;
9180 URL_ATTRS.forEach(function(v) { 9548 URL_ATTRS.forEach(function(v) {
9181 var attr = node.attributes[v]; 9549 var attr = node.attributes[v];
9182 if (attr && attr.value && 9550 var value = attr && attr.value;
9183 (attr.value.search(URL_TEMPLATE_SEARCH) < 0)) { 9551 var replacement;
9184 var urlPath = resolveRelativeUrl(url, attr.value); 9552 if (value && value.search(URL_TEMPLATE_SEARCH) < 0) {
9185 attr.value = urlPath; 9553 if (v === 'style') {
9554 replacement = replaceUrlsInCssText(value, url, CSS_URL_REGEXP);
9555 } else {
9556 replacement = resolveRelativeUrl(url, value);
9557 }
9558 attr.value = replacement;
9186 } 9559 }
9187 }); 9560 });
9188 } 9561 }
9189 }; 9562 };
9190 9563
9191 var CSS_URL_REGEXP = /(url\()([^)]*)(\))/g; 9564 var CSS_URL_REGEXP = /(url\()([^)]*)(\))/g;
9192 var CSS_IMPORT_REGEXP = /(@import[\s]+(?!url\())([^;]*)(;)/g; 9565 var CSS_IMPORT_REGEXP = /(@import[\s]+(?!url\())([^;]*)(;)/g;
9193 var URL_ATTRS = ['href', 'src', 'action']; 9566 var URL_ATTRS = ['href', 'src', 'action', 'style'];
9194 var URL_ATTRS_SELECTOR = '[' + URL_ATTRS.join('],[') + ']'; 9567 var URL_ATTRS_SELECTOR = '[' + URL_ATTRS.join('],[') + ']';
9195 var URL_TEMPLATE_SEARCH = '{{.*}}'; 9568 var URL_TEMPLATE_SEARCH = '{{.*}}';
9196 9569
9197 function replaceUrlsInCssText(cssText, baseUrl, regexp) { 9570 function replaceUrlsInCssText(cssText, baseUrl, keepAbsolute, regexp) {
9198 return cssText.replace(regexp, function(m, pre, url, post) { 9571 return cssText.replace(regexp, function(m, pre, url, post) {
9199 var urlPath = url.replace(/["']/g, ''); 9572 var urlPath = url.replace(/["']/g, '');
9200 urlPath = resolveRelativeUrl(baseUrl, urlPath); 9573 urlPath = resolveRelativeUrl(baseUrl, urlPath, keepAbsolute);
9201 return pre + '\'' + urlPath + '\'' + post; 9574 return pre + '\'' + urlPath + '\'' + post;
9202 }); 9575 });
9203 } 9576 }
9204 9577
9205 function resolveRelativeUrl(baseUrl, url) { 9578 function resolveRelativeUrl(baseUrl, url, keepAbsolute) {
9579 // do not resolve '/' absolute urls
9580 if (url && url[0] === '/') {
9581 return url;
9582 }
9206 var u = new URL(url, baseUrl); 9583 var u = new URL(url, baseUrl);
9207 return makeDocumentRelPath(u.href); 9584 return keepAbsolute ? u.href : makeDocumentRelPath(u.href);
9208 } 9585 }
9209 9586
9210 function makeDocumentRelPath(url) { 9587 function makeDocumentRelPath(url) {
9211 var root = document.baseURI; 9588 var root = new URL(document.baseURI);
9212 var u = new URL(url, root); 9589 var u = new URL(url, root);
9213 if (u.host === root.host && u.port === root.port && 9590 if (u.host === root.host && u.port === root.port &&
9214 u.protocol === root.protocol) { 9591 u.protocol === root.protocol) {
9215 return makeRelPath(root.pathname, u.pathname); 9592 return makeRelPath(root, u);
9216 } else { 9593 } else {
9217 return url; 9594 return url;
9218 } 9595 }
9219 } 9596 }
9220 9597
9221 // make a relative path from source to target 9598 // make a relative path from source to target
9222 function makeRelPath(source, target) { 9599 function makeRelPath(sourceUrl, targetUrl) {
9600 var source = sourceUrl.pathname;
9601 var target = targetUrl.pathname;
9223 var s = source.split('/'); 9602 var s = source.split('/');
9224 var t = target.split('/'); 9603 var t = target.split('/');
9225 while (s.length && s[0] === t[0]){ 9604 while (s.length && s[0] === t[0]){
9226 s.shift(); 9605 s.shift();
9227 t.shift(); 9606 t.shift();
9228 } 9607 }
9229 for (var i = 0, l = s.length - 1; i < l; i++) { 9608 for (var i = 0, l = s.length - 1; i < l; i++) {
9230 t.unshift('..'); 9609 t.unshift('..');
9231 } 9610 }
9232 return t.join('/'); 9611 return t.join('/') + targetUrl.search + targetUrl.hash;
9233 } 9612 }
9234 9613
9235 // exports 9614 // exports
9236 scope.urlResolver = urlResolver; 9615 scope.urlResolver = urlResolver;
9237 9616
9238 })(Platform); 9617 })(Platform);
9239 9618
9240 /* 9619 /*
9241 * Copyright 2012 The Polymer Authors. All rights reserved. 9620 * Copyright 2012 The Polymer Authors. All rights reserved.
9242 * Use of this source code is goverened by a BSD-style 9621 * Use of this source code is goverened by a BSD-style
(...skipping 1217 matching lines...) Expand 10 before | Expand all | Expand 10 after
10460 callback(); 10839 callback();
10461 } 10840 }
10462 } 10841 }
10463 10842
10464 // call <callback> when we ensure all imports have loaded 10843 // call <callback> when we ensure all imports have loaded
10465 function watchImportsLoad(callback, doc) { 10844 function watchImportsLoad(callback, doc) {
10466 var imports = doc.querySelectorAll('link[rel=import]'); 10845 var imports = doc.querySelectorAll('link[rel=import]');
10467 var loaded = 0, l = imports.length; 10846 var loaded = 0, l = imports.length;
10468 function checkDone(d) { 10847 function checkDone(d) {
10469 if (loaded == l) { 10848 if (loaded == l) {
10470 // go async to ensure parser isn't stuck on a script tag 10849 callback && callback();
10471 requestAnimationFrame(callback);
10472 } 10850 }
10473 } 10851 }
10474 function loadedImport(e) { 10852 function loadedImport(e) {
10475 loaded++; 10853 loaded++;
10476 checkDone(); 10854 checkDone();
10477 } 10855 }
10478 if (l) { 10856 if (l) {
10479 for (var i=0, imp; (i<l) && (imp=imports[i]); i++) { 10857 for (var i=0, imp; (i<l) && (imp=imports[i]); i++) {
10480 if (isImportLoaded(imp)) { 10858 if (isImportLoaded(imp)) {
10481 loadedImport.call(imp); 10859 loadedImport.call(imp);
10482 } else { 10860 } else {
10483 imp.addEventListener('load', loadedImport); 10861 imp.addEventListener('load', loadedImport);
10484 imp.addEventListener('error', loadedImport); 10862 imp.addEventListener('error', loadedImport);
10485 } 10863 }
10486 } 10864 }
10487 } else { 10865 } else {
10488 checkDone(); 10866 checkDone();
10489 } 10867 }
10490 } 10868 }
10491 10869
10492 function isImportLoaded(link) { 10870 function isImportLoaded(link) {
10493 return useNative ? (link.import && (link.import.readyState !== 'loading')) : 10871 return useNative ? (link.import && (link.import.readyState !== 'loading')) || link.__loaded :
10494 link.__importParsed; 10872 link.__importParsed;
10495 } 10873 }
10496 10874
10875 // TODO(sorvell): install a mutation observer to see if HTMLImports have loaded
10876 // this is a workaround for https://www.w3.org/Bugs/Public/show_bug.cgi?id=25007
10877 // and should be removed when this bug is addressed.
10878 if (useNative) {
10879 new MutationObserver(function(mxns) {
10880 for (var i=0, l=mxns.length, m; (i < l) && (m=mxns[i]); i++) {
10881 if (m.addedNodes) {
10882 handleImports(m.addedNodes);
10883 }
10884 }
10885 }).observe(document.head, {childList: true});
10886
10887 function handleImports(nodes) {
10888 for (var i=0, l=nodes.length, n; (i<l) && (n=nodes[i]); i++) {
10889 if (isImport(n)) {
10890 handleImport(n);
10891 }
10892 }
10893 }
10894
10895 function isImport(element) {
10896 return element.localName === 'link' && element.rel === 'import';
10897 }
10898
10899 function handleImport(element) {
10900 var loaded = element.import;
10901 if (loaded) {
10902 markTargetLoaded({target: element});
10903 } else {
10904 element.addEventListener('load', markTargetLoaded);
10905 element.addEventListener('error', markTargetLoaded);
10906 }
10907 }
10908
10909 function markTargetLoaded(event) {
10910 event.target.__loaded = true;
10911 }
10912
10913 }
10914
10497 // exports 10915 // exports
10498 scope.hasNative = hasNative; 10916 scope.hasNative = hasNative;
10499 scope.useNative = useNative; 10917 scope.useNative = useNative;
10500 scope.importer = importer; 10918 scope.importer = importer;
10501 scope.whenImportsReady = whenImportsReady; 10919 scope.whenImportsReady = whenImportsReady;
10502 scope.IMPORT_LINK_TYPE = IMPORT_LINK_TYPE; 10920 scope.IMPORT_LINK_TYPE = IMPORT_LINK_TYPE;
10503 scope.isImportLoaded = isImportLoaded; 10921 scope.isImportLoaded = isImportLoaded;
10504 scope.importLoader = importLoader; 10922 scope.importLoader = importLoader;
10505 10923
10506 })(window.HTMLImports); 10924 })(window.HTMLImports);
(...skipping 661 matching lines...) Expand 10 before | Expand all | Expand 10 after
11168 11586
11169 function resolvePrototypeChain(definition) { 11587 function resolvePrototypeChain(definition) {
11170 // if we don't support __proto__ we need to locate the native level 11588 // if we don't support __proto__ we need to locate the native level
11171 // prototype for precise mixing in 11589 // prototype for precise mixing in
11172 if (!Object.__proto__) { 11590 if (!Object.__proto__) {
11173 // default prototype 11591 // default prototype
11174 var nativePrototype = HTMLElement.prototype; 11592 var nativePrototype = HTMLElement.prototype;
11175 // work out prototype when using type-extension 11593 // work out prototype when using type-extension
11176 if (definition.is) { 11594 if (definition.is) {
11177 var inst = document.createElement(definition.tag); 11595 var inst = document.createElement(definition.tag);
11178 nativePrototype = Object.getPrototypeOf(inst); 11596 var expectedPrototype = Object.getPrototypeOf(inst);
11597 // only set nativePrototype if it will actually appear in the definition 's chain
11598 if (expectedPrototype === definition.prototype) {
11599 nativePrototype = expectedPrototype;
11600 }
11179 } 11601 }
11180 // ensure __proto__ reference is installed at each point on the prototype 11602 // ensure __proto__ reference is installed at each point on the prototype
11181 // chain. 11603 // chain.
11182 // NOTE: On platforms without __proto__, a mixin strategy is used instead 11604 // NOTE: On platforms without __proto__, a mixin strategy is used instead
11183 // of prototype swizzling. In this case, this generated __proto__ provides 11605 // of prototype swizzling. In this case, this generated __proto__ provides
11184 // limited support for prototype traversal. 11606 // limited support for prototype traversal.
11185 var proto = definition.prototype, ancestor; 11607 var proto = definition.prototype, ancestor;
11186 while (proto && (proto !== nativePrototype)) { 11608 while (proto && (proto !== nativePrototype)) {
11187 var ancestor = Object.getPrototypeOf(proto); 11609 ancestor = Object.getPrototypeOf(proto);
11188 proto.__proto__ = ancestor; 11610 proto.__proto__ = ancestor;
11189 proto = ancestor; 11611 proto = ancestor;
11190 } 11612 }
11613 // cache this in case of mixin
11614 definition.native = nativePrototype;
11191 } 11615 }
11192 // cache this in case of mixin
11193 definition.native = nativePrototype;
11194 } 11616 }
11195 11617
11196 // SECTION 4 11618 // SECTION 4
11197 11619
11198 function instantiate(definition) { 11620 function instantiate(definition) {
11199 // 4.a.1. Create a new object that implements PROTOTYPE 11621 // 4.a.1. Create a new object that implements PROTOTYPE
11200 // 4.a.2. Let ELEMENT by this new object 11622 // 4.a.2. Let ELEMENT by this new object
11201 // 11623 //
11202 // the custom element instantiation algorithm must also ensure that the 11624 // the custom element instantiation algorithm must also ensure that the
11203 // output is a valid DOM element with the proper wrapper in place. 11625 // output is a valid DOM element with the proper wrapper in place.
(...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after
11574 // bootstrap. 11996 // bootstrap.
11575 } else { 11997 } else {
11576 var loadEvent = window.HTMLImports && !HTMLImports.ready ? 11998 var loadEvent = window.HTMLImports && !HTMLImports.ready ?
11577 'HTMLImportsLoaded' : 'DOMContentLoaded'; 11999 'HTMLImportsLoaded' : 'DOMContentLoaded';
11578 window.addEventListener(loadEvent, bootstrap); 12000 window.addEventListener(loadEvent, bootstrap);
11579 } 12001 }
11580 12002
11581 })(window.CustomElements); 12003 })(window.CustomElements);
11582 12004
11583 /* 12005 /*
11584 * Copyright 2013 The Polymer Authors. All rights reserved. 12006 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
11585 * Use of this source code is governed by a BSD-style 12007 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
11586 * license that can be found in the LICENSE file. 12008 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
12009 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
12010 * Code distributed by Google as part of the polymer project is also
12011 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
11587 */ 12012 */
12013
11588 (function() { 12014 (function() {
11589 12015
11590 if (window.ShadowDOMPolyfill) { 12016 if (window.ShadowDOMPolyfill) {
11591 12017
11592 // ensure wrapped inputs for these functions 12018 // ensure wrapped inputs for these functions
11593 var fns = ['upgradeAll', 'upgradeSubtree', 'observeDocument', 12019 var fns = ['upgradeAll', 'upgradeSubtree', 'observeDocument',
11594 'upgradeDocument']; 12020 'upgradeDocument'];
11595 12021
11596 // cache originals 12022 // cache originals
11597 var original = {}; 12023 var original = {};
11598 fns.forEach(function(fn) { 12024 fns.forEach(function(fn) {
11599 original[fn] = CustomElements[fn]; 12025 original[fn] = CustomElements[fn];
11600 }); 12026 });
11601 12027
11602 // override 12028 // override
11603 fns.forEach(function(fn) { 12029 fns.forEach(function(fn) {
11604 CustomElements[fn] = function(inNode) { 12030 CustomElements[fn] = function(inNode) {
11605 return original[fn](wrap(inNode)); 12031 return original[fn](wrap(inNode));
11606 }; 12032 };
11607 }); 12033 });
11608 12034
11609 } 12035 }
11610 12036
11611 })(); 12037 })();
11612 12038
11613 /* 12039 /*
11614 * Copyright 2014 The Polymer Authors. All rights reserved. 12040 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
11615 * Use of this source code is governed by a BSD-style 12041 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
11616 * license that can be found in the LICENSE file. 12042 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
12043 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
12044 * Code distributed by Google as part of the polymer project is also
12045 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
11617 */ 12046 */
12047
11618 (function(scope) { 12048 (function(scope) {
11619 var endOfMicrotask = scope.endOfMicrotask; 12049 var endOfMicrotask = scope.endOfMicrotask;
11620 12050
11621 // Generic url loader 12051 // Generic url loader
11622 function Loader(regex) { 12052 function Loader(regex) {
12053 this.cache = Object.create(null);
12054 this.map = Object.create(null);
12055 this.requests = 0;
11623 this.regex = regex; 12056 this.regex = regex;
11624 } 12057 }
11625 Loader.prototype = { 12058 Loader.prototype = {
12059
11626 // TODO(dfreedm): there may be a better factoring here 12060 // TODO(dfreedm): there may be a better factoring here
11627 // extract absolute urls from the text (full of relative urls) 12061 // extract absolute urls from the text (full of relative urls)
11628 extractUrls: function(text, base) { 12062 extractUrls: function(text, base) {
11629 var matches = []; 12063 var matches = [];
11630 var matched, u; 12064 var matched, u;
11631 while ((matched = this.regex.exec(text))) { 12065 while ((matched = this.regex.exec(text))) {
11632 u = new URL(matched[1], base); 12066 u = new URL(matched[1], base);
11633 matches.push({matched: matched[0], url: u.href}); 12067 matches.push({matched: matched[0], url: u.href});
11634 } 12068 }
11635 return matches; 12069 return matches;
11636 }, 12070 },
11637 // take a text blob, a root url, and a callback and load all the urls found within the text 12071 // take a text blob, a root url, and a callback and load all the urls found within the text
11638 // returns a map of absolute url to text 12072 // returns a map of absolute url to text
11639 process: function(text, root, callback) { 12073 process: function(text, root, callback) {
11640 var matches = this.extractUrls(text, root); 12074 var matches = this.extractUrls(text, root);
11641 this.fetch(matches, {}, callback); 12075
12076 // every call to process returns all the text this loader has ever receive d
12077 var done = callback.bind(null, this.map);
12078 this.fetch(matches, done);
11642 }, 12079 },
11643 // build a mapping of url -> text from matches 12080 // build a mapping of url -> text from matches
11644 fetch: function(matches, map, callback) { 12081 fetch: function(matches, callback) {
11645 var inflight = matches.length; 12082 var inflight = matches.length;
11646 12083
11647 // return early if there is no fetching to be done 12084 // return early if there is no fetching to be done
11648 if (!inflight) { 12085 if (!inflight) {
11649 return callback(map); 12086 return callback();
11650 } 12087 }
11651 12088
12089 // wait for all subrequests to return
11652 var done = function() { 12090 var done = function() {
11653 if (--inflight === 0) { 12091 if (--inflight === 0) {
11654 callback(map); 12092 callback();
11655 } 12093 }
11656 }; 12094 };
11657 12095
11658 // map url -> responseText 12096 // start fetching all subrequests
11659 var handleXhr = function(err, request) {
11660 var match = request.match;
11661 var key = match.url;
11662 // handle errors with an empty string
11663 if (err) {
11664 map[key] = '';
11665 return done();
11666 }
11667 var response = request.response || request.responseText;
11668 map[key] = response;
11669 this.fetch(this.extractUrls(response, key), map, done);
11670 };
11671
11672 var m, req, url; 12097 var m, req, url;
11673 for (var i = 0; i < inflight; i++) { 12098 for (var i = 0; i < inflight; i++) {
11674 m = matches[i]; 12099 m = matches[i];
11675 url = m.url; 12100 url = m.url;
12101 req = this.cache[url];
11676 // if this url has already been requested, skip requesting it again 12102 // if this url has already been requested, skip requesting it again
11677 if (map[url]) { 12103 if (!req) {
11678 // Async call to done to simplify the inflight logic 12104 req = this.xhr(url);
11679 endOfMicrotask(done); 12105 req.match = m;
11680 continue; 12106 this.cache[url] = req;
11681 } 12107 }
11682 req = this.xhr(url, handleXhr, this); 12108 // wait for the request to process its subrequests
11683 req.match = m; 12109 req.wait(done);
11684 // tag the map with an XHR request to deduplicate at the same level
11685 map[url] = req;
11686 } 12110 }
11687 }, 12111 },
11688 xhr: function(url, callback, scope) { 12112 handleXhr: function(request) {
12113 var match = request.match;
12114 var url = match.url;
12115
12116 // handle errors with an empty string
12117 var response = request.response || request.responseText || '';
12118 this.map[url] = response;
12119 this.fetch(this.extractUrls(response, url), request.resolve);
12120 },
12121 xhr: function(url) {
12122 this.requests++;
11689 var request = new XMLHttpRequest(); 12123 var request = new XMLHttpRequest();
11690 request.open('GET', url, true); 12124 request.open('GET', url, true);
11691 request.send(); 12125 request.send();
11692 request.onload = function() { 12126 request.onerror = request.onload = this.handleXhr.bind(this, request);
11693 callback.call(scope, null, request); 12127
12128 // queue of tasks to run after XHR returns
12129 request.pending = [];
12130 request.resolve = function() {
12131 var pending = request.pending;
12132 for(var i = 0; i < pending.length; i++) {
12133 pending[i]();
12134 }
12135 request.pending = null;
11694 }; 12136 };
11695 request.onerror = function() { 12137
11696 callback.call(scope, null, request); 12138 // if we have already resolved, pending is null, async call the callback
12139 request.wait = function(fn) {
12140 if (request.pending) {
12141 request.pending.push(fn);
12142 } else {
12143 endOfMicrotask(fn);
12144 }
11697 }; 12145 };
12146
11698 return request; 12147 return request;
11699 } 12148 }
11700 }; 12149 };
11701 12150
11702 scope.Loader = Loader; 12151 scope.Loader = Loader;
11703 })(window.Platform); 12152 })(window.Platform);
11704 12153
11705 /* 12154 /*
11706 * Copyright 2014 The Polymer Authors. All rights reserved. 12155 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
11707 * Use of this source code is governed by a BSD-style 12156 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
11708 * license that can be found in the LICENSE file. 12157 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
12158 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
12159 * Code distributed by Google as part of the polymer project is also
12160 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
11709 */ 12161 */
12162
11710 (function(scope) { 12163 (function(scope) {
11711 12164
11712 var urlResolver = scope.urlResolver; 12165 var urlResolver = scope.urlResolver;
11713 var Loader = scope.Loader; 12166 var Loader = scope.Loader;
11714 12167
11715 function StyleResolver() { 12168 function StyleResolver() {
11716 this.loader = new Loader(this.regex); 12169 this.loader = new Loader(this.regex);
11717 } 12170 }
11718 StyleResolver.prototype = { 12171 StyleResolver.prototype = {
11719 regex: /@import\s+(?:url)?["'\(]*([^'"\)]*)['"\)]*;/g, 12172 regex: /@import\s+(?:url)?["'\(]*([^'"\)]*)['"\)]*;/g,
11720 // Recursively replace @imports with the text at that url 12173 // Recursively replace @imports with the text at that url
11721 resolve: function(text, url, callback) { 12174 resolve: function(text, url, callback) {
11722 var done = function(map) { 12175 var done = function(map) {
11723 callback(this.flatten(text, url, map)); 12176 callback(this.flatten(text, url, map));
11724 }.bind(this); 12177 }.bind(this);
11725 this.loader.process(text, url, done); 12178 this.loader.process(text, url, done);
11726 }, 12179 },
11727 // resolve the textContent of a style node 12180 // resolve the textContent of a style node
11728 resolveNode: function(style, callback) { 12181 resolveNode: function(style, url, callback) {
11729 var text = style.textContent; 12182 var text = style.textContent;
11730 var url = style.ownerDocument.baseURI;
11731 var done = function(text) { 12183 var done = function(text) {
11732 style.textContent = text; 12184 style.textContent = text;
11733 callback(style); 12185 callback(style);
11734 }; 12186 };
11735 this.resolve(text, url, done); 12187 this.resolve(text, url, done);
11736 }, 12188 },
11737 // flatten all the @imports to text 12189 // flatten all the @imports to text
11738 flatten: function(text, base, map) { 12190 flatten: function(text, base, map) {
11739 var matches = this.loader.extractUrls(text, base); 12191 var matches = this.loader.extractUrls(text, base);
11740 var match, url, intermediate; 12192 var match, url, intermediate;
11741 for (var i = 0; i < matches.length; i++) { 12193 for (var i = 0; i < matches.length; i++) {
11742 match = matches[i]; 12194 match = matches[i];
11743 url = match.url; 12195 url = match.url;
11744 // resolve any css text to be relative to the importer 12196 // resolve any css text to be relative to the importer, keep absolute url
11745 intermediate = urlResolver.resolveCssText(map[url], url); 12197 intermediate = urlResolver.resolveCssText(map[url], url, true);
11746 // flatten intermediate @imports 12198 // flatten intermediate @imports
11747 intermediate = this.flatten(intermediate, url, map); 12199 intermediate = this.flatten(intermediate, base, map);
11748 text = text.replace(match.matched, intermediate); 12200 text = text.replace(match.matched, intermediate);
11749 } 12201 }
11750 return text; 12202 return text;
11751 }, 12203 },
11752 loadStyles: function(styles, callback) { 12204 loadStyles: function(styles, base, callback) {
11753 var loaded=0, l = styles.length; 12205 var loaded=0, l = styles.length;
11754 // called in the context of the style 12206 // called in the context of the style
11755 function loadedStyle(style) { 12207 function loadedStyle(style) {
11756 loaded++; 12208 loaded++;
11757 if (loaded === l && callback) { 12209 if (loaded === l && callback) {
11758 callback(); 12210 callback();
11759 } 12211 }
11760 } 12212 }
11761 for (var i=0, s; (i<l) && (s=styles[i]); i++) { 12213 for (var i=0, s; (i<l) && (s=styles[i]); i++) {
11762 this.resolveNode(s, loadedStyle); 12214 this.resolveNode(s, base, loadedStyle);
11763 } 12215 }
11764 } 12216 }
11765 }; 12217 };
11766 12218
11767 var styleResolver = new StyleResolver(); 12219 var styleResolver = new StyleResolver();
11768 12220
11769 // exports 12221 // exports
11770 scope.styleResolver = styleResolver; 12222 scope.styleResolver = styleResolver;
11771 12223
11772 })(window.Platform); 12224 })(window.Platform);
11773 12225
11774 /*
11775 * Copyright 2013 The Polymer Authors. All rights reserved.
11776 * Use of this source code is governed by a BSD-style
11777 * license that can be found in the LICENSE file.
11778 */
11779
11780 (function(scope) {
11781 scope = scope || {};
11782 scope.external = scope.external || {};
11783 var target = {
11784 shadow: function(inEl) {
11785 if (inEl) {
11786 return inEl.shadowRoot || inEl.webkitShadowRoot;
11787 }
11788 },
11789 canTarget: function(shadow) {
11790 return shadow && Boolean(shadow.elementFromPoint);
11791 },
11792 targetingShadow: function(inEl) {
11793 var s = this.shadow(inEl);
11794 if (this.canTarget(s)) {
11795 return s;
11796 }
11797 },
11798 olderShadow: function(shadow) {
11799 var os = shadow.olderShadowRoot;
11800 if (!os) {
11801 var se = shadow.querySelector('shadow');
11802 if (se) {
11803 os = se.olderShadowRoot;
11804 }
11805 }
11806 return os;
11807 },
11808 allShadows: function(element) {
11809 var shadows = [], s = this.shadow(element);
11810 while(s) {
11811 shadows.push(s);
11812 s = this.olderShadow(s);
11813 }
11814 return shadows;
11815 },
11816 searchRoot: function(inRoot, x, y) {
11817 if (inRoot) {
11818 var t = inRoot.elementFromPoint(x, y);
11819 var st, sr, os;
11820 // is element a shadow host?
11821 sr = this.targetingShadow(t);
11822 while (sr) {
11823 // find the the element inside the shadow root
11824 st = sr.elementFromPoint(x, y);
11825 if (!st) {
11826 // check for older shadows
11827 sr = this.olderShadow(sr);
11828 } else {
11829 // shadowed element may contain a shadow root
11830 var ssr = this.targetingShadow(st);
11831 return this.searchRoot(ssr, x, y) || st;
11832 }
11833 }
11834 // light dom element is the target
11835 return t;
11836 }
11837 },
11838 owner: function(element) {
11839 var s = element;
11840 // walk up until you hit the shadow root or document
11841 while (s.parentNode) {
11842 s = s.parentNode;
11843 }
11844 // the owner element is expected to be a Document or ShadowRoot
11845 if (s.nodeType != Node.DOCUMENT_NODE && s.nodeType != Node.DOCUMENT_FRAGME NT_NODE) {
11846 s = document;
11847 }
11848 return s;
11849 },
11850 findTarget: function(inEvent) {
11851 var x = inEvent.clientX, y = inEvent.clientY;
11852 // if the listener is in the shadow root, it is much faster to start there
11853 var s = this.owner(inEvent.target);
11854 // if x, y is not in this root, fall back to document search
11855 if (!s.elementFromPoint(x, y)) {
11856 s = document;
11857 }
11858 return this.searchRoot(s, x, y);
11859 }
11860 };
11861 scope.targetFinding = target;
11862 scope.findTarget = target.findTarget.bind(target);
11863
11864 window.PointerEventsPolyfill = scope;
11865 })(window.PointerEventsPolyfill);
11866
11867 /*
11868 * Copyright 2013 The Polymer Authors. All rights reserved.
11869 * Use of this source code is governed by a BSD-style
11870 * license that can be found in the LICENSE file.
11871 */
11872 (function() {
11873 function shadowSelector(v) {
11874 return 'body /shadow-deep/ ' + selector(v);
11875 }
11876 function selector(v) {
11877 return '[touch-action="' + v + '"]';
11878 }
11879 function rule(v) {
11880 return '{ -ms-touch-action: ' + v + '; touch-action: ' + v + '; touch-action -delay: none; }';
11881 }
11882 var attrib2css = [
11883 'none',
11884 'auto',
11885 'pan-x',
11886 'pan-y',
11887 {
11888 rule: 'pan-x pan-y',
11889 selectors: [
11890 'pan-x pan-y',
11891 'pan-y pan-x'
11892 ]
11893 }
11894 ];
11895 var styles = '';
11896 // only install stylesheet if the browser has touch action support
11897 var head = document.head;
11898 var hasNativePE = window.PointerEvent || window.MSPointerEvent;
11899 // only add shadow selectors if shadowdom is supported
11900 var hasShadowRoot = !window.ShadowDOMPolyfill && document.head.createShadowRoo t;
11901
11902 if (hasNativePE) {
11903 attrib2css.forEach(function(r) {
11904 if (String(r) === r) {
11905 styles += selector(r) + rule(r) + '\n';
11906 if (hasShadowRoot) {
11907 styles += shadowSelector(r) + rule(r) + '\n';
11908 }
11909 } else {
11910 styles += r.selectors.map(selector) + rule(r.rule) + '\n';
11911 if (hasShadowRoot) {
11912 styles += r.selectors.map(shadowSelector) + rule(r.rule) + '\n';
11913 }
11914 }
11915 });
11916
11917 var el = document.createElement('style');
11918 el.textContent = styles;
11919 document.head.appendChild(el);
11920 }
11921 })();
11922
11923 /*
11924 * Copyright 2013 The Polymer Authors. All rights reserved.
11925 * Use of this source code is governed by a BSD-style
11926 * license that can be found in the LICENSE file.
11927 */
11928
11929 /**
11930 * This is the constructor for new PointerEvents.
11931 *
11932 * New Pointer Events must be given a type, and an optional dictionary of
11933 * initialization properties.
11934 *
11935 * Due to certain platform requirements, events returned from the constructor
11936 * identify as MouseEvents.
11937 *
11938 * @constructor
11939 * @param {String} inType The type of the event to create.
11940 * @param {Object} [inDict] An optional dictionary of initial event properties.
11941 * @return {Event} A new PointerEvent of type `inType` and initialized with prop erties from `inDict`.
11942 */
11943 (function(scope) {
11944
11945 var MOUSE_PROPS = [
11946 'bubbles',
11947 'cancelable',
11948 'view',
11949 'detail',
11950 'screenX',
11951 'screenY',
11952 'clientX',
11953 'clientY',
11954 'ctrlKey',
11955 'altKey',
11956 'shiftKey',
11957 'metaKey',
11958 'button',
11959 'relatedTarget',
11960 'pageX',
11961 'pageY'
11962 ];
11963
11964 var MOUSE_DEFAULTS = [
11965 false,
11966 false,
11967 null,
11968 null,
11969 0,
11970 0,
11971 0,
11972 0,
11973 false,
11974 false,
11975 false,
11976 false,
11977 0,
11978 null,
11979 0,
11980 0
11981 ];
11982
11983 function PointerEvent(inType, inDict) {
11984 inDict = inDict || Object.create(null);
11985
11986 var e = document.createEvent('Event');
11987 e.initEvent(inType, inDict.bubbles || false, inDict.cancelable || false);
11988
11989 // define inherited MouseEvent properties
11990 for(var i = 0, p; i < MOUSE_PROPS.length; i++) {
11991 p = MOUSE_PROPS[i];
11992 e[p] = inDict[p] || MOUSE_DEFAULTS[i];
11993 }
11994 e.buttons = inDict.buttons || 0;
11995
11996 // Spec requires that pointers without pressure specified use 0.5 for down
11997 // state and 0 for up state.
11998 var pressure = 0;
11999 if (inDict.pressure) {
12000 pressure = inDict.pressure;
12001 } else {
12002 pressure = e.buttons ? 0.5 : 0;
12003 }
12004
12005 // add x/y properties aliased to clientX/Y
12006 e.x = e.clientX;
12007 e.y = e.clientY;
12008
12009 // define the properties of the PointerEvent interface
12010 e.pointerId = inDict.pointerId || 0;
12011 e.width = inDict.width || 0;
12012 e.height = inDict.height || 0;
12013 e.pressure = pressure;
12014 e.tiltX = inDict.tiltX || 0;
12015 e.tiltY = inDict.tiltY || 0;
12016 e.pointerType = inDict.pointerType || '';
12017 e.hwTimestamp = inDict.hwTimestamp || 0;
12018 e.isPrimary = inDict.isPrimary || false;
12019 return e;
12020 }
12021
12022 // attach to window
12023 if (!scope.PointerEvent) {
12024 scope.PointerEvent = PointerEvent;
12025 }
12026 })(window);
12027
12028 /*
12029 * Copyright 2013 The Polymer Authors. All rights reserved.
12030 * Use of this source code is governed by a BSD-style
12031 * license that can be found in the LICENSE file.
12032 */
12033
12034 /**
12035 * This module implements an map of pointer states
12036 */
12037 (function(scope) {
12038 var USE_MAP = window.Map && window.Map.prototype.forEach;
12039 var POINTERS_FN = function(){ return this.size; };
12040 function PointerMap() {
12041 if (USE_MAP) {
12042 var m = new Map();
12043 m.pointers = POINTERS_FN;
12044 return m;
12045 } else {
12046 this.keys = [];
12047 this.values = [];
12048 }
12049 }
12050
12051 PointerMap.prototype = {
12052 set: function(inId, inEvent) {
12053 var i = this.keys.indexOf(inId);
12054 if (i > -1) {
12055 this.values[i] = inEvent;
12056 } else {
12057 this.keys.push(inId);
12058 this.values.push(inEvent);
12059 }
12060 },
12061 has: function(inId) {
12062 return this.keys.indexOf(inId) > -1;
12063 },
12064 'delete': function(inId) {
12065 var i = this.keys.indexOf(inId);
12066 if (i > -1) {
12067 this.keys.splice(i, 1);
12068 this.values.splice(i, 1);
12069 }
12070 },
12071 get: function(inId) {
12072 var i = this.keys.indexOf(inId);
12073 return this.values[i];
12074 },
12075 clear: function() {
12076 this.keys.length = 0;
12077 this.values.length = 0;
12078 },
12079 // return value, key, map
12080 forEach: function(callback, thisArg) {
12081 this.values.forEach(function(v, i) {
12082 callback.call(thisArg, v, this.keys[i], this);
12083 }, this);
12084 },
12085 pointers: function() {
12086 return this.keys.length;
12087 }
12088 };
12089
12090 scope.PointerMap = PointerMap;
12091 })(window.PointerEventsPolyfill);
12092
12093 /*
12094 * Copyright 2013 The Polymer Authors. All rights reserved.
12095 * Use of this source code is governed by a BSD-style
12096 * license that can be found in the LICENSE file.
12097 */
12098
12099 (function(scope) {
12100 var CLONE_PROPS = [
12101 // MouseEvent
12102 'bubbles',
12103 'cancelable',
12104 'view',
12105 'detail',
12106 'screenX',
12107 'screenY',
12108 'clientX',
12109 'clientY',
12110 'ctrlKey',
12111 'altKey',
12112 'shiftKey',
12113 'metaKey',
12114 'button',
12115 'relatedTarget',
12116 // DOM Level 3
12117 'buttons',
12118 // PointerEvent
12119 'pointerId',
12120 'width',
12121 'height',
12122 'pressure',
12123 'tiltX',
12124 'tiltY',
12125 'pointerType',
12126 'hwTimestamp',
12127 'isPrimary',
12128 // event instance
12129 'type',
12130 'target',
12131 'currentTarget',
12132 'which',
12133 'pageX',
12134 'pageY'
12135 ];
12136
12137 var CLONE_DEFAULTS = [
12138 // MouseEvent
12139 false,
12140 false,
12141 null,
12142 null,
12143 0,
12144 0,
12145 0,
12146 0,
12147 false,
12148 false,
12149 false,
12150 false,
12151 0,
12152 null,
12153 // DOM Level 3
12154 0,
12155 // PointerEvent
12156 0,
12157 0,
12158 0,
12159 0,
12160 0,
12161 0,
12162 '',
12163 0,
12164 false,
12165 // event instance
12166 '',
12167 null,
12168 null,
12169 0,
12170 0,
12171 0
12172 ];
12173
12174 var HAS_SVG_INSTANCE = (typeof SVGElementInstance !== 'undefined');
12175
12176 /**
12177 * This module is for normalizing events. Mouse and Touch events will be
12178 * collected here, and fire PointerEvents that have the same semantics, no
12179 * matter the source.
12180 * Events fired:
12181 * - pointerdown: a pointing is added
12182 * - pointerup: a pointer is removed
12183 * - pointermove: a pointer is moved
12184 * - pointerover: a pointer crosses into an element
12185 * - pointerout: a pointer leaves an element
12186 * - pointercancel: a pointer will no longer generate events
12187 */
12188 var dispatcher = {
12189 pointermap: new scope.PointerMap(),
12190 eventMap: Object.create(null),
12191 captureInfo: Object.create(null),
12192 // Scope objects for native events.
12193 // This exists for ease of testing.
12194 eventSources: Object.create(null),
12195 eventSourceList: [],
12196 /**
12197 * Add a new event source that will generate pointer events.
12198 *
12199 * `inSource` must contain an array of event names named `events`, and
12200 * functions with the names specified in the `events` array.
12201 * @param {string} name A name for the event source
12202 * @param {Object} source A new source of platform events.
12203 */
12204 registerSource: function(name, source) {
12205 var s = source;
12206 var newEvents = s.events;
12207 if (newEvents) {
12208 newEvents.forEach(function(e) {
12209 if (s[e]) {
12210 this.eventMap[e] = s[e].bind(s);
12211 }
12212 }, this);
12213 this.eventSources[name] = s;
12214 this.eventSourceList.push(s);
12215 }
12216 },
12217 register: function(element) {
12218 var l = this.eventSourceList.length;
12219 for (var i = 0, es; (i < l) && (es = this.eventSourceList[i]); i++) {
12220 // call eventsource register
12221 es.register.call(es, element);
12222 }
12223 },
12224 unregister: function(element) {
12225 var l = this.eventSourceList.length;
12226 for (var i = 0, es; (i < l) && (es = this.eventSourceList[i]); i++) {
12227 // call eventsource register
12228 es.unregister.call(es, element);
12229 }
12230 },
12231 contains: scope.external.contains || function(container, contained) {
12232 return container.contains(contained);
12233 },
12234 // EVENTS
12235 down: function(inEvent) {
12236 inEvent.bubbles = true;
12237 this.fireEvent('pointerdown', inEvent);
12238 },
12239 move: function(inEvent) {
12240 inEvent.bubbles = true;
12241 this.fireEvent('pointermove', inEvent);
12242 },
12243 up: function(inEvent) {
12244 inEvent.bubbles = true;
12245 this.fireEvent('pointerup', inEvent);
12246 },
12247 enter: function(inEvent) {
12248 inEvent.bubbles = false;
12249 this.fireEvent('pointerenter', inEvent);
12250 },
12251 leave: function(inEvent) {
12252 inEvent.bubbles = false;
12253 this.fireEvent('pointerleave', inEvent);
12254 },
12255 over: function(inEvent) {
12256 inEvent.bubbles = true;
12257 this.fireEvent('pointerover', inEvent);
12258 },
12259 out: function(inEvent) {
12260 inEvent.bubbles = true;
12261 this.fireEvent('pointerout', inEvent);
12262 },
12263 cancel: function(inEvent) {
12264 inEvent.bubbles = true;
12265 this.fireEvent('pointercancel', inEvent);
12266 },
12267 leaveOut: function(event) {
12268 this.out(event);
12269 if (!this.contains(event.target, event.relatedTarget)) {
12270 this.leave(event);
12271 }
12272 },
12273 enterOver: function(event) {
12274 this.over(event);
12275 if (!this.contains(event.target, event.relatedTarget)) {
12276 this.enter(event);
12277 }
12278 },
12279 // LISTENER LOGIC
12280 eventHandler: function(inEvent) {
12281 // This is used to prevent multiple dispatch of pointerevents from
12282 // platform events. This can happen when two elements in different scopes
12283 // are set up to create pointer events, which is relevant to Shadow DOM.
12284 if (inEvent._handledByPE) {
12285 return;
12286 }
12287 var type = inEvent.type;
12288 var fn = this.eventMap && this.eventMap[type];
12289 if (fn) {
12290 fn(inEvent);
12291 }
12292 inEvent._handledByPE = true;
12293 },
12294 // set up event listeners
12295 listen: function(target, events) {
12296 events.forEach(function(e) {
12297 this.addEvent(target, e);
12298 }, this);
12299 },
12300 // remove event listeners
12301 unlisten: function(target, events) {
12302 events.forEach(function(e) {
12303 this.removeEvent(target, e);
12304 }, this);
12305 },
12306 addEvent: scope.external.addEvent || function(target, eventName) {
12307 target.addEventListener(eventName, this.boundHandler);
12308 },
12309 removeEvent: scope.external.removeEvent || function(target, eventName) {
12310 target.removeEventListener(eventName, this.boundHandler);
12311 },
12312 // EVENT CREATION AND TRACKING
12313 /**
12314 * Creates a new Event of type `inType`, based on the information in
12315 * `inEvent`.
12316 *
12317 * @param {string} inType A string representing the type of event to create
12318 * @param {Event} inEvent A platform event with a target
12319 * @return {Event} A PointerEvent of type `inType`
12320 */
12321 makeEvent: function(inType, inEvent) {
12322 // relatedTarget must be null if pointer is captured
12323 if (this.captureInfo[inEvent.pointerId]) {
12324 inEvent.relatedTarget = null;
12325 }
12326 var e = new PointerEvent(inType, inEvent);
12327 if (inEvent.preventDefault) {
12328 e.preventDefault = inEvent.preventDefault;
12329 }
12330 e._target = e._target || inEvent.target;
12331 return e;
12332 },
12333 // make and dispatch an event in one call
12334 fireEvent: function(inType, inEvent) {
12335 var e = this.makeEvent(inType, inEvent);
12336 return this.dispatchEvent(e);
12337 },
12338 /**
12339 * Returns a snapshot of inEvent, with writable properties.
12340 *
12341 * @param {Event} inEvent An event that contains properties to copy.
12342 * @return {Object} An object containing shallow copies of `inEvent`'s
12343 * properties.
12344 */
12345 cloneEvent: function(inEvent) {
12346 var eventCopy = Object.create(null), p;
12347 for (var i = 0; i < CLONE_PROPS.length; i++) {
12348 p = CLONE_PROPS[i];
12349 eventCopy[p] = inEvent[p] || CLONE_DEFAULTS[i];
12350 // Work around SVGInstanceElement shadow tree
12351 // Return the <use> element that is represented by the instance for Safa ri, Chrome, IE.
12352 // This is the behavior implemented by Firefox.
12353 if (HAS_SVG_INSTANCE && (p === 'target' || p === 'relatedTarget')) {
12354 if (eventCopy[p] instanceof SVGElementInstance) {
12355 eventCopy[p] = eventCopy[p].correspondingUseElement;
12356 }
12357 }
12358 }
12359 // keep the semantics of preventDefault
12360 if (inEvent.preventDefault) {
12361 eventCopy.preventDefault = function() {
12362 inEvent.preventDefault();
12363 };
12364 }
12365 return eventCopy;
12366 },
12367 getTarget: function(inEvent) {
12368 // if pointer capture is set, route all events for the specified pointerId
12369 // to the capture target
12370 return this.captureInfo[inEvent.pointerId] || inEvent._target;
12371 },
12372 setCapture: function(inPointerId, inTarget) {
12373 if (this.captureInfo[inPointerId]) {
12374 this.releaseCapture(inPointerId);
12375 }
12376 this.captureInfo[inPointerId] = inTarget;
12377 var e = document.createEvent('Event');
12378 e.initEvent('gotpointercapture', true, false);
12379 e.pointerId = inPointerId;
12380 this.implicitRelease = this.releaseCapture.bind(this, inPointerId);
12381 document.addEventListener('pointerup', this.implicitRelease);
12382 document.addEventListener('pointercancel', this.implicitRelease);
12383 e._target = inTarget;
12384 this.asyncDispatchEvent(e);
12385 },
12386 releaseCapture: function(inPointerId) {
12387 var t = this.captureInfo[inPointerId];
12388 if (t) {
12389 var e = document.createEvent('Event');
12390 e.initEvent('lostpointercapture', true, false);
12391 e.pointerId = inPointerId;
12392 this.captureInfo[inPointerId] = undefined;
12393 document.removeEventListener('pointerup', this.implicitRelease);
12394 document.removeEventListener('pointercancel', this.implicitRelease);
12395 e._target = t;
12396 this.asyncDispatchEvent(e);
12397 }
12398 },
12399 /**
12400 * Dispatches the event to its target.
12401 *
12402 * @param {Event} inEvent The event to be dispatched.
12403 * @return {Boolean} True if an event handler returns true, false otherwise.
12404 */
12405 dispatchEvent: scope.external.dispatchEvent || function(inEvent) {
12406 var t = this.getTarget(inEvent);
12407 if (t) {
12408 return t.dispatchEvent(inEvent);
12409 }
12410 },
12411 asyncDispatchEvent: function(inEvent) {
12412 requestAnimationFrame(this.dispatchEvent.bind(this, inEvent));
12413 }
12414 };
12415 dispatcher.boundHandler = dispatcher.eventHandler.bind(dispatcher);
12416 scope.dispatcher = dispatcher;
12417 scope.register = dispatcher.register.bind(dispatcher);
12418 scope.unregister = dispatcher.unregister.bind(dispatcher);
12419 })(window.PointerEventsPolyfill);
12420
12421 /*
12422 * Copyright 2013 The Polymer Authors. All rights reserved.
12423 * Use of this source code is governed by a BSD-style
12424 * license that can be found in the LICENSE file.
12425 */
12426
12427 /**
12428 * This module uses Mutation Observers to dynamically adjust which nodes will
12429 * generate Pointer Events.
12430 *
12431 * All nodes that wish to generate Pointer Events must have the attribute
12432 * `touch-action` set to `none`.
12433 */
12434 (function(scope) {
12435 var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
12436 var map = Array.prototype.map.call.bind(Array.prototype.map);
12437 var toArray = Array.prototype.slice.call.bind(Array.prototype.slice);
12438 var filter = Array.prototype.filter.call.bind(Array.prototype.filter);
12439 var MO = window.MutationObserver || window.WebKitMutationObserver;
12440 var SELECTOR = '[touch-action]';
12441 var OBSERVER_INIT = {
12442 subtree: true,
12443 childList: true,
12444 attributes: true,
12445 attributeOldValue: true,
12446 attributeFilter: ['touch-action']
12447 };
12448
12449 function Installer(add, remove, changed, binder) {
12450 this.addCallback = add.bind(binder);
12451 this.removeCallback = remove.bind(binder);
12452 this.changedCallback = changed.bind(binder);
12453 if (MO) {
12454 this.observer = new MO(this.mutationWatcher.bind(this));
12455 }
12456 }
12457
12458 Installer.prototype = {
12459 watchSubtree: function(target) {
12460 // Only watch scopes that can target find, as these are top-level.
12461 // Otherwise we can see duplicate additions and removals that add noise.
12462 //
12463 // TODO(dfreedman): For some instances with ShadowDOMPolyfill, we can see
12464 // a removal without an insertion when a node is redistributed among
12465 // shadows. Since it all ends up correct in the document, watching only
12466 // the document will yield the correct mutations to watch.
12467 if (scope.targetFinding.canTarget(target)) {
12468 this.observer.observe(target, OBSERVER_INIT);
12469 }
12470 },
12471 enableOnSubtree: function(target) {
12472 this.watchSubtree(target);
12473 if (target === document && document.readyState !== 'complete') {
12474 this.installOnLoad();
12475 } else {
12476 this.installNewSubtree(target);
12477 }
12478 },
12479 installNewSubtree: function(target) {
12480 forEach(this.findElements(target), this.addElement, this);
12481 },
12482 findElements: function(target) {
12483 if (target.querySelectorAll) {
12484 return target.querySelectorAll(SELECTOR);
12485 }
12486 return [];
12487 },
12488 removeElement: function(el) {
12489 this.removeCallback(el);
12490 },
12491 addElement: function(el) {
12492 this.addCallback(el);
12493 },
12494 elementChanged: function(el, oldValue) {
12495 this.changedCallback(el, oldValue);
12496 },
12497 concatLists: function(accum, list) {
12498 return accum.concat(toArray(list));
12499 },
12500 // register all touch-action = none nodes on document load
12501 installOnLoad: function() {
12502 document.addEventListener('readystatechange', function() {
12503 if (document.readyState === 'complete') {
12504 this.installNewSubtree(document);
12505 }
12506 }.bind(this));
12507 },
12508 isElement: function(n) {
12509 return n.nodeType === Node.ELEMENT_NODE;
12510 },
12511 flattenMutationTree: function(inNodes) {
12512 // find children with touch-action
12513 var tree = map(inNodes, this.findElements, this);
12514 // make sure the added nodes are accounted for
12515 tree.push(filter(inNodes, this.isElement));
12516 // flatten the list
12517 return tree.reduce(this.concatLists, []);
12518 },
12519 mutationWatcher: function(mutations) {
12520 mutations.forEach(this.mutationHandler, this);
12521 },
12522 mutationHandler: function(m) {
12523 if (m.type === 'childList') {
12524 var added = this.flattenMutationTree(m.addedNodes);
12525 added.forEach(this.addElement, this);
12526 var removed = this.flattenMutationTree(m.removedNodes);
12527 removed.forEach(this.removeElement, this);
12528 } else if (m.type === 'attributes') {
12529 this.elementChanged(m.target, m.oldValue);
12530 }
12531 }
12532 };
12533
12534 if (!MO) {
12535 Installer.prototype.watchSubtree = function(){
12536 console.warn('PointerEventsPolyfill: MutationObservers not found, touch-ac tion will not be dynamically detected');
12537 };
12538 }
12539
12540 scope.Installer = Installer;
12541 })(window.PointerEventsPolyfill);
12542
12543 /*
12544 * Copyright 2013 The Polymer Authors. All rights reserved.
12545 * Use of this source code is governed by a BSD-style
12546 * license that can be found in the LICENSE file.
12547 */
12548
12549 (function (scope) {
12550 var dispatcher = scope.dispatcher;
12551 var pointermap = dispatcher.pointermap;
12552 // radius around touchend that swallows mouse events
12553 var DEDUP_DIST = 25;
12554
12555 var WHICH_TO_BUTTONS = [0, 1, 4, 2];
12556
12557 var HAS_BUTTONS = false;
12558 try {
12559 HAS_BUTTONS = new MouseEvent('test', {buttons: 1}).buttons === 1;
12560 } catch (e) {}
12561
12562 // handler block for native mouse events
12563 var mouseEvents = {
12564 POINTER_ID: 1,
12565 POINTER_TYPE: 'mouse',
12566 events: [
12567 'mousedown',
12568 'mousemove',
12569 'mouseup',
12570 'mouseover',
12571 'mouseout'
12572 ],
12573 register: function(target) {
12574 dispatcher.listen(target, this.events);
12575 },
12576 unregister: function(target) {
12577 dispatcher.unlisten(target, this.events);
12578 },
12579 lastTouches: [],
12580 // collide with the global mouse listener
12581 isEventSimulatedFromTouch: function(inEvent) {
12582 var lts = this.lastTouches;
12583 var x = inEvent.clientX, y = inEvent.clientY;
12584 for (var i = 0, l = lts.length, t; i < l && (t = lts[i]); i++) {
12585 // simulated mouse events will be swallowed near a primary touchend
12586 var dx = Math.abs(x - t.x), dy = Math.abs(y - t.y);
12587 if (dx <= DEDUP_DIST && dy <= DEDUP_DIST) {
12588 return true;
12589 }
12590 }
12591 },
12592 prepareEvent: function(inEvent) {
12593 var e = dispatcher.cloneEvent(inEvent);
12594 // forward mouse preventDefault
12595 var pd = e.preventDefault;
12596 e.preventDefault = function() {
12597 inEvent.preventDefault();
12598 pd();
12599 };
12600 e.pointerId = this.POINTER_ID;
12601 e.isPrimary = true;
12602 e.pointerType = this.POINTER_TYPE;
12603 if (!HAS_BUTTONS) {
12604 e.buttons = WHICH_TO_BUTTONS[e.which] || 0;
12605 }
12606 return e;
12607 },
12608 mousedown: function(inEvent) {
12609 if (!this.isEventSimulatedFromTouch(inEvent)) {
12610 var p = pointermap.has(this.POINTER_ID);
12611 // TODO(dfreedman) workaround for some elements not sending mouseup
12612 // http://crbug/149091
12613 if (p) {
12614 this.cancel(inEvent);
12615 }
12616 var e = this.prepareEvent(inEvent);
12617 pointermap.set(this.POINTER_ID, inEvent);
12618 dispatcher.down(e);
12619 }
12620 },
12621 mousemove: function(inEvent) {
12622 if (!this.isEventSimulatedFromTouch(inEvent)) {
12623 var e = this.prepareEvent(inEvent);
12624 dispatcher.move(e);
12625 }
12626 },
12627 mouseup: function(inEvent) {
12628 if (!this.isEventSimulatedFromTouch(inEvent)) {
12629 var p = pointermap.get(this.POINTER_ID);
12630 if (p && p.button === inEvent.button) {
12631 var e = this.prepareEvent(inEvent);
12632 dispatcher.up(e);
12633 this.cleanupMouse();
12634 }
12635 }
12636 },
12637 mouseover: function(inEvent) {
12638 if (!this.isEventSimulatedFromTouch(inEvent)) {
12639 var e = this.prepareEvent(inEvent);
12640 dispatcher.enterOver(e);
12641 }
12642 },
12643 mouseout: function(inEvent) {
12644 if (!this.isEventSimulatedFromTouch(inEvent)) {
12645 var e = this.prepareEvent(inEvent);
12646 dispatcher.leaveOut(e);
12647 }
12648 },
12649 cancel: function(inEvent) {
12650 var e = this.prepareEvent(inEvent);
12651 dispatcher.cancel(e);
12652 this.cleanupMouse();
12653 },
12654 cleanupMouse: function() {
12655 pointermap['delete'](this.POINTER_ID);
12656 }
12657 };
12658
12659 scope.mouseEvents = mouseEvents;
12660 })(window.PointerEventsPolyfill);
12661
12662 /*
12663 * Copyright 2013 The Polymer Authors. All rights reserved.
12664 * Use of this source code is governed by a BSD-style
12665 * license that can be found in the LICENSE file.
12666 */
12667
12668 (function(scope) {
12669 var dispatcher = scope.dispatcher;
12670 var captureInfo = dispatcher.captureInfo;
12671 var findTarget = scope.findTarget;
12672 var allShadows = scope.targetFinding.allShadows.bind(scope.targetFinding);
12673 var pointermap = dispatcher.pointermap;
12674 var touchMap = Array.prototype.map.call.bind(Array.prototype.map);
12675 // This should be long enough to ignore compat mouse events made by touch
12676 var DEDUP_TIMEOUT = 2500;
12677 var CLICK_COUNT_TIMEOUT = 200;
12678 var ATTRIB = 'touch-action';
12679 var INSTALLER;
12680 // The presence of touch event handlers blocks scrolling, and so we must be ca reful to
12681 // avoid adding handlers unnecessarily. Chrome plans to add a touch-action-de lay property
12682 // (crbug.com/329559) to address this, and once we have that we can opt-in to a simpler
12683 // handler registration mechanism. Rather than try to predict how exactly to opt-in to
12684 // that we'll just leave this disabled until there is a build of Chrome to tes t.
12685 var HAS_TOUCH_ACTION_DELAY = false;
12686
12687 // handler block for native touch events
12688 var touchEvents = {
12689 events: [
12690 'touchstart',
12691 'touchmove',
12692 'touchend',
12693 'touchcancel'
12694 ],
12695 register: function(target) {
12696 if (HAS_TOUCH_ACTION_DELAY) {
12697 dispatcher.listen(target, this.events);
12698 } else {
12699 INSTALLER.enableOnSubtree(target);
12700 }
12701 },
12702 unregister: function(target) {
12703 if (HAS_TOUCH_ACTION_DELAY) {
12704 dispatcher.unlisten(target, this.events);
12705 } else {
12706 // TODO(dfreedman): is it worth it to disconnect the MO?
12707 }
12708 },
12709 elementAdded: function(el) {
12710 var a = el.getAttribute(ATTRIB);
12711 var st = this.touchActionToScrollType(a);
12712 if (st) {
12713 el._scrollType = st;
12714 dispatcher.listen(el, this.events);
12715 // set touch-action on shadows as well
12716 allShadows(el).forEach(function(s) {
12717 s._scrollType = st;
12718 dispatcher.listen(s, this.events);
12719 }, this);
12720 }
12721 },
12722 elementRemoved: function(el) {
12723 el._scrollType = undefined;
12724 dispatcher.unlisten(el, this.events);
12725 // remove touch-action from shadow
12726 allShadows(el).forEach(function(s) {
12727 s._scrollType = undefined;
12728 dispatcher.unlisten(s, this.events);
12729 }, this);
12730 },
12731 elementChanged: function(el, oldValue) {
12732 var a = el.getAttribute(ATTRIB);
12733 var st = this.touchActionToScrollType(a);
12734 var oldSt = this.touchActionToScrollType(oldValue);
12735 // simply update scrollType if listeners are already established
12736 if (st && oldSt) {
12737 el._scrollType = st;
12738 allShadows(el).forEach(function(s) {
12739 s._scrollType = st;
12740 }, this);
12741 } else if (oldSt) {
12742 this.elementRemoved(el);
12743 } else if (st) {
12744 this.elementAdded(el);
12745 }
12746 },
12747 scrollTypes: {
12748 EMITTER: 'none',
12749 XSCROLLER: 'pan-x',
12750 YSCROLLER: 'pan-y',
12751 SCROLLER: /^(?:pan-x pan-y)|(?:pan-y pan-x)|auto$/
12752 },
12753 touchActionToScrollType: function(touchAction) {
12754 var t = touchAction;
12755 var st = this.scrollTypes;
12756 if (t === 'none') {
12757 return 'none';
12758 } else if (t === st.XSCROLLER) {
12759 return 'X';
12760 } else if (t === st.YSCROLLER) {
12761 return 'Y';
12762 } else if (st.SCROLLER.exec(t)) {
12763 return 'XY';
12764 }
12765 },
12766 POINTER_TYPE: 'touch',
12767 firstTouch: null,
12768 isPrimaryTouch: function(inTouch) {
12769 return this.firstTouch === inTouch.identifier;
12770 },
12771 setPrimaryTouch: function(inTouch) {
12772 // set primary touch if there no pointers, or the only pointer is the mous e
12773 if (pointermap.pointers() === 0 || (pointermap.pointers() === 1 && pointer map.has(1))) {
12774 this.firstTouch = inTouch.identifier;
12775 this.firstXY = {X: inTouch.clientX, Y: inTouch.clientY};
12776 this.scrolling = false;
12777 this.cancelResetClickCount();
12778 }
12779 },
12780 removePrimaryPointer: function(inPointer) {
12781 if (inPointer.isPrimary) {
12782 this.firstTouch = null;
12783 this.firstXY = null;
12784 this.resetClickCount();
12785 }
12786 },
12787 clickCount: 0,
12788 resetId: null,
12789 resetClickCount: function() {
12790 var fn = function() {
12791 this.clickCount = 0;
12792 this.resetId = null;
12793 }.bind(this);
12794 this.resetId = setTimeout(fn, CLICK_COUNT_TIMEOUT);
12795 },
12796 cancelResetClickCount: function() {
12797 if (this.resetId) {
12798 clearTimeout(this.resetId);
12799 }
12800 },
12801 typeToButtons: function(type) {
12802 var ret = 0;
12803 if (type === 'touchstart' || type === 'touchmove') {
12804 ret = 1;
12805 }
12806 return ret;
12807 },
12808 touchToPointer: function(inTouch) {
12809 var cte = this.currentTouchEvent;
12810 var e = dispatcher.cloneEvent(inTouch);
12811 // Spec specifies that pointerId 1 is reserved for Mouse.
12812 // Touch identifiers can start at 0.
12813 // Add 2 to the touch identifier for compatibility.
12814 var id = e.pointerId = inTouch.identifier + 2;
12815 e.target = captureInfo[id] || findTarget(e);
12816 e.bubbles = true;
12817 e.cancelable = true;
12818 e.detail = this.clickCount;
12819 e.button = 0;
12820 e.buttons = this.typeToButtons(cte.type);
12821 e.width = inTouch.webkitRadiusX || inTouch.radiusX || 0;
12822 e.height = inTouch.webkitRadiusY || inTouch.radiusY || 0;
12823 e.pressure = inTouch.webkitForce || inTouch.force || 0.5;
12824 e.isPrimary = this.isPrimaryTouch(inTouch);
12825 e.pointerType = this.POINTER_TYPE;
12826 // forward touch preventDefaults
12827 var self = this;
12828 e.preventDefault = function() {
12829 self.scrolling = false;
12830 self.firstXY = null;
12831 cte.preventDefault();
12832 };
12833 return e;
12834 },
12835 processTouches: function(inEvent, inFunction) {
12836 var tl = inEvent.changedTouches;
12837 this.currentTouchEvent = inEvent;
12838 for (var i = 0, t; i < tl.length; i++) {
12839 t = tl[i];
12840 inFunction.call(this, this.touchToPointer(t));
12841 }
12842 },
12843 // For single axis scrollers, determines whether the element should emit
12844 // pointer events or behave as a scroller
12845 shouldScroll: function(inEvent) {
12846 if (this.firstXY) {
12847 var ret;
12848 var scrollAxis = inEvent.currentTarget._scrollType;
12849 if (scrollAxis === 'none') {
12850 // this element is a touch-action: none, should never scroll
12851 ret = false;
12852 } else if (scrollAxis === 'XY') {
12853 // this element should always scroll
12854 ret = true;
12855 } else {
12856 var t = inEvent.changedTouches[0];
12857 // check the intended scroll axis, and other axis
12858 var a = scrollAxis;
12859 var oa = scrollAxis === 'Y' ? 'X' : 'Y';
12860 var da = Math.abs(t['client' + a] - this.firstXY[a]);
12861 var doa = Math.abs(t['client' + oa] - this.firstXY[oa]);
12862 // if delta in the scroll axis > delta other axis, scroll instead of
12863 // making events
12864 ret = da >= doa;
12865 }
12866 this.firstXY = null;
12867 return ret;
12868 }
12869 },
12870 findTouch: function(inTL, inId) {
12871 for (var i = 0, l = inTL.length, t; i < l && (t = inTL[i]); i++) {
12872 if (t.identifier === inId) {
12873 return true;
12874 }
12875 }
12876 },
12877 // In some instances, a touchstart can happen without a touchend. This
12878 // leaves the pointermap in a broken state.
12879 // Therefore, on every touchstart, we remove the touches that did not fire a
12880 // touchend event.
12881 // To keep state globally consistent, we fire a
12882 // pointercancel for this "abandoned" touch
12883 vacuumTouches: function(inEvent) {
12884 var tl = inEvent.touches;
12885 // pointermap.pointers() should be < tl.length here, as the touchstart has not
12886 // been processed yet.
12887 if (pointermap.pointers() >= tl.length) {
12888 var d = [];
12889 pointermap.forEach(function(value, key) {
12890 // Never remove pointerId == 1, which is mouse.
12891 // Touch identifiers are 2 smaller than their pointerId, which is the
12892 // index in pointermap.
12893 if (key !== 1 && !this.findTouch(tl, key - 2)) {
12894 var p = value.out;
12895 d.push(p);
12896 }
12897 }, this);
12898 d.forEach(this.cancelOut, this);
12899 }
12900 },
12901 touchstart: function(inEvent) {
12902 this.vacuumTouches(inEvent);
12903 this.setPrimaryTouch(inEvent.changedTouches[0]);
12904 this.dedupSynthMouse(inEvent);
12905 if (!this.scrolling) {
12906 this.clickCount++;
12907 this.processTouches(inEvent, this.overDown);
12908 }
12909 },
12910 overDown: function(inPointer) {
12911 var p = pointermap.set(inPointer.pointerId, {
12912 target: inPointer.target,
12913 out: inPointer,
12914 outTarget: inPointer.target
12915 });
12916 dispatcher.over(inPointer);
12917 dispatcher.enter(inPointer);
12918 dispatcher.down(inPointer);
12919 },
12920 touchmove: function(inEvent) {
12921 if (!this.scrolling) {
12922 if (this.shouldScroll(inEvent)) {
12923 this.scrolling = true;
12924 this.touchcancel(inEvent);
12925 } else {
12926 inEvent.preventDefault();
12927 this.processTouches(inEvent, this.moveOverOut);
12928 }
12929 }
12930 },
12931 moveOverOut: function(inPointer) {
12932 var event = inPointer;
12933 var pointer = pointermap.get(event.pointerId);
12934 // a finger drifted off the screen, ignore it
12935 if (!pointer) {
12936 return;
12937 }
12938 var outEvent = pointer.out;
12939 var outTarget = pointer.outTarget;
12940 dispatcher.move(event);
12941 if (outEvent && outTarget !== event.target) {
12942 outEvent.relatedTarget = event.target;
12943 event.relatedTarget = outTarget;
12944 // recover from retargeting by shadow
12945 outEvent.target = outTarget;
12946 if (event.target) {
12947 dispatcher.leaveOut(outEvent);
12948 dispatcher.enterOver(event);
12949 } else {
12950 // clean up case when finger leaves the screen
12951 event.target = outTarget;
12952 event.relatedTarget = null;
12953 this.cancelOut(event);
12954 }
12955 }
12956 pointer.out = event;
12957 pointer.outTarget = event.target;
12958 },
12959 touchend: function(inEvent) {
12960 this.dedupSynthMouse(inEvent);
12961 this.processTouches(inEvent, this.upOut);
12962 },
12963 upOut: function(inPointer) {
12964 if (!this.scrolling) {
12965 dispatcher.up(inPointer);
12966 dispatcher.out(inPointer);
12967 dispatcher.leave(inPointer);
12968 }
12969 this.cleanUpPointer(inPointer);
12970 },
12971 touchcancel: function(inEvent) {
12972 this.processTouches(inEvent, this.cancelOut);
12973 },
12974 cancelOut: function(inPointer) {
12975 dispatcher.cancel(inPointer);
12976 dispatcher.out(inPointer);
12977 dispatcher.leave(inPointer);
12978 this.cleanUpPointer(inPointer);
12979 },
12980 cleanUpPointer: function(inPointer) {
12981 pointermap['delete'](inPointer.pointerId);
12982 this.removePrimaryPointer(inPointer);
12983 },
12984 // prevent synth mouse events from creating pointer events
12985 dedupSynthMouse: function(inEvent) {
12986 var lts = scope.mouseEvents.lastTouches;
12987 var t = inEvent.changedTouches[0];
12988 // only the primary finger will synth mouse events
12989 if (this.isPrimaryTouch(t)) {
12990 // remember x/y of last touch
12991 var lt = {x: t.clientX, y: t.clientY};
12992 lts.push(lt);
12993 var fn = (function(lts, lt){
12994 var i = lts.indexOf(lt);
12995 if (i > -1) {
12996 lts.splice(i, 1);
12997 }
12998 }).bind(null, lts, lt);
12999 setTimeout(fn, DEDUP_TIMEOUT);
13000 }
13001 }
13002 };
13003
13004 if (!HAS_TOUCH_ACTION_DELAY) {
13005 INSTALLER = new scope.Installer(touchEvents.elementAdded, touchEvents.elemen tRemoved, touchEvents.elementChanged, touchEvents);
13006 }
13007
13008 scope.touchEvents = touchEvents;
13009 })(window.PointerEventsPolyfill);
13010
13011 /*
13012 * Copyright 2013 The Polymer Authors. All rights reserved.
13013 * Use of this source code is governed by a BSD-style
13014 * license that can be found in the LICENSE file.
13015 */
13016
13017 (function(scope) {
13018 var dispatcher = scope.dispatcher;
13019 var pointermap = dispatcher.pointermap;
13020 var HAS_BITMAP_TYPE = window.MSPointerEvent && typeof window.MSPointerEvent.MS POINTER_TYPE_MOUSE === 'number';
13021 var msEvents = {
13022 events: [
13023 'MSPointerDown',
13024 'MSPointerMove',
13025 'MSPointerUp',
13026 'MSPointerOut',
13027 'MSPointerOver',
13028 'MSPointerCancel',
13029 'MSGotPointerCapture',
13030 'MSLostPointerCapture'
13031 ],
13032 register: function(target) {
13033 dispatcher.listen(target, this.events);
13034 },
13035 unregister: function(target) {
13036 dispatcher.unlisten(target, this.events);
13037 },
13038 POINTER_TYPES: [
13039 '',
13040 'unavailable',
13041 'touch',
13042 'pen',
13043 'mouse'
13044 ],
13045 prepareEvent: function(inEvent) {
13046 var e = inEvent;
13047 if (HAS_BITMAP_TYPE) {
13048 e = dispatcher.cloneEvent(inEvent);
13049 e.pointerType = this.POINTER_TYPES[inEvent.pointerType];
13050 }
13051 return e;
13052 },
13053 cleanup: function(id) {
13054 pointermap['delete'](id);
13055 },
13056 MSPointerDown: function(inEvent) {
13057 pointermap.set(inEvent.pointerId, inEvent);
13058 var e = this.prepareEvent(inEvent);
13059 dispatcher.down(e);
13060 },
13061 MSPointerMove: function(inEvent) {
13062 var e = this.prepareEvent(inEvent);
13063 dispatcher.move(e);
13064 },
13065 MSPointerUp: function(inEvent) {
13066 var e = this.prepareEvent(inEvent);
13067 dispatcher.up(e);
13068 this.cleanup(inEvent.pointerId);
13069 },
13070 MSPointerOut: function(inEvent) {
13071 var e = this.prepareEvent(inEvent);
13072 dispatcher.leaveOut(e);
13073 },
13074 MSPointerOver: function(inEvent) {
13075 var e = this.prepareEvent(inEvent);
13076 dispatcher.enterOver(e);
13077 },
13078 MSPointerCancel: function(inEvent) {
13079 var e = this.prepareEvent(inEvent);
13080 dispatcher.cancel(e);
13081 this.cleanup(inEvent.pointerId);
13082 },
13083 MSLostPointerCapture: function(inEvent) {
13084 var e = dispatcher.makeEvent('lostpointercapture', inEvent);
13085 dispatcher.dispatchEvent(e);
13086 },
13087 MSGotPointerCapture: function(inEvent) {
13088 var e = dispatcher.makeEvent('gotpointercapture', inEvent);
13089 dispatcher.dispatchEvent(e);
13090 }
13091 };
13092
13093 scope.msEvents = msEvents;
13094 })(window.PointerEventsPolyfill);
13095
13096 /*
13097 * Copyright 2013 The Polymer Authors. All rights reserved.
13098 * Use of this source code is governed by a BSD-style
13099 * license that can be found in the LICENSE file.
13100 */
13101
13102 /**
13103 * This module contains the handlers for native platform events.
13104 * From here, the dispatcher is called to create unified pointer events.
13105 * Included are touch events (v1), mouse events, and MSPointerEvents.
13106 */
13107 (function(scope) {
13108 var dispatcher = scope.dispatcher;
13109
13110 // only activate if this platform does not have pointer events
13111 if (window.PointerEvent !== scope.PointerEvent) {
13112
13113 if (window.navigator.msPointerEnabled) {
13114 var tp = window.navigator.msMaxTouchPoints;
13115 Object.defineProperty(window.navigator, 'maxTouchPoints', {
13116 value: tp,
13117 enumerable: true
13118 });
13119 dispatcher.registerSource('ms', scope.msEvents);
13120 } else {
13121 dispatcher.registerSource('mouse', scope.mouseEvents);
13122 if (window.ontouchstart !== undefined) {
13123 dispatcher.registerSource('touch', scope.touchEvents);
13124 }
13125 }
13126
13127 dispatcher.register(document);
13128 }
13129 })(window.PointerEventsPolyfill);
13130
13131 /*
13132 * Copyright 2013 The Polymer Authors. All rights reserved.
13133 * Use of this source code is governed by a BSD-style
13134 * license that can be found in the LICENSE file.
13135 */
13136
13137 (function(scope) {
13138 var dispatcher = scope.dispatcher;
13139 var n = window.navigator;
13140 var s, r;
13141 function assertDown(id) {
13142 if (!dispatcher.pointermap.has(id)) {
13143 throw new Error('InvalidPointerId');
13144 }
13145 }
13146 if (n.msPointerEnabled) {
13147 s = function(pointerId) {
13148 assertDown(pointerId);
13149 this.msSetPointerCapture(pointerId);
13150 };
13151 r = function(pointerId) {
13152 assertDown(pointerId);
13153 this.msReleasePointerCapture(pointerId);
13154 };
13155 } else {
13156 s = function setPointerCapture(pointerId) {
13157 assertDown(pointerId);
13158 dispatcher.setCapture(pointerId, this);
13159 };
13160 r = function releasePointerCapture(pointerId) {
13161 assertDown(pointerId);
13162 dispatcher.releaseCapture(pointerId, this);
13163 };
13164 }
13165 if (window.Element && !Element.prototype.setPointerCapture) {
13166 Object.defineProperties(Element.prototype, {
13167 'setPointerCapture': {
13168 value: s
13169 },
13170 'releasePointerCapture': {
13171 value: r
13172 }
13173 });
13174 }
13175 })(window.PointerEventsPolyfill);
13176
13177 /*
13178 * Copyright 2013 The Polymer Authors. All rights reserved.
13179 * Use of this source code is governed by a BSD-style
13180 * license that can be found in the LICENSE file.
13181 */
13182
13183 /**
13184 * PointerGestureEvent is the constructor for all PointerGesture events.
13185 *
13186 * @module PointerGestures
13187 * @class PointerGestureEvent
13188 * @extends UIEvent
13189 * @constructor
13190 * @param {String} inType Event type
13191 * @param {Object} [inDict] Dictionary of properties to initialize on the event
13192 */
13193
13194 function PointerGestureEvent(inType, inDict) {
13195 var dict = inDict || {};
13196 var e = document.createEvent('Event');
13197 var props = {
13198 bubbles: Boolean(dict.bubbles) === dict.bubbles || true,
13199 cancelable: Boolean(dict.cancelable) === dict.cancelable || true
13200 };
13201
13202 e.initEvent(inType, props.bubbles, props.cancelable);
13203
13204 var keys = Object.keys(dict), k;
13205 for (var i = 0; i < keys.length; i++) {
13206 k = keys[i];
13207 e[k] = dict[k];
13208 }
13209
13210 e.preventTap = this.preventTap;
13211
13212 return e;
13213 }
13214
13215 /**
13216 * Allows for any gesture to prevent the tap gesture.
13217 *
13218 * @method preventTap
13219 */
13220 PointerGestureEvent.prototype.preventTap = function() {
13221 this.tapPrevented = true;
13222 };
13223
13224
13225 /*
13226 * Copyright 2013 The Polymer Authors. All rights reserved.
13227 * Use of this source code is governed by a BSD-style
13228 * license that can be found in the LICENSE file.
13229 */
13230
13231 (function(scope) {
13232 /**
13233 * This class contains the gesture recognizers that create the PointerGesture
13234 * events.
13235 *
13236 * @class PointerGestures
13237 * @static
13238 */
13239 scope = scope || {};
13240 scope.utils = {
13241 LCA: {
13242 // Determines the lowest node in the ancestor chain of a and b
13243 find: function(a, b) {
13244 if (a === b) {
13245 return a;
13246 }
13247 // fast case, a is a direct descendant of b or vice versa
13248 if (a.contains) {
13249 if (a.contains(b)) {
13250 return a;
13251 }
13252 if (b.contains(a)) {
13253 return b;
13254 }
13255 }
13256 var adepth = this.depth(a);
13257 var bdepth = this.depth(b);
13258 var d = adepth - bdepth;
13259 if (d > 0) {
13260 a = this.walk(a, d);
13261 } else {
13262 b = this.walk(b, -d);
13263 }
13264 while(a && b && a !== b) {
13265 a = this.walk(a, 1);
13266 b = this.walk(b, 1);
13267 }
13268 return a;
13269 },
13270 walk: function(n, u) {
13271 for (var i = 0; i < u; i++) {
13272 n = n.parentNode;
13273 }
13274 return n;
13275 },
13276 depth: function(n) {
13277 var d = 0;
13278 while(n) {
13279 d++;
13280 n = n.parentNode;
13281 }
13282 return d;
13283 }
13284 }
13285 };
13286 scope.findLCA = function(a, b) {
13287 return scope.utils.LCA.find(a, b);
13288 }
13289 window.PointerGestures = scope;
13290 })(window.PointerGestures);
13291
13292 /*
13293 * Copyright 2013 The Polymer Authors. All rights reserved.
13294 * Use of this source code is governed by a BSD-style
13295 * license that can be found in the LICENSE file.
13296 */
13297
13298 /**
13299 * This module implements an map of pointer states
13300 */
13301 (function(scope) {
13302 var USE_MAP = window.Map && window.Map.prototype.forEach;
13303 var POINTERS_FN = function(){ return this.size; };
13304 function PointerMap() {
13305 if (USE_MAP) {
13306 var m = new Map();
13307 m.pointers = POINTERS_FN;
13308 return m;
13309 } else {
13310 this.keys = [];
13311 this.values = [];
13312 }
13313 }
13314
13315 PointerMap.prototype = {
13316 set: function(inId, inEvent) {
13317 var i = this.keys.indexOf(inId);
13318 if (i > -1) {
13319 this.values[i] = inEvent;
13320 } else {
13321 this.keys.push(inId);
13322 this.values.push(inEvent);
13323 }
13324 },
13325 has: function(inId) {
13326 return this.keys.indexOf(inId) > -1;
13327 },
13328 'delete': function(inId) {
13329 var i = this.keys.indexOf(inId);
13330 if (i > -1) {
13331 this.keys.splice(i, 1);
13332 this.values.splice(i, 1);
13333 }
13334 },
13335 get: function(inId) {
13336 var i = this.keys.indexOf(inId);
13337 return this.values[i];
13338 },
13339 clear: function() {
13340 this.keys.length = 0;
13341 this.values.length = 0;
13342 },
13343 // return value, key, map
13344 forEach: function(callback, thisArg) {
13345 this.values.forEach(function(v, i) {
13346 callback.call(thisArg, v, this.keys[i], this);
13347 }, this);
13348 },
13349 pointers: function() {
13350 return this.keys.length;
13351 }
13352 };
13353
13354 scope.PointerMap = PointerMap;
13355 })(window.PointerGestures);
13356
13357 /*
13358 * Copyright 2013 The Polymer Authors. All rights reserved.
13359 * Use of this source code is governed by a BSD-style
13360 * license that can be found in the LICENSE file.
13361 */
13362
13363 (function(scope) {
13364 var CLONE_PROPS = [
13365 // MouseEvent
13366 'bubbles',
13367 'cancelable',
13368 'view',
13369 'detail',
13370 'screenX',
13371 'screenY',
13372 'clientX',
13373 'clientY',
13374 'ctrlKey',
13375 'altKey',
13376 'shiftKey',
13377 'metaKey',
13378 'button',
13379 'relatedTarget',
13380 // DOM Level 3
13381 'buttons',
13382 // PointerEvent
13383 'pointerId',
13384 'width',
13385 'height',
13386 'pressure',
13387 'tiltX',
13388 'tiltY',
13389 'pointerType',
13390 'hwTimestamp',
13391 'isPrimary',
13392 // event instance
13393 'type',
13394 'target',
13395 'currentTarget',
13396 'screenX',
13397 'screenY',
13398 'pageX',
13399 'pageY',
13400 'tapPrevented'
13401 ];
13402
13403 var CLONE_DEFAULTS = [
13404 // MouseEvent
13405 false,
13406 false,
13407 null,
13408 null,
13409 0,
13410 0,
13411 0,
13412 0,
13413 false,
13414 false,
13415 false,
13416 false,
13417 0,
13418 null,
13419 // DOM Level 3
13420 0,
13421 // PointerEvent
13422 0,
13423 0,
13424 0,
13425 0,
13426 0,
13427 0,
13428 '',
13429 0,
13430 false,
13431 // event instance
13432 '',
13433 null,
13434 null,
13435 0,
13436 0,
13437 0,
13438 0
13439 ];
13440
13441 var dispatcher = {
13442 handledEvents: new WeakMap(),
13443 targets: new WeakMap(),
13444 handlers: {},
13445 recognizers: {},
13446 events: {},
13447 // Add a new gesture recognizer to the event listeners.
13448 // Recognizer needs an `events` property.
13449 registerRecognizer: function(inName, inRecognizer) {
13450 var r = inRecognizer;
13451 this.recognizers[inName] = r;
13452 r.events.forEach(function(e) {
13453 if (r[e]) {
13454 this.events[e] = true;
13455 var f = r[e].bind(r);
13456 this.addHandler(e, f);
13457 }
13458 }, this);
13459 },
13460 addHandler: function(inEvent, inFn) {
13461 var e = inEvent;
13462 if (!this.handlers[e]) {
13463 this.handlers[e] = [];
13464 }
13465 this.handlers[e].push(inFn);
13466 },
13467 // add event listeners for inTarget
13468 registerTarget: function(inTarget) {
13469 this.listen(Object.keys(this.events), inTarget);
13470 },
13471 // remove event listeners for inTarget
13472 unregisterTarget: function(inTarget) {
13473 this.unlisten(Object.keys(this.events), inTarget);
13474 },
13475 // LISTENER LOGIC
13476 eventHandler: function(inEvent) {
13477 if (this.handledEvents.get(inEvent)) {
13478 return;
13479 }
13480 var type = inEvent.type, fns = this.handlers[type];
13481 if (fns) {
13482 this.makeQueue(fns, inEvent);
13483 }
13484 this.handledEvents.set(inEvent, true);
13485 },
13486 // queue event for async dispatch
13487 makeQueue: function(inHandlerFns, inEvent) {
13488 // must clone events to keep the (possibly shadowed) target correct for
13489 // async dispatching
13490 var e = this.cloneEvent(inEvent);
13491 requestAnimationFrame(this.runQueue.bind(this, inHandlerFns, e));
13492 },
13493 // Dispatch the queued events
13494 runQueue: function(inHandlers, inEvent) {
13495 this.currentPointerId = inEvent.pointerId;
13496 for (var i = 0, f, l = inHandlers.length; (i < l) && (f = inHandlers[i]); i++) {
13497 f(inEvent);
13498 }
13499 this.currentPointerId = 0;
13500 },
13501 // set up event listeners
13502 listen: function(inEvents, inTarget) {
13503 inEvents.forEach(function(e) {
13504 this.addEvent(e, this.boundHandler, false, inTarget);
13505 }, this);
13506 },
13507 // remove event listeners
13508 unlisten: function(inEvents) {
13509 inEvents.forEach(function(e) {
13510 this.removeEvent(e, this.boundHandler, false, inTarget);
13511 }, this);
13512 },
13513 addEvent: function(inEventName, inEventHandler, inCapture, inTarget) {
13514 inTarget.addEventListener(inEventName, inEventHandler, inCapture);
13515 },
13516 removeEvent: function(inEventName, inEventHandler, inCapture, inTarget) {
13517 inTarget.removeEventListener(inEventName, inEventHandler, inCapture);
13518 },
13519 // EVENT CREATION AND TRACKING
13520 // Creates a new Event of type `inType`, based on the information in
13521 // `inEvent`.
13522 makeEvent: function(inType, inDict) {
13523 return new PointerGestureEvent(inType, inDict);
13524 },
13525 /*
13526 * Returns a snapshot of inEvent, with writable properties.
13527 *
13528 * @method cloneEvent
13529 * @param {Event} inEvent An event that contains properties to copy.
13530 * @return {Object} An object containing shallow copies of `inEvent`'s
13531 * properties.
13532 */
13533 cloneEvent: function(inEvent) {
13534 var eventCopy = {}, p;
13535 for (var i = 0; i < CLONE_PROPS.length; i++) {
13536 p = CLONE_PROPS[i];
13537 eventCopy[p] = inEvent[p] || CLONE_DEFAULTS[i];
13538 }
13539 return eventCopy;
13540 },
13541 // Dispatches the event to its target.
13542 dispatchEvent: function(inEvent, inTarget) {
13543 var t = inTarget || this.targets.get(inEvent);
13544 if (t) {
13545 t.dispatchEvent(inEvent);
13546 if (inEvent.tapPrevented) {
13547 this.preventTap(this.currentPointerId);
13548 }
13549 }
13550 },
13551 asyncDispatchEvent: function(inEvent, inTarget) {
13552 requestAnimationFrame(this.dispatchEvent.bind(this, inEvent, inTarget));
13553 },
13554 preventTap: function(inPointerId) {
13555 var t = this.recognizers.tap;
13556 if (t){
13557 t.preventTap(inPointerId);
13558 }
13559 }
13560 };
13561 dispatcher.boundHandler = dispatcher.eventHandler.bind(dispatcher);
13562 // recognizers call into the dispatcher and load later
13563 // solve the chicken and egg problem by having registerScopes module run last
13564 dispatcher.registerQueue = [];
13565 dispatcher.immediateRegister = false;
13566 scope.dispatcher = dispatcher;
13567 /**
13568 * Enable gesture events for a given scope, typically
13569 * [ShadowRoots](https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow /index.html#shadow-root-object).
13570 *
13571 * @for PointerGestures
13572 * @method register
13573 * @param {ShadowRoot} scope A top level scope to enable gesture
13574 * support on.
13575 */
13576 scope.register = function(inScope) {
13577 if (dispatcher.immediateRegister) {
13578 var pe = window.PointerEventsPolyfill;
13579 if (pe) {
13580 pe.register(inScope);
13581 }
13582 scope.dispatcher.registerTarget(inScope);
13583 } else {
13584 dispatcher.registerQueue.push(inScope);
13585 }
13586 };
13587 scope.register(document);
13588 })(window.PointerGestures);
13589
13590 /*
13591 * Copyright 2013 The Polymer Authors. All rights reserved.
13592 * Use of this source code is governed by a BSD-style
13593 * license that can be found in the LICENSE file.
13594 */
13595
13596 /**
13597 * This event is fired when a pointer is held down for 200ms.
13598 *
13599 * @module PointerGestures
13600 * @submodule Events
13601 * @class hold
13602 */
13603 /**
13604 * Type of pointer that made the holding event.
13605 * @type String
13606 * @property pointerType
13607 */
13608 /**
13609 * Screen X axis position of the held pointer
13610 * @type Number
13611 * @property clientX
13612 */
13613 /**
13614 * Screen Y axis position of the held pointer
13615 * @type Number
13616 * @property clientY
13617 */
13618 /**
13619 * Type of pointer that made the holding event.
13620 * @type String
13621 * @property pointerType
13622 */
13623 /**
13624 * This event is fired every 200ms while a pointer is held down.
13625 *
13626 * @class holdpulse
13627 * @extends hold
13628 */
13629 /**
13630 * Milliseconds pointer has been held down.
13631 * @type Number
13632 * @property holdTime
13633 */
13634 /**
13635 * This event is fired when a held pointer is released or moved.
13636 *
13637 * @class released
13638 */
13639
13640 (function(scope) {
13641 var dispatcher = scope.dispatcher;
13642 var hold = {
13643 // wait at least HOLD_DELAY ms between hold and pulse events
13644 HOLD_DELAY: 200,
13645 // pointer can move WIGGLE_THRESHOLD pixels before not counting as a hold
13646 WIGGLE_THRESHOLD: 16,
13647 events: [
13648 'pointerdown',
13649 'pointermove',
13650 'pointerup',
13651 'pointercancel'
13652 ],
13653 heldPointer: null,
13654 holdJob: null,
13655 pulse: function() {
13656 var hold = Date.now() - this.heldPointer.timeStamp;
13657 var type = this.held ? 'holdpulse' : 'hold';
13658 this.fireHold(type, hold);
13659 this.held = true;
13660 },
13661 cancel: function() {
13662 clearInterval(this.holdJob);
13663 if (this.held) {
13664 this.fireHold('release');
13665 }
13666 this.held = false;
13667 this.heldPointer = null;
13668 this.target = null;
13669 this.holdJob = null;
13670 },
13671 pointerdown: function(inEvent) {
13672 if (inEvent.isPrimary && !this.heldPointer) {
13673 this.heldPointer = inEvent;
13674 this.target = inEvent.target;
13675 this.holdJob = setInterval(this.pulse.bind(this), this.HOLD_DELAY);
13676 }
13677 },
13678 pointerup: function(inEvent) {
13679 if (this.heldPointer && this.heldPointer.pointerId === inEvent.pointerId) {
13680 this.cancel();
13681 }
13682 },
13683 pointercancel: function(inEvent) {
13684 this.cancel();
13685 },
13686 pointermove: function(inEvent) {
13687 if (this.heldPointer && this.heldPointer.pointerId === inEvent.pointerId) {
13688 var x = inEvent.clientX - this.heldPointer.clientX;
13689 var y = inEvent.clientY - this.heldPointer.clientY;
13690 if ((x * x + y * y) > this.WIGGLE_THRESHOLD) {
13691 this.cancel();
13692 }
13693 }
13694 },
13695 fireHold: function(inType, inHoldTime) {
13696 var p = {
13697 pointerType: this.heldPointer.pointerType,
13698 clientX: this.heldPointer.clientX,
13699 clientY: this.heldPointer.clientY
13700 };
13701 if (inHoldTime) {
13702 p.holdTime = inHoldTime;
13703 }
13704 var e = dispatcher.makeEvent(inType, p);
13705 dispatcher.dispatchEvent(e, this.target);
13706 if (e.tapPrevented) {
13707 dispatcher.preventTap(this.heldPointer.pointerId);
13708 }
13709 }
13710 };
13711 dispatcher.registerRecognizer('hold', hold);
13712 })(window.PointerGestures);
13713
13714 /*
13715 * Copyright 2013 The Polymer Authors. All rights reserved.
13716 * Use of this source code is governed by a BSD-style
13717 * license that can be found in the LICENSE file.
13718 */
13719
13720 /**
13721 * This event denotes the beginning of a series of tracking events.
13722 *
13723 * @module PointerGestures
13724 * @submodule Events
13725 * @class trackstart
13726 */
13727 /**
13728 * Pixels moved in the x direction since trackstart.
13729 * @type Number
13730 * @property dx
13731 */
13732 /**
13733 * Pixes moved in the y direction since trackstart.
13734 * @type Number
13735 * @property dy
13736 */
13737 /**
13738 * Pixels moved in the x direction since the last track.
13739 * @type Number
13740 * @property ddx
13741 */
13742 /**
13743 * Pixles moved in the y direction since the last track.
13744 * @type Number
13745 * @property ddy
13746 */
13747 /**
13748 * The clientX position of the track gesture.
13749 * @type Number
13750 * @property clientX
13751 */
13752 /**
13753 * The clientY position of the track gesture.
13754 * @type Number
13755 * @property clientY
13756 */
13757 /**
13758 * The pageX position of the track gesture.
13759 * @type Number
13760 * @property pageX
13761 */
13762 /**
13763 * The pageY position of the track gesture.
13764 * @type Number
13765 * @property pageY
13766 */
13767 /**
13768 * The screenX position of the track gesture.
13769 * @type Number
13770 * @property screenX
13771 */
13772 /**
13773 * The screenY position of the track gesture.
13774 * @type Number
13775 * @property screenY
13776 */
13777 /**
13778 * The last x axis direction of the pointer.
13779 * @type Number
13780 * @property xDirection
13781 */
13782 /**
13783 * The last y axis direction of the pointer.
13784 * @type Number
13785 * @property yDirection
13786 */
13787 /**
13788 * A shared object between all tracking events.
13789 * @type Object
13790 * @property trackInfo
13791 */
13792 /**
13793 * The element currently under the pointer.
13794 * @type Element
13795 * @property relatedTarget
13796 */
13797 /**
13798 * The type of pointer that make the track gesture.
13799 * @type String
13800 * @property pointerType
13801 */
13802 /**
13803 *
13804 * This event fires for all pointer movement being tracked.
13805 *
13806 * @class track
13807 * @extends trackstart
13808 */
13809 /**
13810 * This event fires when the pointer is no longer being tracked.
13811 *
13812 * @class trackend
13813 * @extends trackstart
13814 */
13815
13816 (function(scope) {
13817 var dispatcher = scope.dispatcher;
13818 var pointermap = new scope.PointerMap();
13819 var track = {
13820 events: [
13821 'pointerdown',
13822 'pointermove',
13823 'pointerup',
13824 'pointercancel'
13825 ],
13826 WIGGLE_THRESHOLD: 4,
13827 clampDir: function(inDelta) {
13828 return inDelta > 0 ? 1 : -1;
13829 },
13830 calcPositionDelta: function(inA, inB) {
13831 var x = 0, y = 0;
13832 if (inA && inB) {
13833 x = inB.pageX - inA.pageX;
13834 y = inB.pageY - inA.pageY;
13835 }
13836 return {x: x, y: y};
13837 },
13838 fireTrack: function(inType, inEvent, inTrackingData) {
13839 var t = inTrackingData;
13840 var d = this.calcPositionDelta(t.downEvent, inEvent);
13841 var dd = this.calcPositionDelta(t.lastMoveEvent, inEvent);
13842 if (dd.x) {
13843 t.xDirection = this.clampDir(dd.x);
13844 }
13845 if (dd.y) {
13846 t.yDirection = this.clampDir(dd.y);
13847 }
13848 var trackData = {
13849 dx: d.x,
13850 dy: d.y,
13851 ddx: dd.x,
13852 ddy: dd.y,
13853 clientX: inEvent.clientX,
13854 clientY: inEvent.clientY,
13855 pageX: inEvent.pageX,
13856 pageY: inEvent.pageY,
13857 screenX: inEvent.screenX,
13858 screenY: inEvent.screenY,
13859 xDirection: t.xDirection,
13860 yDirection: t.yDirection,
13861 trackInfo: t.trackInfo,
13862 relatedTarget: inEvent.target,
13863 pointerType: inEvent.pointerType
13864 };
13865 var e = dispatcher.makeEvent(inType, trackData);
13866 t.lastMoveEvent = inEvent;
13867 dispatcher.dispatchEvent(e, t.downTarget);
13868 },
13869 pointerdown: function(inEvent) {
13870 if (inEvent.isPrimary && (inEvent.pointerType === 'mouse' ? inEvent.butto ns === 1 : true)) {
13871 var p = {
13872 downEvent: inEvent,
13873 downTarget: inEvent.target,
13874 trackInfo: {},
13875 lastMoveEvent: null,
13876 xDirection: 0,
13877 yDirection: 0,
13878 tracking: false
13879 };
13880 pointermap.set(inEvent.pointerId, p);
13881 }
13882 },
13883 pointermove: function(inEvent) {
13884 var p = pointermap.get(inEvent.pointerId);
13885 if (p) {
13886 if (!p.tracking) {
13887 var d = this.calcPositionDelta(p.downEvent, inEvent);
13888 var move = d.x * d.x + d.y * d.y;
13889 // start tracking only if finger moves more than WIGGLE_THRESHOLD
13890 if (move > this.WIGGLE_THRESHOLD) {
13891 p.tracking = true;
13892 this.fireTrack('trackstart', p.downEvent, p);
13893 this.fireTrack('track', inEvent, p);
13894 }
13895 } else {
13896 this.fireTrack('track', inEvent, p);
13897 }
13898 }
13899 },
13900 pointerup: function(inEvent) {
13901 var p = pointermap.get(inEvent.pointerId);
13902 if (p) {
13903 if (p.tracking) {
13904 this.fireTrack('trackend', inEvent, p);
13905 }
13906 pointermap.delete(inEvent.pointerId);
13907 }
13908 },
13909 pointercancel: function(inEvent) {
13910 this.pointerup(inEvent);
13911 }
13912 };
13913 dispatcher.registerRecognizer('track', track);
13914 })(window.PointerGestures);
13915
13916 /*
13917 * Copyright 2013 The Polymer Authors. All rights reserved.
13918 * Use of this source code is governed by a BSD-style
13919 * license that can be found in the LICENSE file.
13920 */
13921
13922 /**
13923 * This event denotes a rapid down/move/up sequence from a pointer.
13924 *
13925 * The event is sent to the first element the pointer went down on.
13926 *
13927 * @module PointerGestures
13928 * @submodule Events
13929 * @class flick
13930 */
13931 /**
13932 * Signed velocity of the flick in the x direction.
13933 * @property xVelocity
13934 * @type Number
13935 */
13936 /**
13937 * Signed velocity of the flick in the y direction.
13938 * @type Number
13939 * @property yVelocity
13940 */
13941 /**
13942 * Unsigned total velocity of the flick.
13943 * @type Number
13944 * @property velocity
13945 */
13946 /**
13947 * Angle of the flick in degrees, with 0 along the
13948 * positive x axis.
13949 * @type Number
13950 * @property angle
13951 */
13952 /**
13953 * Axis with the greatest absolute velocity. Denoted
13954 * with 'x' or 'y'.
13955 * @type String
13956 * @property majorAxis
13957 */
13958 /**
13959 * Type of the pointer that made the flick.
13960 * @type String
13961 * @property pointerType
13962 */
13963
13964 (function(scope) {
13965 var dispatcher = scope.dispatcher;
13966 var flick = {
13967 // TODO(dfreedman): value should be low enough for low speed flicks, but
13968 // high enough to remove accidental flicks
13969 MIN_VELOCITY: 0.5 /* px/ms */,
13970 MAX_QUEUE: 4,
13971 moveQueue: [],
13972 target: null,
13973 pointerId: null,
13974 events: [
13975 'pointerdown',
13976 'pointermove',
13977 'pointerup',
13978 'pointercancel'
13979 ],
13980 pointerdown: function(inEvent) {
13981 if (inEvent.isPrimary && !this.pointerId) {
13982 this.pointerId = inEvent.pointerId;
13983 this.target = inEvent.target;
13984 this.addMove(inEvent);
13985 }
13986 },
13987 pointermove: function(inEvent) {
13988 if (inEvent.pointerId === this.pointerId) {
13989 this.addMove(inEvent);
13990 }
13991 },
13992 pointerup: function(inEvent) {
13993 if (inEvent.pointerId === this.pointerId) {
13994 this.fireFlick(inEvent);
13995 }
13996 this.cleanup();
13997 },
13998 pointercancel: function(inEvent) {
13999 this.cleanup();
14000 },
14001 cleanup: function() {
14002 this.moveQueue = [];
14003 this.target = null;
14004 this.pointerId = null;
14005 },
14006 addMove: function(inEvent) {
14007 if (this.moveQueue.length >= this.MAX_QUEUE) {
14008 this.moveQueue.shift();
14009 }
14010 this.moveQueue.push(inEvent);
14011 },
14012 fireFlick: function(inEvent) {
14013 var e = inEvent;
14014 var l = this.moveQueue.length;
14015 var dt, dx, dy, tx, ty, tv, x = 0, y = 0, v = 0;
14016 // flick based off the fastest segment of movement
14017 for (var i = 0, m; i < l && (m = this.moveQueue[i]); i++) {
14018 dt = e.timeStamp - m.timeStamp;
14019 dx = e.clientX - m.clientX, dy = e.clientY - m.clientY;
14020 tx = dx / dt, ty = dy / dt, tv = Math.sqrt(tx * tx + ty * ty);
14021 if (tv > v) {
14022 x = tx, y = ty, v = tv;
14023 }
14024 }
14025 var ma = Math.abs(x) > Math.abs(y) ? 'x' : 'y';
14026 var a = this.calcAngle(x, y);
14027 if (Math.abs(v) >= this.MIN_VELOCITY) {
14028 var ev = dispatcher.makeEvent('flick', {
14029 xVelocity: x,
14030 yVelocity: y,
14031 velocity: v,
14032 angle: a,
14033 majorAxis: ma,
14034 pointerType: inEvent.pointerType
14035 });
14036 dispatcher.dispatchEvent(ev, this.target);
14037 }
14038 },
14039 calcAngle: function(inX, inY) {
14040 return (Math.atan2(inY, inX) * 180 / Math.PI);
14041 }
14042 };
14043 dispatcher.registerRecognizer('flick', flick);
14044 })(window.PointerGestures);
14045
14046 /*
14047 * Copyright 2013 The Polymer Authors. All rights reserved.
14048 * Use of this source code is governed by a BSD-style
14049 * license that can be found in the LICENSE file.
14050 */
14051
14052 /*
14053 * Basic strategy: find the farthest apart points, use as diameter of circle
14054 * react to size change and rotation of the chord
14055 */
14056
14057 /**
14058 * @module PointerGestures
14059 * @submodule Events
14060 * @class pinch
14061 */
14062 /**
14063 * Scale of the pinch zoom gesture
14064 * @property scale
14065 * @type Number
14066 */
14067 /**
14068 * Center X position of pointers causing pinch
14069 * @property centerX
14070 * @type Number
14071 */
14072 /**
14073 * Center Y position of pointers causing pinch
14074 * @property centerY
14075 * @type Number
14076 */
14077
14078 /**
14079 * @module PointerGestures
14080 * @submodule Events
14081 * @class rotate
14082 */
14083 /**
14084 * Angle (in degrees) of rotation. Measured from starting positions of pointers.
14085 * @property angle
14086 * @type Number
14087 */
14088 /**
14089 * Center X position of pointers causing rotation
14090 * @property centerX
14091 * @type Number
14092 */
14093 /**
14094 * Center Y position of pointers causing rotation
14095 * @property centerY
14096 * @type Number
14097 */
14098 (function(scope) {
14099 var dispatcher = scope.dispatcher;
14100 var pointermap = new scope.PointerMap();
14101 var RAD_TO_DEG = 180 / Math.PI;
14102 var pinch = {
14103 events: [
14104 'pointerdown',
14105 'pointermove',
14106 'pointerup',
14107 'pointercancel'
14108 ],
14109 reference: {},
14110 pointerdown: function(ev) {
14111 pointermap.set(ev.pointerId, ev);
14112 if (pointermap.pointers() == 2) {
14113 var points = this.calcChord();
14114 var angle = this.calcAngle(points);
14115 this.reference = {
14116 angle: angle,
14117 diameter: points.diameter,
14118 target: scope.findLCA(points.a.target, points.b.target)
14119 };
14120 }
14121 },
14122 pointerup: function(ev) {
14123 pointermap.delete(ev.pointerId);
14124 },
14125 pointermove: function(ev) {
14126 if (pointermap.has(ev.pointerId)) {
14127 pointermap.set(ev.pointerId, ev);
14128 if (pointermap.pointers() > 1) {
14129 this.calcPinchRotate();
14130 }
14131 }
14132 },
14133 pointercancel: function(ev) {
14134 this.pointerup(ev);
14135 },
14136 dispatchPinch: function(diameter, points) {
14137 var zoom = diameter / this.reference.diameter;
14138 var ev = dispatcher.makeEvent('pinch', {
14139 scale: zoom,
14140 centerX: points.center.x,
14141 centerY: points.center.y
14142 });
14143 dispatcher.dispatchEvent(ev, this.reference.target);
14144 },
14145 dispatchRotate: function(angle, points) {
14146 var diff = Math.round((angle - this.reference.angle) % 360);
14147 var ev = dispatcher.makeEvent('rotate', {
14148 angle: diff,
14149 centerX: points.center.x,
14150 centerY: points.center.y
14151 });
14152 dispatcher.dispatchEvent(ev, this.reference.target);
14153 },
14154 calcPinchRotate: function() {
14155 var points = this.calcChord();
14156 var diameter = points.diameter;
14157 var angle = this.calcAngle(points);
14158 if (diameter != this.reference.diameter) {
14159 this.dispatchPinch(diameter, points);
14160 }
14161 if (angle != this.reference.angle) {
14162 this.dispatchRotate(angle, points);
14163 }
14164 },
14165 calcChord: function() {
14166 var pointers = [];
14167 pointermap.forEach(function(p) {
14168 pointers.push(p);
14169 });
14170 var dist = 0;
14171 // start with at least two pointers
14172 var points = {a: pointers[0], b: pointers[1]};
14173 var x, y, d;
14174 for (var i = 0; i < pointers.length; i++) {
14175 var a = pointers[i];
14176 for (var j = i + 1; j < pointers.length; j++) {
14177 var b = pointers[j];
14178 x = Math.abs(a.clientX - b.clientX);
14179 y = Math.abs(a.clientY - b.clientY);
14180 d = x + y;
14181 if (d > dist) {
14182 dist = d;
14183 points = {a: a, b: b};
14184 }
14185 }
14186 }
14187 x = Math.abs(points.a.clientX + points.b.clientX) / 2;
14188 y = Math.abs(points.a.clientY + points.b.clientY) / 2;
14189 points.center = { x: x, y: y };
14190 points.diameter = dist;
14191 return points;
14192 },
14193 calcAngle: function(points) {
14194 var x = points.a.clientX - points.b.clientX;
14195 var y = points.a.clientY - points.b.clientY;
14196 return (360 + Math.atan2(y, x) * RAD_TO_DEG) % 360;
14197 },
14198 };
14199 dispatcher.registerRecognizer('pinch', pinch);
14200 })(window.PointerGestures);
14201
14202 /*
14203 * Copyright 2013 The Polymer Authors. All rights reserved.
14204 * Use of this source code is governed by a BSD-style
14205 * license that can be found in the LICENSE file.
14206 */
14207
14208 /**
14209 * This event is fired when a pointer quickly goes down and up, and is used to
14210 * denote activation.
14211 *
14212 * Any gesture event can prevent the tap event from being created by calling
14213 * `event.preventTap`.
14214 *
14215 * Any pointer event can prevent the tap by setting the `tapPrevented` property
14216 * on itself.
14217 *
14218 * @module PointerGestures
14219 * @submodule Events
14220 * @class tap
14221 */
14222 /**
14223 * X axis position of the tap.
14224 * @property x
14225 * @type Number
14226 */
14227 /**
14228 * Y axis position of the tap.
14229 * @property y
14230 * @type Number
14231 */
14232 /**
14233 * Type of the pointer that made the tap.
14234 * @property pointerType
14235 * @type String
14236 */
14237 (function(scope) {
14238 var dispatcher = scope.dispatcher;
14239 var pointermap = new scope.PointerMap();
14240 var tap = {
14241 events: [
14242 'pointerdown',
14243 'pointermove',
14244 'pointerup',
14245 'pointercancel',
14246 'keyup'
14247 ],
14248 pointerdown: function(inEvent) {
14249 if (inEvent.isPrimary && !inEvent.tapPrevented) {
14250 pointermap.set(inEvent.pointerId, {
14251 target: inEvent.target,
14252 buttons: inEvent.buttons,
14253 x: inEvent.clientX,
14254 y: inEvent.clientY
14255 });
14256 }
14257 },
14258 pointermove: function(inEvent) {
14259 if (inEvent.isPrimary) {
14260 var start = pointermap.get(inEvent.pointerId);
14261 if (start) {
14262 if (inEvent.tapPrevented) {
14263 pointermap.delete(inEvent.pointerId);
14264 }
14265 }
14266 }
14267 },
14268 shouldTap: function(e, downState) {
14269 if (!e.tapPrevented) {
14270 if (e.pointerType === 'mouse') {
14271 // only allow left click to tap for mouse
14272 return downState.buttons === 1;
14273 } else {
14274 return true;
14275 }
14276 }
14277 },
14278 pointerup: function(inEvent) {
14279 var start = pointermap.get(inEvent.pointerId);
14280 if (start && this.shouldTap(inEvent, start)) {
14281 var t = scope.findLCA(start.target, inEvent.target);
14282 if (t) {
14283 var e = dispatcher.makeEvent('tap', {
14284 x: inEvent.clientX,
14285 y: inEvent.clientY,
14286 detail: inEvent.detail,
14287 pointerType: inEvent.pointerType
14288 });
14289 dispatcher.dispatchEvent(e, t);
14290 }
14291 }
14292 pointermap.delete(inEvent.pointerId);
14293 },
14294 pointercancel: function(inEvent) {
14295 pointermap.delete(inEvent.pointerId);
14296 },
14297 keyup: function(inEvent) {
14298 var code = inEvent.keyCode;
14299 // 32 == spacebar
14300 if (code === 32) {
14301 var t = inEvent.target;
14302 if (!(t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement) ) {
14303 dispatcher.dispatchEvent(dispatcher.makeEvent('tap', {
14304 x: 0,
14305 y: 0,
14306 detail: 0,
14307 pointerType: 'unavailable'
14308 }), t);
14309 }
14310 }
14311 },
14312 preventTap: function(inPointerId) {
14313 pointermap.delete(inPointerId);
14314 }
14315 };
14316 dispatcher.registerRecognizer('tap', tap);
14317 })(window.PointerGestures);
14318
14319 /*
14320 * Copyright 2014 The Polymer Authors. All rights reserved.
14321 * Use of this source code is governed by a BSD-style
14322 * license that can be found in the LICENSE file.
14323 */
14324
14325 /**
14326 * Because recognizers are loaded after dispatcher, we have to wait to register
14327 * scopes until after all the recognizers.
14328 */
14329 (function(scope) {
14330 var dispatcher = scope.dispatcher;
14331 function registerScopes() {
14332 dispatcher.immediateRegister = true;
14333 var rq = dispatcher.registerQueue;
14334 rq.forEach(scope.register);
14335 rq.length = 0;
14336 }
14337 if (document.readyState === 'complete') {
14338 registerScopes();
14339 } else {
14340 // register scopes after a steadystate is reached
14341 // less MutationObserver churn
14342 document.addEventListener('readystatechange', function() {
14343 if (document.readyState === 'complete') {
14344 registerScopes();
14345 }
14346 });
14347 }
14348 })(window.PointerGestures);
14349
14350 // Copyright (c) 2014 The Polymer Project Authors. All rights reserved. 12226 // Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
14351 // This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt 12227 // This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
14352 // The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt 12228 // The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
14353 // The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt 12229 // The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
14354 // Code distributed by Google as part of the polymer project is also 12230 // Code distributed by Google as part of the polymer project is also
14355 // subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt 12231 // subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
14356 12232
14357 (function(global) { 12233 (function(global) {
14358 'use strict'; 12234 'use strict';
14359 12235
14360 var filter = Array.prototype.filter.call.bind(Array.prototype.filter); 12236 var filter = Array.prototype.filter.call.bind(Array.prototype.filter);
14361 12237
14362 function getTreeScope(node) { 12238 function getTreeScope(node) {
14363 while (node.parentNode) { 12239 while (node.parentNode) {
14364 node = node.parentNode; 12240 node = node.parentNode;
14365 } 12241 }
14366 12242
14367 return typeof node.getElementById === 'function' ? node : null; 12243 return typeof node.getElementById === 'function' ? node : null;
14368 } 12244 }
14369 12245
14370 Node.prototype.bind = function(name, observable) { 12246 Node.prototype.bind = function(name, observable) {
14371 console.error('Unhandled binding to Node: ', this, name, observable); 12247 console.error('Unhandled binding to Node: ', this, name, observable);
14372 }; 12248 };
14373 12249
12250 Node.prototype.bindFinished = function() {};
12251
14374 function updateBindings(node, name, binding) { 12252 function updateBindings(node, name, binding) {
14375 var bindings = node.bindings_; 12253 var bindings = node.bindings_;
14376 if (!bindings) 12254 if (!bindings)
14377 bindings = node.bindings_ = {}; 12255 bindings = node.bindings_ = {};
14378 12256
14379 if (bindings[name]) 12257 if (bindings[name])
14380 binding[name].close(); 12258 binding[name].close();
14381 12259
14382 return bindings[name] = binding; 12260 return bindings[name] = binding;
14383 } 12261 }
(...skipping 564 matching lines...) Expand 10 before | Expand all | Expand 10 after
14948 doc.templateContentsOwner_ = d; 12826 doc.templateContentsOwner_ = d;
14949 } 12827 }
14950 return d; 12828 return d;
14951 } 12829 }
14952 12830
14953 function getTemplateStagingDocument(template) { 12831 function getTemplateStagingDocument(template) {
14954 if (!template.stagingDocument_) { 12832 if (!template.stagingDocument_) {
14955 var owner = template.ownerDocument; 12833 var owner = template.ownerDocument;
14956 if (!owner.stagingDocument_) { 12834 if (!owner.stagingDocument_) {
14957 owner.stagingDocument_ = owner.implementation.createHTMLDocument(''); 12835 owner.stagingDocument_ = owner.implementation.createHTMLDocument('');
14958 12836 owner.stagingDocument_.isStagingDocument = true;
14959 // TODO(rafaelw): Remove when fix for 12837 // TODO(rafaelw): Remove when fix for
14960 // https://codereview.chromium.org/164803002/ 12838 // https://codereview.chromium.org/164803002/
14961 // makes it to Chrome release. 12839 // makes it to Chrome release.
14962 var base = owner.stagingDocument_.createElement('base'); 12840 var base = owner.stagingDocument_.createElement('base');
14963 base.href = document.baseURI; 12841 base.href = document.baseURI;
14964 owner.stagingDocument_.head.appendChild(base); 12842 owner.stagingDocument_.head.appendChild(base);
14965 12843
14966 owner.stagingDocument_.stagingDocument_ = owner.stagingDocument_; 12844 owner.stagingDocument_.stagingDocument_ = owner.stagingDocument_;
14967 } 12845 }
14968 12846
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
15191 templateObserver.observe(this, { attributes: true, 13069 templateObserver.observe(this, { attributes: true,
15192 attributeFilter: ['ref'] }); 13070 attributeFilter: ['ref'] });
15193 } 13071 }
15194 13072
15195 return this.iterator_; 13073 return this.iterator_;
15196 }, 13074 },
15197 13075
15198 createInstance: function(model, bindingDelegate, delegate_) { 13076 createInstance: function(model, bindingDelegate, delegate_) {
15199 if (bindingDelegate) 13077 if (bindingDelegate)
15200 delegate_ = this.newDelegate_(bindingDelegate); 13078 delegate_ = this.newDelegate_(bindingDelegate);
13079 else if (!delegate_)
13080 delegate_ = this.delegate_;
15201 13081
15202 if (!this.refContent_) 13082 if (!this.refContent_)
15203 this.refContent_ = this.ref_.content; 13083 this.refContent_ = this.ref_.content;
15204 var content = this.refContent_; 13084 var content = this.refContent_;
15205 if (content.firstChild === null) 13085 if (content.firstChild === null)
15206 return emptyInstance; 13086 return emptyInstance;
15207 13087
15208 var map = this.bindingMap_; 13088 var map = getInstanceBindingMap(content, delegate_);
15209 if (!map || map.content !== content) {
15210 // TODO(rafaelw): Setup a MutationObserver on content to detect
15211 // when the instanceMap is invalid.
15212 map = createInstanceBindingMap(content,
15213 delegate_ && delegate_.prepareBinding) || [];
15214 map.content = content;
15215 this.bindingMap_ = map;
15216 }
15217
15218 var stagingDocument = getTemplateStagingDocument(this); 13089 var stagingDocument = getTemplateStagingDocument(this);
15219 var instance = stagingDocument.createDocumentFragment(); 13090 var instance = stagingDocument.createDocumentFragment();
15220 instance.templateCreator_ = this; 13091 instance.templateCreator_ = this;
15221 instance.protoContent_ = content; 13092 instance.protoContent_ = content;
15222 instance.bindings_ = []; 13093 instance.bindings_ = [];
15223 instance.terminator_ = null; 13094 instance.terminator_ = null;
15224 var instanceRecord = instance.templateInstance_ = { 13095 var instanceRecord = instance.templateInstance_ = {
15225 firstNode: null, 13096 firstNode: null,
15226 lastNode: null, 13097 lastNode: null,
15227 model: model 13098 model: model
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
15293 this.delegate_ = delegate; 13164 this.delegate_ = delegate;
15294 this.bindingMap_ = undefined; 13165 this.bindingMap_ = undefined;
15295 if (this.iterator_) { 13166 if (this.iterator_) {
15296 this.iterator_.instancePositionChangedFn_ = undefined; 13167 this.iterator_.instancePositionChangedFn_ = undefined;
15297 this.iterator_.instanceModelFn_ = undefined; 13168 this.iterator_.instanceModelFn_ = undefined;
15298 } 13169 }
15299 }, 13170 },
15300 13171
15301 newDelegate_: function(bindingDelegate) { 13172 newDelegate_: function(bindingDelegate) {
15302 if (!bindingDelegate) 13173 if (!bindingDelegate)
15303 return {}; 13174 return;
15304 13175
15305 function delegateFn(name) { 13176 function delegateFn(name) {
15306 var fn = bindingDelegate && bindingDelegate[name]; 13177 var fn = bindingDelegate && bindingDelegate[name];
15307 if (typeof fn != 'function') 13178 if (typeof fn != 'function')
15308 return; 13179 return;
15309 13180
15310 return function() { 13181 return function() {
15311 return fn.apply(bindingDelegate, arguments); 13182 return fn.apply(bindingDelegate, arguments);
15312 }; 13183 };
15313 } 13184 }
15314 13185
15315 return { 13186 return {
13187 bindingMaps: {},
15316 raw: bindingDelegate, 13188 raw: bindingDelegate,
15317 prepareBinding: delegateFn('prepareBinding'), 13189 prepareBinding: delegateFn('prepareBinding'),
15318 prepareInstanceModel: delegateFn('prepareInstanceModel'), 13190 prepareInstanceModel: delegateFn('prepareInstanceModel'),
15319 prepareInstancePositionChanged: 13191 prepareInstancePositionChanged:
15320 delegateFn('prepareInstancePositionChanged') 13192 delegateFn('prepareInstancePositionChanged')
15321 }; 13193 };
15322 }, 13194 },
15323 13195
15324 // TODO(rafaelw): Assigning .bindingDelegate always succeeds. It may 13196 // TODO(rafaelw): Assigning .bindingDelegate always succeeds. It may
15325 // make sense to issue a warning or even throw if the template is already 13197 // make sense to issue a warning or even throw if the template is already
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
15484 function processBindings(node, bindings, model, instanceBindings) { 13356 function processBindings(node, bindings, model, instanceBindings) {
15485 for (var i = 0; i < bindings.length; i += 2) { 13357 for (var i = 0; i < bindings.length; i += 2) {
15486 var name = bindings[i] 13358 var name = bindings[i]
15487 var tokens = bindings[i + 1]; 13359 var tokens = bindings[i + 1];
15488 var value = processBinding(name, tokens, node, model); 13360 var value = processBinding(name, tokens, node, model);
15489 var binding = node.bind(name, value, tokens.onlyOneTime); 13361 var binding = node.bind(name, value, tokens.onlyOneTime);
15490 if (binding && instanceBindings) 13362 if (binding && instanceBindings)
15491 instanceBindings.push(binding); 13363 instanceBindings.push(binding);
15492 } 13364 }
15493 13365
13366 node.bindFinished();
15494 if (!bindings.isTemplate) 13367 if (!bindings.isTemplate)
15495 return; 13368 return;
15496 13369
15497 node.model_ = model; 13370 node.model_ = model;
15498 var iter = node.processBindingDirectives_(bindings); 13371 var iter = node.processBindingDirectives_(bindings);
15499 if (instanceBindings && iter) 13372 if (instanceBindings && iter)
15500 instanceBindings.push(iter); 13373 instanceBindings.push(iter);
15501 } 13374 }
15502 13375
15503 function parseWithDefault(el, name, prepareBindingFn) { 13376 function parseWithDefault(el, name, prepareBindingFn) {
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
15595 var map = getBindings(node, prepareBindingFn); 13468 var map = getBindings(node, prepareBindingFn);
15596 map.children = {}; 13469 map.children = {};
15597 var index = 0; 13470 var index = 0;
15598 for (var child = node.firstChild; child; child = child.nextSibling) { 13471 for (var child = node.firstChild; child; child = child.nextSibling) {
15599 map.children[index++] = createInstanceBindingMap(child, prepareBindingFn); 13472 map.children[index++] = createInstanceBindingMap(child, prepareBindingFn);
15600 } 13473 }
15601 13474
15602 return map; 13475 return map;
15603 } 13476 }
15604 13477
13478 var contentUidCounter = 1;
13479
13480 // TODO(rafaelw): Setup a MutationObserver on content which clears the id
13481 // so that bindingMaps regenerate when the template.content changes.
13482 function getContentUid(content) {
13483 var id = content.id_;
13484 if (!id)
13485 id = content.id_ = contentUidCounter++;
13486 return id;
13487 }
13488
13489 // Each delegate is associated with a set of bindingMaps, one for each
13490 // content which may be used by a template. The intent is that each binding
13491 // delegate gets the opportunity to prepare the instance (via the prepare*
13492 // delegate calls) once across all uses.
13493 // TODO(rafaelw): Separate out the parse map from the binding map. In the
13494 // current implementation, if two delegates need a binding map for the same
13495 // content, the second will have to reparse.
13496 function getInstanceBindingMap(content, delegate_) {
13497 var contentId = getContentUid(content);
13498 if (delegate_) {
13499 var map = delegate_.bindingMaps[contentId];
13500 if (!map) {
13501 map = delegate_.bindingMaps[contentId] =
13502 createInstanceBindingMap(content, delegate_.prepareBinding) || [];
13503 }
13504 return map;
13505 }
13506
13507 var map = content.bindingMap_;
13508 if (!map) {
13509 map = content.bindingMap_ =
13510 createInstanceBindingMap(content, undefined) || [];
13511 }
13512 return map;
13513 }
13514
15605 Object.defineProperty(Node.prototype, 'templateInstance', { 13515 Object.defineProperty(Node.prototype, 'templateInstance', {
15606 get: function() { 13516 get: function() {
15607 var instance = this.templateInstance_; 13517 var instance = this.templateInstance_;
15608 return instance ? instance : 13518 return instance ? instance :
15609 (this.parentNode ? this.parentNode.templateInstance : undefined); 13519 (this.parentNode ? this.parentNode.templateInstance : undefined);
15610 } 13520 }
15611 }); 13521 });
15612 13522
15613 var emptyInstance = document.createDocumentFragment(); 13523 var emptyInstance = document.createDocumentFragment();
15614 emptyInstance.bindings_ = []; 13524 emptyInstance.bindings_ = [];
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after
15910 this.templateElement_.iterator_ = undefined; 13820 this.templateElement_.iterator_ = undefined;
15911 this.closed = true; 13821 this.closed = true;
15912 } 13822 }
15913 }; 13823 };
15914 13824
15915 // Polyfill-specific API. 13825 // Polyfill-specific API.
15916 HTMLTemplateElement.forAllTemplatesFrom_ = forAllTemplatesFrom; 13826 HTMLTemplateElement.forAllTemplatesFrom_ = forAllTemplatesFrom;
15917 })(this); 13827 })(this);
15918 13828
15919 /* 13829 /*
15920 Copyright (C) 2013 Ariya Hidayat <ariya.hidayat@gmail.com> 13830 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
15921 Copyright (C) 2013 Thaddee Tyl <thaddee.tyl@gmail.com> 13831 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
15922 Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com> 13832 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
15923 Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be> 13833 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
15924 Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl> 13834 * Code distributed by Google as part of the polymer project is also
15925 Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com> 13835 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
15926 Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com> 13836 */
15927 Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com>
15928 Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
15929 13837
15930 Redistribution and use in source and binary forms, with or without
15931 modification, are permitted provided that the following conditions are met:
15932
15933 * Redistributions of source code must retain the above copyright
15934 notice, this list of conditions and the following disclaimer.
15935 * Redistributions in binary form must reproduce the above copyright
15936 notice, this list of conditions and the following disclaimer in the
15937 documentation and/or other materials provided with the distribution.
15938
15939 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15940 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15941 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15942 ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
15943 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
15944 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
15945 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
15946 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
15947 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
15948 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15949 */
15950
15951 (function (global) {
15952 'use strict';
15953
15954 var Token,
15955 TokenName,
15956 Syntax,
15957 Messages,
15958 source,
15959 index,
15960 length,
15961 delegate,
15962 lookahead,
15963 state;
15964
15965 Token = {
15966 BooleanLiteral: 1,
15967 EOF: 2,
15968 Identifier: 3,
15969 Keyword: 4,
15970 NullLiteral: 5,
15971 NumericLiteral: 6,
15972 Punctuator: 7,
15973 StringLiteral: 8
15974 };
15975
15976 TokenName = {};
15977 TokenName[Token.BooleanLiteral] = 'Boolean';
15978 TokenName[Token.EOF] = '<end>';
15979 TokenName[Token.Identifier] = 'Identifier';
15980 TokenName[Token.Keyword] = 'Keyword';
15981 TokenName[Token.NullLiteral] = 'Null';
15982 TokenName[Token.NumericLiteral] = 'Numeric';
15983 TokenName[Token.Punctuator] = 'Punctuator';
15984 TokenName[Token.StringLiteral] = 'String';
15985
15986 Syntax = {
15987 ArrayExpression: 'ArrayExpression',
15988 BinaryExpression: 'BinaryExpression',
15989 CallExpression: 'CallExpression',
15990 ConditionalExpression: 'ConditionalExpression',
15991 EmptyStatement: 'EmptyStatement',
15992 ExpressionStatement: 'ExpressionStatement',
15993 Identifier: 'Identifier',
15994 Literal: 'Literal',
15995 LabeledStatement: 'LabeledStatement',
15996 LogicalExpression: 'LogicalExpression',
15997 MemberExpression: 'MemberExpression',
15998 ObjectExpression: 'ObjectExpression',
15999 Program: 'Program',
16000 Property: 'Property',
16001 ThisExpression: 'ThisExpression',
16002 UnaryExpression: 'UnaryExpression'
16003 };
16004
16005 // Error messages should be identical to V8.
16006 Messages = {
16007 UnexpectedToken: 'Unexpected token %0',
16008 UnknownLabel: 'Undefined label \'%0\'',
16009 Redeclaration: '%0 \'%1\' has already been declared'
16010 };
16011
16012 // Ensure the condition is true, otherwise throw an error.
16013 // This is only to have a better contract semantic, i.e. another safety net
16014 // to catch a logic error. The condition shall be fulfilled in normal case.
16015 // Do NOT use this to enforce a certain condition on any user input.
16016
16017 function assert(condition, message) {
16018 if (!condition) {
16019 throw new Error('ASSERT: ' + message);
16020 }
16021 }
16022
16023 function isDecimalDigit(ch) {
16024 return (ch >= 48 && ch <= 57); // 0..9
16025 }
16026
16027
16028 // 7.2 White Space
16029
16030 function isWhiteSpace(ch) {
16031 return (ch === 32) || // space
16032 (ch === 9) || // tab
16033 (ch === 0xB) ||
16034 (ch === 0xC) ||
16035 (ch === 0xA0) ||
16036 (ch >= 0x1680 && '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u 2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(String.fromCharCod e(ch)) > 0);
16037 }
16038
16039 // 7.3 Line Terminators
16040
16041 function isLineTerminator(ch) {
16042 return (ch === 10) || (ch === 13) || (ch === 0x2028) || (ch === 0x2029);
16043 }
16044
16045 // 7.6 Identifier Names and Identifiers
16046
16047 function isIdentifierStart(ch) {
16048 return (ch === 36) || (ch === 95) || // $ (dollar) and _ (underscore)
16049 (ch >= 65 && ch <= 90) || // A..Z
16050 (ch >= 97 && ch <= 122); // a..z
16051 }
16052
16053 function isIdentifierPart(ch) {
16054 return (ch === 36) || (ch === 95) || // $ (dollar) and _ (underscore)
16055 (ch >= 65 && ch <= 90) || // A..Z
16056 (ch >= 97 && ch <= 122) || // a..z
16057 (ch >= 48 && ch <= 57); // 0..9
16058 }
16059
16060 // 7.6.1.1 Keywords
16061
16062 function isKeyword(id) {
16063 return (id === 'this')
16064 }
16065
16066 // 7.4 Comments
16067
16068 function skipWhitespace() {
16069 while (index < length && isWhiteSpace(source.charCodeAt(index))) {
16070 ++index;
16071 }
16072 }
16073
16074 function getIdentifier() {
16075 var start, ch;
16076
16077 start = index++;
16078 while (index < length) {
16079 ch = source.charCodeAt(index);
16080 if (isIdentifierPart(ch)) {
16081 ++index;
16082 } else {
16083 break;
16084 }
16085 }
16086
16087 return source.slice(start, index);
16088 }
16089
16090 function scanIdentifier() {
16091 var start, id, type;
16092
16093 start = index;
16094
16095 id = getIdentifier();
16096
16097 // There is no keyword or literal with only one character.
16098 // Thus, it must be an identifier.
16099 if (id.length === 1) {
16100 type = Token.Identifier;
16101 } else if (isKeyword(id)) {
16102 type = Token.Keyword;
16103 } else if (id === 'null') {
16104 type = Token.NullLiteral;
16105 } else if (id === 'true' || id === 'false') {
16106 type = Token.BooleanLiteral;
16107 } else {
16108 type = Token.Identifier;
16109 }
16110
16111 return {
16112 type: type,
16113 value: id,
16114 range: [start, index]
16115 };
16116 }
16117
16118
16119 // 7.7 Punctuators
16120
16121 function scanPunctuator() {
16122 var start = index,
16123 code = source.charCodeAt(index),
16124 code2,
16125 ch1 = source[index],
16126 ch2;
16127
16128 switch (code) {
16129
16130 // Check for most common single-character punctuators.
16131 case 46: // . dot
16132 case 40: // ( open bracket
16133 case 41: // ) close bracket
16134 case 59: // ; semicolon
16135 case 44: // , comma
16136 case 123: // { open curly brace
16137 case 125: // } close curly brace
16138 case 91: // [
16139 case 93: // ]
16140 case 58: // :
16141 case 63: // ?
16142 ++index;
16143 return {
16144 type: Token.Punctuator,
16145 value: String.fromCharCode(code),
16146 range: [start, index]
16147 };
16148
16149 default:
16150 code2 = source.charCodeAt(index + 1);
16151
16152 // '=' (char #61) marks an assignment or comparison operator.
16153 if (code2 === 61) {
16154 switch (code) {
16155 case 37: // %
16156 case 38: // &
16157 case 42: // *:
16158 case 43: // +
16159 case 45: // -
16160 case 47: // /
16161 case 60: // <
16162 case 62: // >
16163 case 124: // |
16164 index += 2;
16165 return {
16166 type: Token.Punctuator,
16167 value: String.fromCharCode(code) + String.fromCharCode(c ode2),
16168 range: [start, index]
16169 };
16170
16171 case 33: // !
16172 case 61: // =
16173 index += 2;
16174
16175 // !== and ===
16176 if (source.charCodeAt(index) === 61) {
16177 ++index;
16178 }
16179 return {
16180 type: Token.Punctuator,
16181 value: source.slice(start, index),
16182 range: [start, index]
16183 };
16184 default:
16185 break;
16186 }
16187 }
16188 break;
16189 }
16190
16191 // Peek more characters.
16192
16193 ch2 = source[index + 1];
16194
16195 // Other 2-character punctuators: && ||
16196
16197 if (ch1 === ch2 && ('&|'.indexOf(ch1) >= 0)) {
16198 index += 2;
16199 return {
16200 type: Token.Punctuator,
16201 value: ch1 + ch2,
16202 range: [start, index]
16203 };
16204 }
16205
16206 if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) {
16207 ++index;
16208 return {
16209 type: Token.Punctuator,
16210 value: ch1,
16211 range: [start, index]
16212 };
16213 }
16214
16215 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
16216 }
16217
16218 // 7.8.3 Numeric Literals
16219 function scanNumericLiteral() {
16220 var number, start, ch;
16221
16222 ch = source[index];
16223 assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'),
16224 'Numeric literal must start with a decimal digit or a decimal point' );
16225
16226 start = index;
16227 number = '';
16228 if (ch !== '.') {
16229 number = source[index++];
16230 ch = source[index];
16231
16232 // Hex number starts with '0x'.
16233 // Octal number starts with '0'.
16234 if (number === '0') {
16235 // decimal number starts with '0' such as '09' is illegal.
16236 if (ch && isDecimalDigit(ch.charCodeAt(0))) {
16237 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
16238 }
16239 }
16240
16241 while (isDecimalDigit(source.charCodeAt(index))) {
16242 number += source[index++];
16243 }
16244 ch = source[index];
16245 }
16246
16247 if (ch === '.') {
16248 number += source[index++];
16249 while (isDecimalDigit(source.charCodeAt(index))) {
16250 number += source[index++];
16251 }
16252 ch = source[index];
16253 }
16254
16255 if (ch === 'e' || ch === 'E') {
16256 number += source[index++];
16257
16258 ch = source[index];
16259 if (ch === '+' || ch === '-') {
16260 number += source[index++];
16261 }
16262 if (isDecimalDigit(source.charCodeAt(index))) {
16263 while (isDecimalDigit(source.charCodeAt(index))) {
16264 number += source[index++];
16265 }
16266 } else {
16267 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
16268 }
16269 }
16270
16271 if (isIdentifierStart(source.charCodeAt(index))) {
16272 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
16273 }
16274
16275 return {
16276 type: Token.NumericLiteral,
16277 value: parseFloat(number),
16278 range: [start, index]
16279 };
16280 }
16281
16282 // 7.8.4 String Literals
16283
16284 function scanStringLiteral() {
16285 var str = '', quote, start, ch, octal = false;
16286
16287 quote = source[index];
16288 assert((quote === '\'' || quote === '"'),
16289 'String literal must starts with a quote');
16290
16291 start = index;
16292 ++index;
16293
16294 while (index < length) {
16295 ch = source[index++];
16296
16297 if (ch === quote) {
16298 quote = '';
16299 break;
16300 } else if (ch === '\\') {
16301 ch = source[index++];
16302 if (!ch || !isLineTerminator(ch.charCodeAt(0))) {
16303 switch (ch) {
16304 case 'n':
16305 str += '\n';
16306 break;
16307 case 'r':
16308 str += '\r';
16309 break;
16310 case 't':
16311 str += '\t';
16312 break;
16313 case 'b':
16314 str += '\b';
16315 break;
16316 case 'f':
16317 str += '\f';
16318 break;
16319 case 'v':
16320 str += '\x0B';
16321 break;
16322
16323 default:
16324 str += ch;
16325 break;
16326 }
16327 } else {
16328 if (ch === '\r' && source[index] === '\n') {
16329 ++index;
16330 }
16331 }
16332 } else if (isLineTerminator(ch.charCodeAt(0))) {
16333 break;
16334 } else {
16335 str += ch;
16336 }
16337 }
16338
16339 if (quote !== '') {
16340 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
16341 }
16342
16343 return {
16344 type: Token.StringLiteral,
16345 value: str,
16346 octal: octal,
16347 range: [start, index]
16348 };
16349 }
16350
16351 function isIdentifierName(token) {
16352 return token.type === Token.Identifier ||
16353 token.type === Token.Keyword ||
16354 token.type === Token.BooleanLiteral ||
16355 token.type === Token.NullLiteral;
16356 }
16357
16358 function advance() {
16359 var ch;
16360
16361 skipWhitespace();
16362
16363 if (index >= length) {
16364 return {
16365 type: Token.EOF,
16366 range: [index, index]
16367 };
16368 }
16369
16370 ch = source.charCodeAt(index);
16371
16372 // Very common: ( and ) and ;
16373 if (ch === 40 || ch === 41 || ch === 58) {
16374 return scanPunctuator();
16375 }
16376
16377 // String literal starts with single quote (#39) or double quote (#34).
16378 if (ch === 39 || ch === 34) {
16379 return scanStringLiteral();
16380 }
16381
16382 if (isIdentifierStart(ch)) {
16383 return scanIdentifier();
16384 }
16385
16386 // Dot (.) char #46 can also start a floating-point number, hence the ne ed
16387 // to check the next character.
16388 if (ch === 46) {
16389 if (isDecimalDigit(source.charCodeAt(index + 1))) {
16390 return scanNumericLiteral();
16391 }
16392 return scanPunctuator();
16393 }
16394
16395 if (isDecimalDigit(ch)) {
16396 return scanNumericLiteral();
16397 }
16398
16399 return scanPunctuator();
16400 }
16401
16402 function lex() {
16403 var token;
16404
16405 token = lookahead;
16406 index = token.range[1];
16407
16408 lookahead = advance();
16409
16410 index = token.range[1];
16411
16412 return token;
16413 }
16414
16415 function peek() {
16416 var pos;
16417
16418 pos = index;
16419 lookahead = advance();
16420 index = pos;
16421 }
16422
16423 // Throw an exception
16424
16425 function throwError(token, messageFormat) {
16426 var error,
16427 args = Array.prototype.slice.call(arguments, 2),
16428 msg = messageFormat.replace(
16429 /%(\d)/g,
16430 function (whole, index) {
16431 assert(index < args.length, 'Message reference must be in ra nge');
16432 return args[index];
16433 }
16434 );
16435
16436 error = new Error(msg);
16437 error.index = index;
16438 error.description = msg;
16439 throw error;
16440 }
16441
16442 // Throw an exception because of the token.
16443
16444 function throwUnexpected(token) {
16445 throwError(token, Messages.UnexpectedToken, token.value);
16446 }
16447
16448 // Expect the next token to match the specified punctuator.
16449 // If not, an exception will be thrown.
16450
16451 function expect(value) {
16452 var token = lex();
16453 if (token.type !== Token.Punctuator || token.value !== value) {
16454 throwUnexpected(token);
16455 }
16456 }
16457
16458 // Return true if the next token matches the specified punctuator.
16459
16460 function match(value) {
16461 return lookahead.type === Token.Punctuator && lookahead.value === value;
16462 }
16463
16464 // Return true if the next token matches the specified keyword
16465
16466 function matchKeyword(keyword) {
16467 return lookahead.type === Token.Keyword && lookahead.value === keyword;
16468 }
16469
16470 function consumeSemicolon() {
16471 // Catch the very common case first: immediately a semicolon (char #59).
16472 if (source.charCodeAt(index) === 59) {
16473 lex();
16474 return;
16475 }
16476
16477 skipWhitespace();
16478
16479 if (match(';')) {
16480 lex();
16481 return;
16482 }
16483
16484 if (lookahead.type !== Token.EOF && !match('}')) {
16485 throwUnexpected(lookahead);
16486 }
16487 }
16488
16489 // 11.1.4 Array Initialiser
16490
16491 function parseArrayInitialiser() {
16492 var elements = [];
16493
16494 expect('[');
16495
16496 while (!match(']')) {
16497 if (match(',')) {
16498 lex();
16499 elements.push(null);
16500 } else {
16501 elements.push(parseExpression());
16502
16503 if (!match(']')) {
16504 expect(',');
16505 }
16506 }
16507 }
16508
16509 expect(']');
16510
16511 return delegate.createArrayExpression(elements);
16512 }
16513
16514 // 11.1.5 Object Initialiser
16515
16516 function parseObjectPropertyKey() {
16517 var token;
16518
16519 skipWhitespace();
16520 token = lex();
16521
16522 // Note: This function is called only from parseObjectProperty(), where
16523 // EOF and Punctuator tokens are already filtered out.
16524 if (token.type === Token.StringLiteral || token.type === Token.NumericLi teral) {
16525 return delegate.createLiteral(token);
16526 }
16527
16528 return delegate.createIdentifier(token.value);
16529 }
16530
16531 function parseObjectProperty() {
16532 var token, key;
16533
16534 token = lookahead;
16535 skipWhitespace();
16536
16537 if (token.type === Token.EOF || token.type === Token.Punctuator) {
16538 throwUnexpected(token);
16539 }
16540
16541 key = parseObjectPropertyKey();
16542 expect(':');
16543 return delegate.createProperty('init', key, parseExpression());
16544 }
16545
16546 function parseObjectInitialiser() {
16547 var properties = [];
16548
16549 expect('{');
16550
16551 while (!match('}')) {
16552 properties.push(parseObjectProperty());
16553
16554 if (!match('}')) {
16555 expect(',');
16556 }
16557 }
16558
16559 expect('}');
16560
16561 return delegate.createObjectExpression(properties);
16562 }
16563
16564 // 11.1.6 The Grouping Operator
16565
16566 function parseGroupExpression() {
16567 var expr;
16568
16569 expect('(');
16570
16571 expr = parseExpression();
16572
16573 expect(')');
16574
16575 return expr;
16576 }
16577
16578
16579 // 11.1 Primary Expressions
16580
16581 function parsePrimaryExpression() {
16582 var type, token, expr;
16583
16584 if (match('(')) {
16585 return parseGroupExpression();
16586 }
16587
16588 type = lookahead.type;
16589
16590 if (type === Token.Identifier) {
16591 expr = delegate.createIdentifier(lex().value);
16592 } else if (type === Token.StringLiteral || type === Token.NumericLiteral ) {
16593 expr = delegate.createLiteral(lex());
16594 } else if (type === Token.Keyword) {
16595 if (matchKeyword('this')) {
16596 lex();
16597 expr = delegate.createThisExpression();
16598 }
16599 } else if (type === Token.BooleanLiteral) {
16600 token = lex();
16601 token.value = (token.value === 'true');
16602 expr = delegate.createLiteral(token);
16603 } else if (type === Token.NullLiteral) {
16604 token = lex();
16605 token.value = null;
16606 expr = delegate.createLiteral(token);
16607 } else if (match('[')) {
16608 expr = parseArrayInitialiser();
16609 } else if (match('{')) {
16610 expr = parseObjectInitialiser();
16611 }
16612
16613 if (expr) {
16614 return expr;
16615 }
16616
16617 throwUnexpected(lex());
16618 }
16619
16620 // 11.2 Left-Hand-Side Expressions
16621
16622 function parseArguments() {
16623 var args = [];
16624
16625 expect('(');
16626
16627 if (!match(')')) {
16628 while (index < length) {
16629 args.push(parseExpression());
16630 if (match(')')) {
16631 break;
16632 }
16633 expect(',');
16634 }
16635 }
16636
16637 expect(')');
16638
16639 return args;
16640 }
16641
16642 function parseNonComputedProperty() {
16643 var token;
16644
16645 token = lex();
16646
16647 if (!isIdentifierName(token)) {
16648 throwUnexpected(token);
16649 }
16650
16651 return delegate.createIdentifier(token.value);
16652 }
16653
16654 function parseNonComputedMember() {
16655 expect('.');
16656
16657 return parseNonComputedProperty();
16658 }
16659
16660 function parseComputedMember() {
16661 var expr;
16662
16663 expect('[');
16664
16665 expr = parseExpression();
16666
16667 expect(']');
16668
16669 return expr;
16670 }
16671
16672 function parseLeftHandSideExpression() {
16673 var expr, property;
16674
16675 expr = parsePrimaryExpression();
16676
16677 while (match('.') || match('[')) {
16678 if (match('[')) {
16679 property = parseComputedMember();
16680 expr = delegate.createMemberExpression('[', expr, property);
16681 } else {
16682 property = parseNonComputedMember();
16683 expr = delegate.createMemberExpression('.', expr, property);
16684 }
16685 }
16686
16687 return expr;
16688 }
16689
16690 // 11.3 Postfix Expressions
16691
16692 var parsePostfixExpression = parseLeftHandSideExpression;
16693
16694 // 11.4 Unary Operators
16695
16696 function parseUnaryExpression() {
16697 var token, expr;
16698
16699 if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyw ord) {
16700 expr = parsePostfixExpression();
16701 } else if (match('+') || match('-') || match('!')) {
16702 token = lex();
16703 expr = parseUnaryExpression();
16704 expr = delegate.createUnaryExpression(token.value, expr);
16705 } else if (matchKeyword('delete') || matchKeyword('void') || matchKeywor d('typeof')) {
16706 throwError({}, Messages.UnexpectedToken);
16707 } else {
16708 expr = parsePostfixExpression();
16709 }
16710
16711 return expr;
16712 }
16713
16714 function binaryPrecedence(token) {
16715 var prec = 0;
16716
16717 if (token.type !== Token.Punctuator && token.type !== Token.Keyword) {
16718 return 0;
16719 }
16720
16721 switch (token.value) {
16722 case '||':
16723 prec = 1;
16724 break;
16725
16726 case '&&':
16727 prec = 2;
16728 break;
16729
16730 case '==':
16731 case '!=':
16732 case '===':
16733 case '!==':
16734 prec = 6;
16735 break;
16736
16737 case '<':
16738 case '>':
16739 case '<=':
16740 case '>=':
16741 case 'instanceof':
16742 prec = 7;
16743 break;
16744
16745 case 'in':
16746 prec = 7;
16747 break;
16748
16749 case '+':
16750 case '-':
16751 prec = 9;
16752 break;
16753
16754 case '*':
16755 case '/':
16756 case '%':
16757 prec = 11;
16758 break;
16759
16760 default:
16761 break;
16762 }
16763
16764 return prec;
16765 }
16766
16767 // 11.5 Multiplicative Operators
16768 // 11.6 Additive Operators
16769 // 11.7 Bitwise Shift Operators
16770 // 11.8 Relational Operators
16771 // 11.9 Equality Operators
16772 // 11.10 Binary Bitwise Operators
16773 // 11.11 Binary Logical Operators
16774
16775 function parseBinaryExpression() {
16776 var expr, token, prec, stack, right, operator, left, i;
16777
16778 left = parseUnaryExpression();
16779
16780 token = lookahead;
16781 prec = binaryPrecedence(token);
16782 if (prec === 0) {
16783 return left;
16784 }
16785 token.prec = prec;
16786 lex();
16787
16788 right = parseUnaryExpression();
16789
16790 stack = [left, token, right];
16791
16792 while ((prec = binaryPrecedence(lookahead)) > 0) {
16793
16794 // Reduce: make a binary expression from the three topmost entries.
16795 while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) {
16796 right = stack.pop();
16797 operator = stack.pop().value;
16798 left = stack.pop();
16799 expr = delegate.createBinaryExpression(operator, left, right);
16800 stack.push(expr);
16801 }
16802
16803 // Shift.
16804 token = lex();
16805 token.prec = prec;
16806 stack.push(token);
16807 expr = parseUnaryExpression();
16808 stack.push(expr);
16809 }
16810
16811 // Final reduce to clean-up the stack.
16812 i = stack.length - 1;
16813 expr = stack[i];
16814 while (i > 1) {
16815 expr = delegate.createBinaryExpression(stack[i - 1].value, stack[i - 2], expr);
16816 i -= 2;
16817 }
16818
16819 return expr;
16820 }
16821
16822
16823 // 11.12 Conditional Operator
16824
16825 function parseConditionalExpression() {
16826 var expr, consequent, alternate;
16827
16828 expr = parseBinaryExpression();
16829
16830 if (match('?')) {
16831 lex();
16832 consequent = parseConditionalExpression();
16833 expect(':');
16834 alternate = parseConditionalExpression();
16835
16836 expr = delegate.createConditionalExpression(expr, consequent, altern ate);
16837 }
16838
16839 return expr;
16840 }
16841
16842 // Simplification since we do not support AssignmentExpression.
16843 var parseExpression = parseConditionalExpression;
16844
16845 // Polymer Syntax extensions
16846
16847 // Filter ::
16848 // Identifier
16849 // Identifier "(" ")"
16850 // Identifier "(" FilterArguments ")"
16851
16852 function parseFilter() {
16853 var identifier, args;
16854
16855 identifier = lex();
16856
16857 if (identifier.type !== Token.Identifier) {
16858 throwUnexpected(identifier);
16859 }
16860
16861 args = match('(') ? parseArguments() : [];
16862
16863 return delegate.createFilter(identifier.value, args);
16864 }
16865
16866 // Filters ::
16867 // "|" Filter
16868 // Filters "|" Filter
16869
16870 function parseFilters() {
16871 while (match('|')) {
16872 lex();
16873 parseFilter();
16874 }
16875 }
16876
16877 // TopLevel ::
16878 // LabelledExpressions
16879 // AsExpression
16880 // InExpression
16881 // FilterExpression
16882
16883 // AsExpression ::
16884 // FilterExpression as Identifier
16885
16886 // InExpression ::
16887 // Identifier, Identifier in FilterExpression
16888 // Identifier in FilterExpression
16889
16890 // FilterExpression ::
16891 // Expression
16892 // Expression Filters
16893
16894 function parseTopLevel() {
16895 skipWhitespace();
16896 peek();
16897
16898 var expr = parseExpression();
16899 if (expr) {
16900 if (lookahead.value === ',' || lookahead.value == 'in' &&
16901 expr.type === Syntax.Identifier) {
16902 parseInExpression(expr);
16903 } else {
16904 parseFilters();
16905 if (lookahead.value === 'as') {
16906 parseAsExpression(expr);
16907 } else {
16908 delegate.createTopLevel(expr);
16909 }
16910 }
16911 }
16912
16913 if (lookahead.type !== Token.EOF) {
16914 throwUnexpected(lookahead);
16915 }
16916 }
16917
16918 function parseAsExpression(expr) {
16919 lex(); // as
16920 var identifier = lex().value;
16921 delegate.createAsExpression(expr, identifier);
16922 }
16923
16924 function parseInExpression(identifier) {
16925 var indexName;
16926 if (lookahead.value === ',') {
16927 lex();
16928 if (lookahead.type !== Token.Identifier)
16929 throwUnexpected(lookahead);
16930 indexName = lex().value;
16931 }
16932
16933 lex(); // in
16934 var expr = parseExpression();
16935 parseFilters();
16936 delegate.createInExpression(identifier.name, indexName, expr);
16937 }
16938
16939 function parse(code, inDelegate) {
16940 delegate = inDelegate;
16941 source = code;
16942 index = 0;
16943 length = source.length;
16944 lookahead = null;
16945 state = {
16946 labelSet: {}
16947 };
16948
16949 return parseTopLevel();
16950 }
16951
16952 global.esprima = {
16953 parse: parse
16954 };
16955 })(this);
16956
16957 // Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
16958 // This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
16959 // The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
16960 // The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
16961 // Code distributed by Google as part of the polymer project is also
16962 // subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
16963
16964 (function (global) {
16965 'use strict';
16966
16967 // JScript does not have __proto__. We wrap all object literals with
16968 // createObject which uses Object.create, Object.defineProperty and
16969 // Object.getOwnPropertyDescriptor to create a new object that does the exact
16970 // same thing. The main downside to this solution is that we have to extract
16971 // all those property descriptors for IE.
16972 var createObject = ('__proto__' in {}) ?
16973 function(obj) { return obj; } :
16974 function(obj) {
16975 var proto = obj.__proto__;
16976 if (!proto)
16977 return obj;
16978 var newObject = Object.create(proto);
16979 Object.getOwnPropertyNames(obj).forEach(function(name) {
16980 Object.defineProperty(newObject, name,
16981 Object.getOwnPropertyDescriptor(obj, name));
16982 });
16983 return newObject;
16984 };
16985
16986 function prepareBinding(expressionText, name, node, filterRegistry) {
16987 var expression;
16988 try {
16989 expression = getExpression(expressionText);
16990 if (expression.scopeIdent &&
16991 (node.nodeType !== Node.ELEMENT_NODE ||
16992 node.tagName !== 'TEMPLATE' ||
16993 (name !== 'bind' && name !== 'repeat'))) {
16994 throw Error('as and in can only be used within <template bind/repeat>');
16995 }
16996 } catch (ex) {
16997 console.error('Invalid expression syntax: ' + expressionText, ex);
16998 return;
16999 }
17000
17001 return function(model, node, oneTime) {
17002 var binding = expression.getBinding(model, filterRegistry, oneTime);
17003 if (expression.scopeIdent && binding) {
17004 node.polymerExpressionScopeIdent_ = expression.scopeIdent;
17005 if (expression.indexIdent)
17006 node.polymerExpressionIndexIdent_ = expression.indexIdent;
17007 }
17008
17009 return binding;
17010 }
17011 }
17012
17013 // TODO(rafaelw): Implement simple LRU.
17014 var expressionParseCache = Object.create(null);
17015
17016 function getExpression(expressionText) {
17017 var expression = expressionParseCache[expressionText];
17018 if (!expression) {
17019 var delegate = new ASTDelegate();
17020 esprima.parse(expressionText, delegate);
17021 expression = new Expression(delegate);
17022 expressionParseCache[expressionText] = expression;
17023 }
17024 return expression;
17025 }
17026
17027 function Literal(value) {
17028 this.value = value;
17029 this.valueFn_ = undefined;
17030 }
17031
17032 Literal.prototype = {
17033 valueFn: function() {
17034 if (!this.valueFn_) {
17035 var value = this.value;
17036 this.valueFn_ = function() {
17037 return value;
17038 }
17039 }
17040
17041 return this.valueFn_;
17042 }
17043 }
17044
17045 function IdentPath(name) {
17046 this.name = name;
17047 this.path = Path.get(name);
17048 }
17049
17050 IdentPath.prototype = {
17051 valueFn: function() {
17052 if (!this.valueFn_) {
17053 var name = this.name;
17054 var path = this.path;
17055 this.valueFn_ = function(model, observer) {
17056 if (observer)
17057 observer.addPath(model, path);
17058
17059 return path.getValueFrom(model);
17060 }
17061 }
17062
17063 return this.valueFn_;
17064 },
17065
17066 setValue: function(model, newValue) {
17067 if (this.path.length == 1);
17068 model = findScope(model, this.path[0]);
17069
17070 return this.path.setValueFrom(model, newValue);
17071 }
17072 };
17073
17074 function MemberExpression(object, property, accessor) {
17075 // convert literal computed property access where literal value is a value
17076 // path to ident dot-access.
17077 if (accessor == '[' &&
17078 property instanceof Literal &&
17079 Path.get(property.value).valid) {
17080 accessor = '.';
17081 property = new IdentPath(property.value);
17082 }
17083
17084 this.dynamicDeps = typeof object == 'function' || object.dynamic;
17085
17086 this.dynamic = typeof property == 'function' ||
17087 property.dynamic ||
17088 accessor == '[';
17089
17090 this.simplePath =
17091 !this.dynamic &&
17092 !this.dynamicDeps &&
17093 property instanceof IdentPath &&
17094 (object instanceof MemberExpression || object instanceof IdentPath);
17095
17096 this.object = this.simplePath ? object : getFn(object);
17097 this.property = accessor == '.' ? property : getFn(property);
17098 }
17099
17100 MemberExpression.prototype = {
17101 get fullPath() {
17102 if (!this.fullPath_) {
17103 var last = this.object instanceof IdentPath ?
17104 this.object.name : this.object.fullPath;
17105 this.fullPath_ = Path.get(last + '.' + this.property.name);
17106 }
17107
17108 return this.fullPath_;
17109 },
17110
17111 valueFn: function() {
17112 if (!this.valueFn_) {
17113 var object = this.object;
17114
17115 if (this.simplePath) {
17116 var path = this.fullPath;
17117
17118 this.valueFn_ = function(model, observer) {
17119 if (observer)
17120 observer.addPath(model, path);
17121
17122 return path.getValueFrom(model);
17123 };
17124 } else if (this.property instanceof IdentPath) {
17125 var path = Path.get(this.property.name);
17126
17127 this.valueFn_ = function(model, observer) {
17128 var context = object(model, observer);
17129
17130 if (observer)
17131 observer.addPath(context, path);
17132
17133 return path.getValueFrom(context);
17134 }
17135 } else {
17136 // Computed property.
17137 var property = this.property;
17138
17139 this.valueFn_ = function(model, observer) {
17140 var context = object(model, observer);
17141 var propName = property(model, observer);
17142 if (observer)
17143 observer.addPath(context, propName);
17144
17145 return context ? context[propName] : undefined;
17146 };
17147 }
17148 }
17149 return this.valueFn_;
17150 },
17151
17152 setValue: function(model, newValue) {
17153 if (this.simplePath) {
17154 this.fullPath.setValueFrom(model, newValue);
17155 return newValue;
17156 }
17157
17158 var object = this.object(model);
17159 var propName = this.property instanceof IdentPath ? this.property.name :
17160 this.property(model);
17161 return object[propName] = newValue;
17162 }
17163 };
17164
17165 function Filter(name, args) {
17166 this.name = name;
17167 this.args = [];
17168 for (var i = 0; i < args.length; i++) {
17169 this.args[i] = getFn(args[i]);
17170 }
17171 }
17172
17173 Filter.prototype = {
17174 transform: function(value, toModelDirection, filterRegistry, model,
17175 observer) {
17176 var fn = filterRegistry[this.name];
17177 var context = model;
17178 if (fn) {
17179 context = undefined;
17180 } else {
17181 fn = context[this.name];
17182 if (!fn) {
17183 console.error('Cannot find filter: ' + this.name);
17184 return;
17185 }
17186 }
17187
17188 // If toModelDirection is falsey, then the "normal" (dom-bound) direction
17189 // is used. Otherwise, it looks for a 'toModel' property function on the
17190 // object.
17191 if (toModelDirection) {
17192 fn = fn.toModel;
17193 } else if (typeof fn.toDOM == 'function') {
17194 fn = fn.toDOM;
17195 }
17196
17197 if (typeof fn != 'function') {
17198 console.error('No ' + (toModelDirection ? 'toModel' : 'toDOM') +
17199 ' found on' + this.name);
17200 return;
17201 }
17202
17203 var args = [value];
17204 for (var i = 0; i < this.args.length; i++) {
17205 args[i + 1] = getFn(this.args[i])(model, observer);
17206 }
17207
17208 return fn.apply(context, args);
17209 }
17210 };
17211
17212 function notImplemented() { throw Error('Not Implemented'); }
17213
17214 var unaryOperators = {
17215 '+': function(v) { return +v; },
17216 '-': function(v) { return -v; },
17217 '!': function(v) { return !v; }
17218 };
17219
17220 var binaryOperators = {
17221 '+': function(l, r) { return l+r; },
17222 '-': function(l, r) { return l-r; },
17223 '*': function(l, r) { return l*r; },
17224 '/': function(l, r) { return l/r; },
17225 '%': function(l, r) { return l%r; },
17226 '<': function(l, r) { return l<r; },
17227 '>': function(l, r) { return l>r; },
17228 '<=': function(l, r) { return l<=r; },
17229 '>=': function(l, r) { return l>=r; },
17230 '==': function(l, r) { return l==r; },
17231 '!=': function(l, r) { return l!=r; },
17232 '===': function(l, r) { return l===r; },
17233 '!==': function(l, r) { return l!==r; },
17234 '&&': function(l, r) { return l&&r; },
17235 '||': function(l, r) { return l||r; },
17236 };
17237
17238 function getFn(arg) {
17239 return typeof arg == 'function' ? arg : arg.valueFn();
17240 }
17241
17242 function ASTDelegate() {
17243 this.expression = null;
17244 this.filters = [];
17245 this.deps = {};
17246 this.currentPath = undefined;
17247 this.scopeIdent = undefined;
17248 this.indexIdent = undefined;
17249 this.dynamicDeps = false;
17250 }
17251
17252 ASTDelegate.prototype = {
17253 createUnaryExpression: function(op, argument) {
17254 if (!unaryOperators[op])
17255 throw Error('Disallowed operator: ' + op);
17256
17257 argument = getFn(argument);
17258
17259 return function(model, observer) {
17260 return unaryOperators[op](argument(model, observer));
17261 };
17262 },
17263
17264 createBinaryExpression: function(op, left, right) {
17265 if (!binaryOperators[op])
17266 throw Error('Disallowed operator: ' + op);
17267
17268 left = getFn(left);
17269 right = getFn(right);
17270
17271 return function(model, observer) {
17272 return binaryOperators[op](left(model, observer),
17273 right(model, observer));
17274 };
17275 },
17276
17277 createConditionalExpression: function(test, consequent, alternate) {
17278 test = getFn(test);
17279 consequent = getFn(consequent);
17280 alternate = getFn(alternate);
17281
17282 return function(model, observer) {
17283 return test(model, observer) ?
17284 consequent(model, observer) : alternate(model, observer);
17285 }
17286 },
17287
17288 createIdentifier: function(name) {
17289 var ident = new IdentPath(name);
17290 ident.type = 'Identifier';
17291 return ident;
17292 },
17293
17294 createMemberExpression: function(accessor, object, property) {
17295 var ex = new MemberExpression(object, property, accessor);
17296 if (ex.dynamicDeps)
17297 this.dynamicDeps = true;
17298 return ex;
17299 },
17300
17301 createLiteral: function(token) {
17302 return new Literal(token.value);
17303 },
17304
17305 createArrayExpression: function(elements) {
17306 for (var i = 0; i < elements.length; i++)
17307 elements[i] = getFn(elements[i]);
17308
17309 return function(model, observer) {
17310 var arr = []
17311 for (var i = 0; i < elements.length; i++)
17312 arr.push(elements[i](model, observer));
17313 return arr;
17314 }
17315 },
17316
17317 createProperty: function(kind, key, value) {
17318 return {
17319 key: key instanceof IdentPath ? key.name : key.value,
17320 value: value
17321 };
17322 },
17323
17324 createObjectExpression: function(properties) {
17325 for (var i = 0; i < properties.length; i++)
17326 properties[i].value = getFn(properties[i].value);
17327
17328 return function(model, observer) {
17329 var obj = {};
17330 for (var i = 0; i < properties.length; i++)
17331 obj[properties[i].key] = properties[i].value(model, observer);
17332 return obj;
17333 }
17334 },
17335
17336 createFilter: function(name, args) {
17337 this.filters.push(new Filter(name, args));
17338 },
17339
17340 createAsExpression: function(expression, scopeIdent) {
17341 this.expression = expression;
17342 this.scopeIdent = scopeIdent;
17343 },
17344
17345 createInExpression: function(scopeIdent, indexIdent, expression) {
17346 this.expression = expression;
17347 this.scopeIdent = scopeIdent;
17348 this.indexIdent = indexIdent;
17349 },
17350
17351 createTopLevel: function(expression) {
17352 this.expression = expression;
17353 },
17354
17355 createThisExpression: notImplemented
17356 }
17357
17358 function ConstantObservable(value) {
17359 this.value_ = value;
17360 }
17361
17362 ConstantObservable.prototype = {
17363 open: function() { return this.value_; },
17364 discardChanges: function() { return this.value_; },
17365 deliver: function() {},
17366 close: function() {},
17367 }
17368
17369 function Expression(delegate) {
17370 this.scopeIdent = delegate.scopeIdent;
17371 this.indexIdent = delegate.indexIdent;
17372
17373 if (!delegate.expression)
17374 throw Error('No expression found.');
17375
17376 this.expression = delegate.expression;
17377 getFn(this.expression); // forces enumeration of path dependencies
17378
17379 this.filters = delegate.filters;
17380 this.dynamicDeps = delegate.dynamicDeps;
17381 }
17382
17383 Expression.prototype = {
17384 getBinding: function(model, filterRegistry, oneTime) {
17385 if (oneTime)
17386 return this.getValue(model, undefined, filterRegistry);
17387
17388 var observer = new CompoundObserver();
17389 // captures deps.
17390 var firstValue = this.getValue(model, observer, filterRegistry);
17391 var firstTime = true;
17392 var self = this;
17393
17394 function valueFn() {
17395 // deps cannot have changed on first value retrieval.
17396 if (firstTime) {
17397 firstTime = false;
17398 return firstValue;
17399 }
17400
17401 if (self.dynamicDeps)
17402 observer.startReset();
17403
17404 var value = self.getValue(model,
17405 self.dynamicDeps ? observer : undefined,
17406 filterRegistry);
17407 if (self.dynamicDeps)
17408 observer.finishReset();
17409
17410 return value;
17411 }
17412
17413 function setValueFn(newValue) {
17414 self.setValue(model, newValue, filterRegistry);
17415 return newValue;
17416 }
17417
17418 return new ObserverTransform(observer, valueFn, setValueFn, true);
17419 },
17420
17421 getValue: function(model, observer, filterRegistry) {
17422 var value = getFn(this.expression)(model, observer);
17423 for (var i = 0; i < this.filters.length; i++) {
17424 value = this.filters[i].transform(value, false, filterRegistry, model,
17425 observer);
17426 }
17427
17428 return value;
17429 },
17430
17431 setValue: function(model, newValue, filterRegistry) {
17432 var count = this.filters ? this.filters.length : 0;
17433 while (count-- > 0) {
17434 newValue = this.filters[count].transform(newValue, true, filterRegistry,
17435 model);
17436 }
17437
17438 if (this.expression.setValue)
17439 return this.expression.setValue(model, newValue);
17440 }
17441 }
17442
17443 /**
17444 * Converts a style property name to a css property name. For example:
17445 * "WebkitUserSelect" to "-webkit-user-select"
17446 */
17447 function convertStylePropertyName(name) {
17448 return String(name).replace(/[A-Z]/g, function(c) {
17449 return '-' + c.toLowerCase();
17450 });
17451 }
17452
17453 function isEventHandler(name) {
17454 return name[0] === 'o' &&
17455 name[1] === 'n' &&
17456 name[2] === '-';
17457 }
17458
17459 var mixedCaseEventTypes = {};
17460 [
17461 'webkitAnimationStart',
17462 'webkitAnimationEnd',
17463 'webkitTransitionEnd',
17464 'DOMFocusOut',
17465 'DOMFocusIn',
17466 'DOMMouseScroll'
17467 ].forEach(function(e) {
17468 mixedCaseEventTypes[e.toLowerCase()] = e;
17469 });
17470
17471 var parentScopeName = '@' + Math.random().toString(36).slice(2);
17472
17473 // Single ident paths must bind directly to the appropriate scope object.
17474 // I.e. Pushed values in two-bindings need to be assigned to the actual model
17475 // object.
17476 function findScope(model, prop) {
17477 while (model[parentScopeName] &&
17478 !Object.prototype.hasOwnProperty.call(model, prop)) {
17479 model = model[parentScopeName];
17480 }
17481
17482 return model;
17483 }
17484
17485 function resolveEventReceiver(model, path, node) {
17486 if (path.length == 0)
17487 return undefined;
17488
17489 if (path.length == 1)
17490 return findScope(model, path[0]);
17491
17492 for (var i = 0; model != null && i < path.length - 1; i++) {
17493 model = model[path[i]];
17494 }
17495
17496 return model;
17497 }
17498
17499 function prepareEventBinding(path, name, polymerExpressions) {
17500 var eventType = name.substring(3);
17501 eventType = mixedCaseEventTypes[eventType] || eventType;
17502
17503 return function(model, node, oneTime) {
17504 var fn, receiver, handler;
17505 if (typeof polymerExpressions.resolveEventHandler == 'function') {
17506 handler = function(e) {
17507 fn = fn || polymerExpressions.resolveEventHandler(model, path, node);
17508 fn(e, e.detail, e.currentTarget);
17509
17510 if (Platform && typeof Platform.flush == 'function')
17511 Platform.flush();
17512 };
17513 } else {
17514 handler = function(e) {
17515 fn = fn || path.getValueFrom(model);
17516 receiver = receiver || resolveEventReceiver(model, path, node);
17517
17518 fn.apply(receiver, [e, e.detail, e.currentTarget]);
17519
17520 if (Platform && typeof Platform.flush == 'function')
17521 Platform.flush();
17522 };
17523 }
17524
17525 node.addEventListener(eventType, handler);
17526
17527 if (oneTime)
17528 return;
17529
17530 function bindingValue() {
17531 return '{{ ' + path + ' }}';
17532 }
17533
17534 return {
17535 open: bindingValue,
17536 discardChanges: bindingValue,
17537 close: function() {
17538 node.removeEventListener(eventType, handler);
17539 }
17540 };
17541 }
17542 }
17543
17544 function isLiteralExpression(pathString) {
17545 switch (pathString) {
17546 case '':
17547 return false;
17548
17549 case 'false':
17550 case 'null':
17551 case 'true':
17552 return true;
17553 }
17554
17555 if (!isNaN(Number(pathString)))
17556 return true;
17557
17558 return false;
17559 };
17560
17561 function PolymerExpressions() {}
17562
17563 PolymerExpressions.prototype = {
17564 // "built-in" filters
17565 styleObject: function(value) {
17566 var parts = [];
17567 for (var key in value) {
17568 parts.push(convertStylePropertyName(key) + ': ' + value[key]);
17569 }
17570 return parts.join('; ');
17571 },
17572
17573 tokenList: function(value) {
17574 var tokens = [];
17575 for (var key in value) {
17576 if (value[key])
17577 tokens.push(key);
17578 }
17579 return tokens.join(' ');
17580 },
17581
17582 // binding delegate API
17583 prepareInstancePositionChanged: function(template) {
17584 var indexIdent = template.polymerExpressionIndexIdent_;
17585 if (!indexIdent)
17586 return;
17587
17588 return function(templateInstance, index) {
17589 templateInstance.model[indexIdent] = index;
17590 };
17591 },
17592
17593 prepareBinding: function(pathString, name, node) {
17594 var path = Path.get(pathString);
17595 if (isEventHandler(name)) {
17596 if (!path.valid) {
17597 console.error('on-* bindings must be simple path expressions');
17598 return;
17599 }
17600
17601 return prepareEventBinding(path, name, this);
17602 }
17603
17604 if (!isLiteralExpression(pathString) && path.valid) {
17605 if (path.length == 1) {
17606 return function(model, node, oneTime) {
17607 if (oneTime)
17608 return path.getValueFrom(model);
17609
17610 var scope = findScope(model, path[0]);
17611 return new PathObserver(scope, path);
17612 };
17613 }
17614 return; // bail out early if pathString is simple path.
17615 }
17616
17617 return prepareBinding(pathString, name, node, this);
17618 },
17619
17620 prepareInstanceModel: function(template) {
17621 var scopeName = template.polymerExpressionScopeIdent_;
17622 if (!scopeName)
17623 return;
17624
17625 var parentScope = template.templateInstance ?
17626 template.templateInstance.model :
17627 template.model;
17628
17629 var indexName = template.polymerExpressionIndexIdent_;
17630
17631 return function(model) {
17632 var scope = Object.create(parentScope);
17633 scope[scopeName] = model;
17634 scope[indexName] = undefined;
17635 scope[parentScopeName] = parentScope;
17636 return scope;
17637 };
17638 }
17639 };
17640
17641 global.PolymerExpressions = PolymerExpressions;
17642 if (global.exposeGetExpression)
17643 global.getExpression_ = getExpression;
17644
17645 global.PolymerExpressions.prepareEventBinding = prepareEventBinding;
17646 })(this);
17647
17648 /*
17649 * Copyright 2013 The Polymer Authors. All rights reserved.
17650 * Use of this source code is governed by a BSD-style
17651 * license that can be found in the LICENSE file.
17652 */
17653 (function(scope) { 13838 (function(scope) {
17654 13839
17655 // inject style sheet 13840 // inject style sheet
17656 var style = document.createElement('style'); 13841 var style = document.createElement('style');
17657 style.textContent = 'template {display: none !important;} /* injected by platfor m.js */'; 13842 style.textContent = 'template {display: none !important;} /* injected by platfor m.js */';
17658 var head = document.querySelector('head'); 13843 var head = document.querySelector('head');
17659 head.insertBefore(style, head.firstChild); 13844 head.insertBefore(style, head.firstChild);
17660 13845
17661 // flush (with logging) 13846 // flush (with logging)
17662 var flushing; 13847 var flushing;
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
17694 } 13879 }
17695 } 13880 }
17696 13881
17697 // exports 13882 // exports
17698 scope.flush = flush; 13883 scope.flush = flush;
17699 13884
17700 })(window.Platform); 13885 })(window.Platform);
17701 13886
17702 13887
17703 //# sourceMappingURL=platform.concat.js.map 13888 //# sourceMappingURL=platform.concat.js.map
OLDNEW
« no previous file with comments | « pkg/web_components/lib/platform.js ('k') | pkg/web_components/pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698