| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |