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

Side by Side Diff: pkg/polymer/lib/src/js/polymer/polymer.concat.js

Issue 558673004: update polymer js to 0.4.0 (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: review updates Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /** 1 /**
2 * @license 2 * @license
3 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. 3 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
4 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt 4 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
5 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt 5 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
6 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt 6 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
7 * Code distributed by Google as part of the polymer project is also 7 * Code distributed by Google as part of the polymer project is also
8 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt 8 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
9 */ 9 */
10 window.PolymerGestures = {}; 10 window.PolymerGestures = {};
(...skipping 573 matching lines...) Expand 10 before | Expand all | Expand 10 after
584 0, 584 0,
585 0, 585 0,
586 function(){}, 586 function(){},
587 false 587 false
588 ]; 588 ];
589 589
590 var HAS_SVG_INSTANCE = (typeof SVGElementInstance !== 'undefined'); 590 var HAS_SVG_INSTANCE = (typeof SVGElementInstance !== 'undefined');
591 591
592 var eventFactory = scope.eventFactory; 592 var eventFactory = scope.eventFactory;
593 593
594 // set of recognizers to run for the currently handled event
595 var currentGestures;
596
594 /** 597 /**
595 * This module is for normalizing events. Mouse and Touch events will be 598 * This module is for normalizing events. Mouse and Touch events will be
596 * collected here, and fire PointerEvents that have the same semantics, no 599 * collected here, and fire PointerEvents that have the same semantics, no
597 * matter the source. 600 * matter the source.
598 * Events fired: 601 * Events fired:
599 * - pointerdown: a pointing is added 602 * - pointerdown: a pointing is added
600 * - pointerup: a pointer is removed 603 * - pointerup: a pointer is removed
601 * - pointermove: a pointer is moved 604 * - pointermove: a pointer is moved
602 * - pointerover: a pointer crosses into an element 605 * - pointerover: a pointer crosses into an element
603 * - pointerout: a pointer leaves an element 606 * - pointerout: a pointer leaves an element
604 * - pointercancel: a pointer will no longer generate events 607 * - pointercancel: a pointer will no longer generate events
605 */ 608 */
606 var dispatcher = { 609 var dispatcher = {
607 pointermap: new scope.PointerMap(), 610 pointermap: new scope.PointerMap(),
611 requiredGestures: new scope.PointerMap(),
608 eventMap: Object.create(null), 612 eventMap: Object.create(null),
609 // Scope objects for native events. 613 // Scope objects for native events.
610 // This exists for ease of testing. 614 // This exists for ease of testing.
611 eventSources: Object.create(null), 615 eventSources: Object.create(null),
612 eventSourceList: [], 616 eventSourceList: [],
613 gestures: [], 617 gestures: [],
614 // map gesture event -> {listeners: int, index: gestures[int]} 618 // map gesture event -> {listeners: int, index: gestures[int]}
615 dependencyMap: { 619 dependencyMap: {
616 // make sure down and up are in the map to trigger "register" 620 // make sure down and up are in the map to trigger "register"
617 down: {listeners: 0, index: -1}, 621 down: {listeners: 0, index: -1},
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
658 }, 662 },
659 unregister: function(element) { 663 unregister: function(element) {
660 var l = this.eventSourceList.length; 664 var l = this.eventSourceList.length;
661 for (var i = 0, es; (i < l) && (es = this.eventSourceList[i]); i++) { 665 for (var i = 0, es; (i < l) && (es = this.eventSourceList[i]); i++) {
662 // call eventsource register 666 // call eventsource register
663 es.unregister.call(es, element); 667 es.unregister.call(es, element);
664 } 668 }
665 }, 669 },
666 // EVENTS 670 // EVENTS
667 down: function(inEvent) { 671 down: function(inEvent) {
672 this.requiredGestures.set(inEvent.pointerId, currentGestures);
668 this.fireEvent('down', inEvent); 673 this.fireEvent('down', inEvent);
669 }, 674 },
670 move: function(inEvent) { 675 move: function(inEvent) {
671 // pipe move events into gesture queue directly 676 // pipe move events into gesture queue directly
672 inEvent.type = 'move'; 677 inEvent.type = 'move';
673 this.fillGestureQueue(inEvent); 678 this.fillGestureQueue(inEvent);
674 }, 679 },
675 up: function(inEvent) { 680 up: function(inEvent) {
676 this.fireEvent('up', inEvent); 681 this.fireEvent('up', inEvent);
682 this.requiredGestures.delete(inEvent.pointerId);
677 }, 683 },
678 cancel: function(inEvent) { 684 cancel: function(inEvent) {
679 inEvent.tapPrevented = true; 685 inEvent.tapPrevented = true;
680 this.fireEvent('up', inEvent); 686 this.fireEvent('up', inEvent);
687 this.requiredGestures.delete(inEvent.pointerId);
681 }, 688 },
682 // LISTENER LOGIC 689 // LISTENER LOGIC
683 eventHandler: function(inEvent) { 690 eventHandler: function(inEvent) {
684 // This is used to prevent multiple dispatch of events from 691 // This is used to prevent multiple dispatch of events from
685 // platform events. This can happen when two elements in different scopes 692 // platform events. This can happen when two elements in different scopes
686 // are set up to create pointer events, which is relevant to Shadow DOM. 693 // are set up to create pointer events, which is relevant to Shadow DOM.
687 694
688 // TODO(dfreedm): make this check more granular, allow for minimal event g eneration 695 var type = inEvent.type;
689 // e.g inEvent._handledByPG['tap'] and inEvent._handledByPG['track'], etc 696
697 // only generate the list of desired events on "down"
698 if (type === 'touchstart' || type === 'mousedown' || type === 'pointerdown ' || type === 'MSPointerDown') {
699 if (!inEvent._handledByPG) {
700 currentGestures = {};
701 }
702 // map gesture names to ordered set of recognizers
703 var gesturesWanted = inEvent.currentTarget._pgEvents;
704 if (gesturesWanted) {
705 var gk = Object.keys(gesturesWanted);
706 for (var i = 0, r, ri, g; i < gk.length; i++) {
707 // gesture
708 g = gk[i];
709 if (gesturesWanted[g] > 0) {
710 // lookup gesture recognizer
711 r = this.dependencyMap[g];
712 // recognizer index
713 ri = r ? r.index : -1;
714 currentGestures[ri] = true;
715 }
716 }
717 }
718 }
719
690 if (inEvent._handledByPG) { 720 if (inEvent._handledByPG) {
691 return; 721 return;
692 } 722 }
693 var type = inEvent.type;
694 var fn = this.eventMap && this.eventMap[type]; 723 var fn = this.eventMap && this.eventMap[type];
695 if (fn) { 724 if (fn) {
696 fn(inEvent); 725 fn(inEvent);
697 } 726 }
698 inEvent._handledByPG = true; 727 inEvent._handledByPG = true;
699 }, 728 },
700 // set up event listeners 729 // set up event listeners
701 listen: function(target, events) { 730 listen: function(target, events) {
702 for (var i = 0, l = events.length, e; (i < l) && (e = events[i]); i++) { 731 for (var i = 0, l = events.length, e; (i < l) && (e = events[i]); i++) {
703 this.addEvent(target, e); 732 this.addEvent(target, e);
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
775 t.dispatchEvent(inEvent); 804 t.dispatchEvent(inEvent);
776 // clone the event for the gesture system to process 805 // clone the event for the gesture system to process
777 // clone after dispatch to pick up gesture prevention code 806 // clone after dispatch to pick up gesture prevention code
778 var clone = this.cloneEvent(inEvent); 807 var clone = this.cloneEvent(inEvent);
779 clone.target = t; 808 clone.target = t;
780 this.fillGestureQueue(clone); 809 this.fillGestureQueue(clone);
781 } 810 }
782 }, 811 },
783 gestureTrigger: function() { 812 gestureTrigger: function() {
784 // process the gesture queue 813 // process the gesture queue
785 for (var i = 0, e; i < this.gestureQueue.length; i++) { 814 for (var i = 0, e, rg; i < this.gestureQueue.length; i++) {
786 e = this.gestureQueue[i]; 815 e = this.gestureQueue[i];
816 rg = e._requiredGestures;
787 for (var j = 0, g, fn; j < this.gestures.length; j++) { 817 for (var j = 0, g, fn; j < this.gestures.length; j++) {
788 g = this.gestures[j]; 818 // only run recognizer if an element in the source event's path is lis tening for those gestures
789 fn = g[e.type]; 819 if (rg[j]) {
790 if (g.enabled && fn) { 820 g = this.gestures[j];
791 fn.call(g, e); 821 fn = g[e.type];
822 if (fn) {
823 fn.call(g, e);
824 }
792 } 825 }
793 } 826 }
794 } 827 }
795 this.gestureQueue.length = 0; 828 this.gestureQueue.length = 0;
796 }, 829 },
797 fillGestureQueue: function(ev) { 830 fillGestureQueue: function(ev) {
798 // only trigger the gesture queue once 831 // only trigger the gesture queue once
799 if (!this.gestureQueue.length) { 832 if (!this.gestureQueue.length) {
800 requestAnimationFrame(this.boundGestureTrigger); 833 requestAnimationFrame(this.boundGestureTrigger);
801 } 834 }
835 ev._requiredGestures = this.requiredGestures.get(ev.pointerId);
802 this.gestureQueue.push(ev); 836 this.gestureQueue.push(ev);
803 } 837 }
804 }; 838 };
805 dispatcher.boundHandler = dispatcher.eventHandler.bind(dispatcher); 839 dispatcher.boundHandler = dispatcher.eventHandler.bind(dispatcher);
806 dispatcher.boundGestureTrigger = dispatcher.gestureTrigger.bind(dispatcher); 840 dispatcher.boundGestureTrigger = dispatcher.gestureTrigger.bind(dispatcher);
807 scope.dispatcher = dispatcher; 841 scope.dispatcher = dispatcher;
808 842
809 /** 843 /**
810 * Listen for `gesture` on `node` with the `handler` function 844 * Listen for `gesture` on `node` with the `handler` function
811 * 845 *
812 * If `handler` is the first listener for `gesture`, the underlying gesture re cognizer is then enabled. 846 * If `handler` is the first listener for `gesture`, the underlying gesture re cognizer is then enabled.
813 * 847 *
814 * @param {Element} node 848 * @param {Element} node
815 * @param {string} gesture 849 * @param {string} gesture
816 * @return Boolean `gesture` is a valid gesture 850 * @return Boolean `gesture` is a valid gesture
817 */ 851 */
818 scope.activateGesture = function(node, gesture) { 852 scope.activateGesture = function(node, gesture) {
819 var g = gesture.toLowerCase(); 853 var g = gesture.toLowerCase();
820 var dep = dispatcher.dependencyMap[g]; 854 var dep = dispatcher.dependencyMap[g];
821 if (dep) { 855 if (dep) {
822 var recognizer = dispatcher.gestures[dep.index]; 856 var recognizer = dispatcher.gestures[dep.index];
823 if (dep.listeners === 0) {
824 if (recognizer) {
825 recognizer.enabled = true;
826 }
827 }
828 dep.listeners++;
829 if (!node._pgListeners) { 857 if (!node._pgListeners) {
830 dispatcher.register(node); 858 dispatcher.register(node);
831 node._pgListeners = 0; 859 node._pgListeners = 0;
832 } 860 }
833 // TODO(dfreedm): re-evaluate bookkeeping to avoid using attributes 861 // TODO(dfreedm): re-evaluate bookkeeping to avoid using attributes
834 if (recognizer) { 862 if (recognizer) {
835 var touchAction = recognizer.defaultActions && recognizer.defaultActions [g]; 863 var touchAction = recognizer.defaultActions && recognizer.defaultActions [g];
836 var actionNode; 864 var actionNode;
837 switch(node.nodeType) { 865 switch(node.nodeType) {
838 case Node.ELEMENT_NODE: 866 case Node.ELEMENT_NODE:
839 actionNode = node; 867 actionNode = node;
840 break; 868 break;
841 case Node.DOCUMENT_FRAGMENT_NODE: 869 case Node.DOCUMENT_FRAGMENT_NODE:
842 actionNode = node.host; 870 actionNode = node.host;
843 break; 871 break;
844 default: 872 default:
845 actionNode = null; 873 actionNode = null;
846 break; 874 break;
847 } 875 }
848 if (touchAction && actionNode && !actionNode.hasAttribute('touch-action' )) { 876 if (touchAction && actionNode && !actionNode.hasAttribute('touch-action' )) {
849 actionNode.setAttribute('touch-action', touchAction); 877 actionNode.setAttribute('touch-action', touchAction);
850 } 878 }
851 } 879 }
880 if (!node._pgEvents) {
881 node._pgEvents = {};
882 }
883 node._pgEvents[g] = (node._pgEvents[g] || 0) + 1;
852 node._pgListeners++; 884 node._pgListeners++;
853 } 885 }
854 return Boolean(dep); 886 return Boolean(dep);
855 }; 887 };
856 888
857 /** 889 /**
858 * 890 *
859 * Listen for `gesture` from `node` with `handler` function. 891 * Listen for `gesture` from `node` with `handler` function.
860 * 892 *
861 * @param {Element} node 893 * @param {Element} node
(...skipping 14 matching lines...) Expand all
876 * If `handler` is the last listener for `gesture`, the underlying gesture rec ognizer is disabled. 908 * If `handler` is the last listener for `gesture`, the underlying gesture rec ognizer is disabled.
877 * 909 *
878 * @param {Element} node 910 * @param {Element} node
879 * @param {string} gesture 911 * @param {string} gesture
880 * @return Boolean `gesture` is a valid gesture 912 * @return Boolean `gesture` is a valid gesture
881 */ 913 */
882 scope.deactivateGesture = function(node, gesture) { 914 scope.deactivateGesture = function(node, gesture) {
883 var g = gesture.toLowerCase(); 915 var g = gesture.toLowerCase();
884 var dep = dispatcher.dependencyMap[g]; 916 var dep = dispatcher.dependencyMap[g];
885 if (dep) { 917 if (dep) {
886 if (dep.listeners > 0) {
887 dep.listeners--;
888 }
889 if (dep.listeners === 0) {
890 var recognizer = dispatcher.gestures[dep.index];
891 if (recognizer) {
892 recognizer.enabled = false;
893 }
894 }
895 if (node._pgListeners > 0) { 918 if (node._pgListeners > 0) {
896 node._pgListeners--; 919 node._pgListeners--;
897 } 920 }
898 if (node._pgListeners === 0) { 921 if (node._pgListeners === 0) {
899 dispatcher.unregister(node); 922 dispatcher.unregister(node);
900 } 923 }
924 if (node._pgEvents) {
925 if (node._pgEvents[g] > 0) {
926 node._pgEvents[g]--;
927 } else {
928 node._pgEvents[g] = 0;
929 }
930 }
901 } 931 }
902 return Boolean(dep); 932 return Boolean(dep);
903 }; 933 };
904 934
905 /** 935 /**
906 * Stop listening for `gesture` from `node` with `handler` function. 936 * Stop listening for `gesture` from `node` with `handler` function.
907 * 937 *
908 * @param {Element} node 938 * @param {Element} node
909 * @param {string} gesture 939 * @param {string} gesture
910 * @param {Function} handler 940 * @param {Function} handler
(...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after
1358 var pointermap = dispatcher.pointermap; 1388 var pointermap = dispatcher.pointermap;
1359 var HAS_BITMAP_TYPE = window.MSPointerEvent && typeof window.MSPointerEvent.MS POINTER_TYPE_MOUSE === 'number'; 1389 var HAS_BITMAP_TYPE = window.MSPointerEvent && typeof window.MSPointerEvent.MS POINTER_TYPE_MOUSE === 'number';
1360 var msEvents = { 1390 var msEvents = {
1361 events: [ 1391 events: [
1362 'MSPointerDown', 1392 'MSPointerDown',
1363 'MSPointerMove', 1393 'MSPointerMove',
1364 'MSPointerUp', 1394 'MSPointerUp',
1365 'MSPointerCancel', 1395 'MSPointerCancel',
1366 ], 1396 ],
1367 register: function(target) { 1397 register: function(target) {
1368 if (target !== document) {
1369 return;
1370 }
1371 dispatcher.listen(target, this.events); 1398 dispatcher.listen(target, this.events);
1372 }, 1399 },
1373 unregister: function(target) { 1400 unregister: function(target) {
1374 dispatcher.unlisten(target, this.events); 1401 dispatcher.unlisten(target, this.events);
1375 }, 1402 },
1376 POINTER_TYPES: [ 1403 POINTER_TYPES: [
1377 '', 1404 '',
1378 'unavailable', 1405 'unavailable',
1379 'touch', 1406 'touch',
1380 'pen', 1407 'pen',
(...skipping 11 matching lines...) Expand all
1392 cleanup: function(id) { 1419 cleanup: function(id) {
1393 pointermap['delete'](id); 1420 pointermap['delete'](id);
1394 }, 1421 },
1395 MSPointerDown: function(inEvent) { 1422 MSPointerDown: function(inEvent) {
1396 var e = this.prepareEvent(inEvent); 1423 var e = this.prepareEvent(inEvent);
1397 e.target = scope.findTarget(inEvent); 1424 e.target = scope.findTarget(inEvent);
1398 pointermap.set(inEvent.pointerId, e.target); 1425 pointermap.set(inEvent.pointerId, e.target);
1399 dispatcher.down(e); 1426 dispatcher.down(e);
1400 }, 1427 },
1401 MSPointerMove: function(inEvent) { 1428 MSPointerMove: function(inEvent) {
1402 var e = this.prepareEvent(inEvent); 1429 var target = pointermap.get(inEvent.pointerId);
1403 e.target = pointermap.get(e.pointerId); 1430 if (target) {
1404 dispatcher.move(e); 1431 var e = this.prepareEvent(inEvent);
1432 e.target = target;
1433 dispatcher.move(e);
1434 }
1405 }, 1435 },
1406 MSPointerUp: function(inEvent) { 1436 MSPointerUp: function(inEvent) {
1407 var e = this.prepareEvent(inEvent); 1437 var e = this.prepareEvent(inEvent);
1408 e.relatedTarget = scope.findTarget(inEvent); 1438 e.relatedTarget = scope.findTarget(inEvent);
1409 e.target = pointermap.get(e.pointerId); 1439 e.target = pointermap.get(e.pointerId);
1410 dispatcher.up(e); 1440 dispatcher.up(e);
1411 this.cleanup(inEvent.pointerId); 1441 this.cleanup(inEvent.pointerId);
1412 }, 1442 },
1413 MSPointerCancel: function(inEvent) { 1443 MSPointerCancel: function(inEvent) {
1414 var e = this.prepareEvent(inEvent); 1444 var e = this.prepareEvent(inEvent);
(...skipping 25 matching lines...) Expand all
1440 'pointermove', 1470 'pointermove',
1441 'pointerup', 1471 'pointerup',
1442 'pointercancel' 1472 'pointercancel'
1443 ], 1473 ],
1444 prepareEvent: function(inEvent) { 1474 prepareEvent: function(inEvent) {
1445 var e = dispatcher.cloneEvent(inEvent); 1475 var e = dispatcher.cloneEvent(inEvent);
1446 e._source = 'pointer'; 1476 e._source = 'pointer';
1447 return e; 1477 return e;
1448 }, 1478 },
1449 register: function(target) { 1479 register: function(target) {
1450 if (target !== document) {
1451 return;
1452 }
1453 dispatcher.listen(target, this.events); 1480 dispatcher.listen(target, this.events);
1454 }, 1481 },
1455 unregister: function(target) { 1482 unregister: function(target) {
1456 dispatcher.unlisten(target, this.events); 1483 dispatcher.unlisten(target, this.events);
1457 }, 1484 },
1458 cleanup: function(id) { 1485 cleanup: function(id) {
1459 pointermap['delete'](id); 1486 pointermap['delete'](id);
1460 }, 1487 },
1461 pointerdown: function(inEvent) { 1488 pointerdown: function(inEvent) {
1462 var e = this.prepareEvent(inEvent); 1489 var e = this.prepareEvent(inEvent);
1463 e.target = scope.findTarget(inEvent); 1490 e.target = scope.findTarget(inEvent);
1464 pointermap.set(e.pointerId, e.target); 1491 pointermap.set(e.pointerId, e.target);
1465 dispatcher.down(e); 1492 dispatcher.down(e);
1466 }, 1493 },
1467 pointermove: function(inEvent) { 1494 pointermove: function(inEvent) {
1468 var e = this.prepareEvent(inEvent); 1495 var target = pointermap.get(inEvent.pointerId);
1469 e.target = pointermap.get(e.pointerId); 1496 if (target) {
1470 dispatcher.move(e); 1497 var e = this.prepareEvent(inEvent);
1498 e.target = target;
1499 dispatcher.move(e);
1500 }
1471 }, 1501 },
1472 pointerup: function(inEvent) { 1502 pointerup: function(inEvent) {
1473 var e = this.prepareEvent(inEvent); 1503 var e = this.prepareEvent(inEvent);
1474 e.relatedTarget = scope.findTarget(inEvent); 1504 e.relatedTarget = scope.findTarget(inEvent);
1475 e.target = pointermap.get(e.pointerId); 1505 e.target = pointermap.get(e.pointerId);
1476 dispatcher.up(e); 1506 dispatcher.up(e);
1477 this.cleanup(inEvent.pointerId); 1507 this.cleanup(inEvent.pointerId);
1478 }, 1508 },
1479 pointercancel: function(inEvent) { 1509 pointercancel: function(inEvent) {
1480 var e = this.prepareEvent(inEvent); 1510 var e = this.prepareEvent(inEvent);
(...skipping 2180 matching lines...) Expand 10 before | Expand all | Expand 10 after
3661 3691
3662 /* 3692 /*
3663 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. 3693 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
3664 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt 3694 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
3665 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt 3695 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
3666 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt 3696 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
3667 * Code distributed by Google as part of the polymer project is also 3697 * Code distributed by Google as part of the polymer project is also
3668 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt 3698 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
3669 */ 3699 */
3670 Polymer = { 3700 Polymer = {
3671 version: '0.3.5-5d00e4b' 3701 version: '0.4.0-d66a86e'
3672 }; 3702 };
3673 3703
3674 /* 3704 /*
3675 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. 3705 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
3676 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt 3706 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
3677 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt 3707 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
3678 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt 3708 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
3679 * Code distributed by Google as part of the polymer project is also 3709 * Code distributed by Google as part of the polymer project is also
3680 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt 3710 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
3681 */ 3711 */
3682 3712
3683 // TODO(sorvell): this ensures Polymer is an object and not a function 3713 // TODO(sorvell): this ensures Polymer is an object and not a function
3684 // Platform is currently defining it as a function to allow for async loading 3714 // Platform is currently defining it as a function to allow for async loading
3685 // of polymer; once we refine the loading process this likely goes away. 3715 // of polymer; once we refine the loading process this likely goes away.
3686 if (typeof window.Polymer === 'function') { 3716 if (typeof window.Polymer === 'function') {
3687 Polymer = {}; 3717 Polymer = {};
3688 } 3718 }
3689 3719
3690 3720
3691 /* 3721 /*
3692 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. 3722 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
3693 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt 3723 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
3694 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt 3724 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
3695 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt 3725 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
3696 * Code distributed by Google as part of the polymer project is also 3726 * Code distributed by Google as part of the polymer project is also
3697 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt 3727 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
3698 */ 3728 */
3699 3729
3700 (function(scope) { 3730 /*
3731 » On supported platforms, platform.js is not needed. To retain compatibili ty
3732 » with the polyfills, we stub out minimal functionality.
3733 */
3734 if (!window.Platform) {
3735 logFlags = window.logFlags || {};
3701 3736
3702 // copy own properties from 'api' to 'prototype, with name hinting for 'super' 3737
3703 function extend(prototype, api) { 3738 Platform = {
3704 if (prototype && api) { 3739 » flush: function() {}
3705 // use only own properties of 'api' 3740 };
3706 Object.getOwnPropertyNames(api).forEach(function(n) { 3741
3707 // acquire property descriptor 3742 CustomElements = {
3708 var pd = Object.getOwnPropertyDescriptor(api, n); 3743 » useNative: true,
3709 if (pd) { 3744 ready: true,
3710 // clone property via descriptor 3745 takeRecords: function() {},
3711 Object.defineProperty(prototype, n, pd); 3746 instanceof: function(obj, base) {
3712 // cache name-of-method for 'super' engine 3747 return obj instanceof base;
3713 if (typeof pd.value == 'function') {
3714 // hint the 'super' engine
3715 pd.value.nom = n;
3716 }
3717 }
3718 });
3719 } 3748 }
3720 return prototype; 3749 };
3721 }
3722 3750
3723 // exports 3751 HTMLImports = {
3752 » useNative: true
3753 };
3724 3754
3725 scope.extend = extend; 3755
3756 addEventListener('HTMLImportsLoaded', function() {
3757 document.dispatchEvent(
3758 new CustomEvent('WebComponentsReady', {bubbles: true})
3759 );
3760 });
3726 3761
3727 })(Polymer); 3762
3763 // ShadowDOM
3764 ShadowDOMPolyfill = null;
3765 wrap = unwrap = function(n){
3766 return n;
3767 };
3768
3769 }
3728 3770
3729 /* 3771 /*
3730 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. 3772 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
3731 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
3732 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
3733 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
3734 * Code distributed by Google as part of the polymer project is also
3735 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
3736 */
3737
3738 (function(scope) {
3739
3740 // usage
3741
3742 // invoke cb.call(this) in 100ms, unless the job is re-registered,
3743 // which resets the timer
3744 //
3745 // this.myJob = this.job(this.myJob, cb, 100)
3746 //
3747 // returns a job handle which can be used to re-register a job
3748
3749 var Job = function(inContext) {
3750 this.context = inContext;
3751 this.boundComplete = this.complete.bind(this)
3752 };
3753 Job.prototype = {
3754 go: function(callback, wait) {
3755 this.callback = callback;
3756 var h;
3757 if (!wait) {
3758 h = requestAnimationFrame(this.boundComplete);
3759 this.handle = function() {
3760 cancelAnimationFrame(h);
3761 }
3762 } else {
3763 h = setTimeout(this.boundComplete, wait);
3764 this.handle = function() {
3765 clearTimeout(h);
3766 }
3767 }
3768 },
3769 stop: function() {
3770 if (this.handle) {
3771 this.handle();
3772 this.handle = null;
3773 }
3774 },
3775 complete: function() {
3776 if (this.handle) {
3777 this.stop();
3778 this.callback.call(this.context);
3779 }
3780 }
3781 };
3782
3783 function job(job, callback, wait) {
3784 if (job) {
3785 job.stop();
3786 } else {
3787 job = new Job(this);
3788 }
3789 job.go(callback, wait);
3790 return job;
3791 }
3792
3793 // exports
3794
3795 scope.job = job;
3796
3797 })(Polymer);
3798
3799 /*
3800 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
3801 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
3802 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
3803 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
3804 * Code distributed by Google as part of the polymer project is also
3805 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
3806 */
3807
3808 (function(scope) {
3809
3810 var registry = {};
3811
3812 HTMLElement.register = function(tag, prototype) {
3813 registry[tag] = prototype;
3814 }
3815
3816 // get prototype mapped to node <tag>
3817 HTMLElement.getPrototypeForTag = function(tag) {
3818 var prototype = !tag ? HTMLElement.prototype : registry[tag];
3819 // TODO(sjmiles): creating <tag> is likely to have wasteful side-effects
3820 return prototype || Object.getPrototypeOf(document.createElement(tag));
3821 };
3822
3823 // we have to flag propagation stoppage for the event dispatcher
3824 var originalStopPropagation = Event.prototype.stopPropagation;
3825 Event.prototype.stopPropagation = function() {
3826 this.cancelBubble = true;
3827 originalStopPropagation.apply(this, arguments);
3828 };
3829
3830 // TODO(sorvell): remove when we're sure imports does not need
3831 // to load stylesheets
3832 /*
3833 HTMLImports.importer.preloadSelectors +=
3834 ', polymer-element link[rel=stylesheet]';
3835 */
3836 })(Polymer);
3837
3838 /*
3839 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
3840 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt 3773 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
3841 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt 3774 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
3842 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt 3775 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
3843 * Code distributed by Google as part of the polymer project is also 3776 * Code distributed by Google as part of the polymer project is also
3844 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt 3777 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
3845 */ 3778 */
3846 3779
3780 (function(scope) {
3781
3782 var hasNative = ('import' in document.createElement('link'));
3783 var useNative = hasNative;
3784
3785 isIE = /Trident/.test(navigator.userAgent);
3786
3787 // TODO(sorvell): SD polyfill intrusion
3788 var hasShadowDOMPolyfill = Boolean(window.ShadowDOMPolyfill);
3789 var wrap = function(node) {
3790 return hasShadowDOMPolyfill ? ShadowDOMPolyfill.wrapIfNeeded(node) : node;
3791 };
3792 var mainDoc = wrap(document);
3793
3794 // NOTE: We cannot polyfill document.currentScript because it's not possible
3795 // both to override and maintain the ability to capture the native value;
3796 // therefore we choose to expose _currentScript both when native imports
3797 // and the polyfill are in use.
3798 var currentScriptDescriptor = {
3799 get: function() {
3800 var script = HTMLImports.currentScript || document.currentScript ||
3801 // NOTE: only works when called in synchronously executing code.
3802 // readyState should check if `loading` but IE10 is
3803 // interactive when scripts run so we cheat.
3804 (document.readyState !== 'complete' ?
3805 document.scripts[document.scripts.length - 1] : null);
3806 return wrap(script);
3807 },
3808 configurable: true
3809 };
3810
3811 Object.defineProperty(document, '_currentScript', currentScriptDescriptor);
3812 Object.defineProperty(mainDoc, '_currentScript', currentScriptDescriptor);
3813
3814 // call a callback when all HTMLImports in the document at call (or at least
3815 // document ready) time have loaded.
3816 // 1. ensure the document is in a ready state (has dom), then
3817 // 2. watch for loading of imports and call callback when done
3818 function whenImportsReady(callback, doc) {
3819 doc = doc || mainDoc;
3820 // if document is loading, wait and try again
3821 whenDocumentReady(function() {
3822 watchImportsLoad(callback, doc);
3823 }, doc);
3824 }
3825
3826 // call the callback when the document is in a ready state (has dom)
3827 var requiredReadyState = isIE ? 'complete' : 'interactive';
3828 var READY_EVENT = 'readystatechange';
3829 function isDocumentReady(doc) {
3830 return (doc.readyState === 'complete' ||
3831 doc.readyState === requiredReadyState);
3832 }
3833
3834 // call <callback> when we ensure the document is in a ready state
3835 function whenDocumentReady(callback, doc) {
3836 if (!isDocumentReady(doc)) {
3837 var checkReady = function() {
3838 if (doc.readyState === 'complete' ||
3839 doc.readyState === requiredReadyState) {
3840 doc.removeEventListener(READY_EVENT, checkReady);
3841 whenDocumentReady(callback, doc);
3842 }
3843 };
3844 doc.addEventListener(READY_EVENT, checkReady);
3845 } else if (callback) {
3846 callback();
3847 }
3848 }
3849
3850 function markTargetLoaded(event) {
3851 event.target.__loaded = true;
3852 }
3853
3854 // call <callback> when we ensure all imports have loaded
3855 function watchImportsLoad(callback, doc) {
3856 var imports = doc.querySelectorAll('link[rel=import]');
3857 var loaded = 0, l = imports.length;
3858 function checkDone(d) {
3859 if (loaded == l) {
3860 callback && callback();
3861 }
3862 }
3863 function loadedImport(e) {
3864 markTargetLoaded(e);
3865 loaded++;
3866 checkDone();
3867 }
3868 if (l) {
3869 for (var i=0, imp; (i<l) && (imp=imports[i]); i++) {
3870 if (isImportLoaded(imp)) {
3871 loadedImport.call(imp, {target: imp});
3872 } else {
3873 imp.addEventListener('load', loadedImport);
3874 imp.addEventListener('error', loadedImport);
3875 }
3876 }
3877 } else {
3878 checkDone();
3879 }
3880 }
3881
3882 // NOTE: test for native imports loading is based on explicitly watching
3883 // all imports (see below).
3884 function isImportLoaded(link) {
3885 return useNative ? link.__loaded : link.__importParsed;
3886 }
3887
3888 // TODO(sorvell): Workaround for
3889 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=25007, should be removed when
3890 // this bug is addressed.
3891 // (1) Install a mutation observer to see when HTMLImports have loaded
3892 // (2) if this script is run during document load it will watch any existing
3893 // imports for loading.
3894 //
3895 // NOTE: The workaround has restricted functionality: (1) it's only compatible
3896 // with imports that are added to document.head since the mutation observer
3897 // watches only head for perf reasons, (2) it requires this script
3898 // to run before any imports have completed loading.
3899 if (useNative) {
3900 new MutationObserver(function(mxns) {
3901 for (var i=0, l=mxns.length, m; (i < l) && (m=mxns[i]); i++) {
3902 if (m.addedNodes) {
3903 handleImports(m.addedNodes);
3904 }
3905 }
3906 }).observe(document.head, {childList: true});
3907
3908 function handleImports(nodes) {
3909 for (var i=0, l=nodes.length, n; (i<l) && (n=nodes[i]); i++) {
3910 if (isImport(n)) {
3911 handleImport(n);
3912 }
3913 }
3914 }
3915
3916 function isImport(element) {
3917 return element.localName === 'link' && element.rel === 'import';
3918 }
3919
3920 function handleImport(element) {
3921 var loaded = element.import;
3922 if (loaded) {
3923 markTargetLoaded({target: element});
3924 } else {
3925 element.addEventListener('load', markTargetLoaded);
3926 element.addEventListener('error', markTargetLoaded);
3927 }
3928 }
3929
3930 // make sure to catch any imports that are in the process of loading
3931 // when this script is run.
3932 (function() {
3933 if (document.readyState === 'loading') {
3934 var imports = document.querySelectorAll('link[rel=import]');
3935 for (var i=0, l=imports.length, imp; (i<l) && (imp=imports[i]); i++) {
3936 handleImport(imp);
3937 }
3938 }
3939 })();
3940
3941 }
3942
3943 // Fire the 'HTMLImportsLoaded' event when imports in document at load time
3944 // have loaded. This event is required to simulate the script blocking
3945 // behavior of native imports. A main document script that needs to be sure
3946 // imports have loaded should wait for this event.
3947 whenImportsReady(function() {
3948 HTMLImports.ready = true;
3949 HTMLImports.readyTime = new Date().getTime();
3950 mainDoc.dispatchEvent(
3951 new CustomEvent('HTMLImportsLoaded', {bubbles: true})
3952 );
3953 });
3954
3955 // exports
3956 scope.useNative = useNative;
3957 scope.isImportLoaded = isImportLoaded;
3958 scope.whenReady = whenImportsReady;
3959 scope.isIE = isIE;
3960
3961 // deprecated
3962 scope.whenImportsReady = whenImportsReady;
3963
3964 })(window.HTMLImports);
3965 /*
3966 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
3967 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
3968 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
3969 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
3970 * Code distributed by Google as part of the polymer project is also
3971 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
3972 */
3973
3974 (function(scope) {
3975
3976 function withDependencies(task, depends) {
3977 depends = depends || [];
3978 if (!depends.map) {
3979 depends = [depends];
3980 }
3981 return task.apply(this, depends.map(marshal));
3982 }
3983
3984 function module(name, dependsOrFactory, moduleFactory) {
3985 var module;
3986 switch (arguments.length) {
3987 case 0:
3988 return;
3989 case 1:
3990 module = null;
3991 break;
3992 case 2:
3993 // dependsOrFactory is `factory` in this case
3994 module = dependsOrFactory.apply(this);
3995 break;
3996 default:
3997 // dependsOrFactory is `depends` in this case
3998 module = withDependencies(moduleFactory, dependsOrFactory);
3999 break;
4000 }
4001 modules[name] = module;
4002 };
4003
4004 function marshal(name) {
4005 return modules[name];
4006 }
4007
4008 var modules = {};
4009
4010 function using(depends, task) {
4011 HTMLImports.whenImportsReady(function() {
4012 withDependencies(task, depends);
4013 });
4014 };
4015
4016 // exports
4017
4018 scope.marshal = marshal;
4019 // `module` confuses commonjs detectors
4020 scope.modularize = module;
4021 scope.using = using;
4022
4023 })(window);
4024
4025 /*
4026 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
4027 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
4028 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
4029 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
4030 * Code distributed by Google as part of the polymer project is also
4031 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
4032 */
4033
4034 (function(scope) {
4035
4036 // TODO(sorvell): It's desireable to provide a default stylesheet
4037 // that's convenient for styling unresolved elements, but
4038 // it's cumbersome to have to include this manually in every page.
4039 // It would make sense to put inside some HTMLImport but
4040 // the HTMLImports polyfill does not allow loading of stylesheets
4041 // that block rendering. Therefore this injection is tolerated here.
4042 var style = document.createElement('style');
4043 style.textContent = ''
4044 + 'body {'
4045 + 'transition: opacity ease-in 0.2s;'
4046 + ' } \n'
4047 + 'body[unresolved] {'
4048 + 'opacity: 0; display: block; overflow: hidden;'
4049 + ' } \n'
4050 ;
4051 var head = document.querySelector('head');
4052 head.insertBefore(style, head.firstChild);
4053
4054 })(Platform);
4055
4056 // Copyright 2012 Google Inc.
4057 //
4058 // Licensed under the Apache License, Version 2.0 (the "License");
4059 // you may not use this file except in compliance with the License.
4060 // You may obtain a copy of the License at
4061 //
4062 // http://www.apache.org/licenses/LICENSE-2.0
4063 //
4064 // Unless required by applicable law or agreed to in writing, software
4065 // distributed under the License is distributed on an "AS IS" BASIS,
4066 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4067 // See the License for the specific language governing permissions and
4068 // limitations under the License.
4069
4070 (function(global) {
4071 'use strict';
4072
4073 var testingExposeCycleCount = global.testingExposeCycleCount;
4074
4075 // Detect and do basic sanity checking on Object/Array.observe.
4076 function detectObjectObserve() {
4077 if (typeof Object.observe !== 'function' ||
4078 typeof Array.observe !== 'function') {
4079 return false;
4080 }
4081
4082 var records = [];
4083
4084 function callback(recs) {
4085 records = recs;
4086 }
4087
4088 var test = {};
4089 var arr = [];
4090 Object.observe(test, callback);
4091 Array.observe(arr, callback);
4092 test.id = 1;
4093 test.id = 2;
4094 delete test.id;
4095 arr.push(1, 2);
4096 arr.length = 0;
4097
4098 Object.deliverChangeRecords(callback);
4099 if (records.length !== 5)
4100 return false;
4101
4102 if (records[0].type != 'add' ||
4103 records[1].type != 'update' ||
4104 records[2].type != 'delete' ||
4105 records[3].type != 'splice' ||
4106 records[4].type != 'splice') {
4107 return false;
4108 }
4109
4110 Object.unobserve(test, callback);
4111 Array.unobserve(arr, callback);
4112
4113 return true;
4114 }
4115
4116 var hasObserve = detectObjectObserve();
4117
4118 function detectEval() {
4119 // Don't test for eval if we're running in a Chrome App environment.
4120 // We check for APIs set that only exist in a Chrome App context.
4121 if (typeof chrome !== 'undefined' && chrome.app && chrome.app.runtime) {
4122 return false;
4123 }
4124
4125 // Firefox OS Apps do not allow eval. This feature detection is very hacky
4126 // but even if some other platform adds support for this function this code
4127 // will continue to work.
4128 if (navigator.getDeviceStorage) {
4129 return false;
4130 }
4131
4132 try {
4133 var f = new Function('', 'return true;');
4134 return f();
4135 } catch (ex) {
4136 return false;
4137 }
4138 }
4139
4140 var hasEval = detectEval();
4141
4142 function isIndex(s) {
4143 return +s === s >>> 0;
4144 }
4145
4146 function toNumber(s) {
4147 return +s;
4148 }
4149
4150 function isObject(obj) {
4151 return obj === Object(obj);
4152 }
4153
4154 var numberIsNaN = global.Number.isNaN || function(value) {
4155 return typeof value === 'number' && global.isNaN(value);
4156 }
4157
4158 function areSameValue(left, right) {
4159 if (left === right)
4160 return left !== 0 || 1 / left === 1 / right;
4161 if (numberIsNaN(left) && numberIsNaN(right))
4162 return true;
4163
4164 return left !== left && right !== right;
4165 }
4166
4167 var createObject = ('__proto__' in {}) ?
4168 function(obj) { return obj; } :
4169 function(obj) {
4170 var proto = obj.__proto__;
4171 if (!proto)
4172 return obj;
4173 var newObject = Object.create(proto);
4174 Object.getOwnPropertyNames(obj).forEach(function(name) {
4175 Object.defineProperty(newObject, name,
4176 Object.getOwnPropertyDescriptor(obj, name));
4177 });
4178 return newObject;
4179 };
4180
4181 var identStart = '[\$_a-zA-Z]';
4182 var identPart = '[\$_a-zA-Z0-9]';
4183 var identRegExp = new RegExp('^' + identStart + '+' + identPart + '*' + '$');
4184
4185 function getPathCharType(char) {
4186 if (char === undefined)
4187 return 'eof';
4188
4189 var code = char.charCodeAt(0);
4190
4191 switch(code) {
4192 case 0x5B: // [
4193 case 0x5D: // ]
4194 case 0x2E: // .
4195 case 0x22: // "
4196 case 0x27: // '
4197 case 0x30: // 0
4198 return char;
4199
4200 case 0x5F: // _
4201 case 0x24: // $
4202 return 'ident';
4203
4204 case 0x20: // Space
4205 case 0x09: // Tab
4206 case 0x0A: // Newline
4207 case 0x0D: // Return
4208 case 0xA0: // No-break space
4209 case 0xFEFF: // Byte Order Mark
4210 case 0x2028: // Line Separator
4211 case 0x2029: // Paragraph Separator
4212 return 'ws';
4213 }
4214
4215 // a-z, A-Z
4216 if ((0x61 <= code && code <= 0x7A) || (0x41 <= code && code <= 0x5A))
4217 return 'ident';
4218
4219 // 1-9
4220 if (0x31 <= code && code <= 0x39)
4221 return 'number';
4222
4223 return 'else';
4224 }
4225
4226 var pathStateMachine = {
4227 'beforePath': {
4228 'ws': ['beforePath'],
4229 'ident': ['inIdent', 'append'],
4230 '[': ['beforeElement'],
4231 'eof': ['afterPath']
4232 },
4233
4234 'inPath': {
4235 'ws': ['inPath'],
4236 '.': ['beforeIdent'],
4237 '[': ['beforeElement'],
4238 'eof': ['afterPath']
4239 },
4240
4241 'beforeIdent': {
4242 'ws': ['beforeIdent'],
4243 'ident': ['inIdent', 'append']
4244 },
4245
4246 'inIdent': {
4247 'ident': ['inIdent', 'append'],
4248 '0': ['inIdent', 'append'],
4249 'number': ['inIdent', 'append'],
4250 'ws': ['inPath', 'push'],
4251 '.': ['beforeIdent', 'push'],
4252 '[': ['beforeElement', 'push'],
4253 'eof': ['afterPath', 'push']
4254 },
4255
4256 'beforeElement': {
4257 'ws': ['beforeElement'],
4258 '0': ['afterZero', 'append'],
4259 'number': ['inIndex', 'append'],
4260 "'": ['inSingleQuote', 'append', ''],
4261 '"': ['inDoubleQuote', 'append', '']
4262 },
4263
4264 'afterZero': {
4265 'ws': ['afterElement', 'push'],
4266 ']': ['inPath', 'push']
4267 },
4268
4269 'inIndex': {
4270 '0': ['inIndex', 'append'],
4271 'number': ['inIndex', 'append'],
4272 'ws': ['afterElement'],
4273 ']': ['inPath', 'push']
4274 },
4275
4276 'inSingleQuote': {
4277 "'": ['afterElement'],
4278 'eof': ['error'],
4279 'else': ['inSingleQuote', 'append']
4280 },
4281
4282 'inDoubleQuote': {
4283 '"': ['afterElement'],
4284 'eof': ['error'],
4285 'else': ['inDoubleQuote', 'append']
4286 },
4287
4288 'afterElement': {
4289 'ws': ['afterElement'],
4290 ']': ['inPath', 'push']
4291 }
4292 }
4293
4294 function noop() {}
4295
4296 function parsePath(path) {
4297 var keys = [];
4298 var index = -1;
4299 var c, newChar, key, type, transition, action, typeMap, mode = 'beforePath';
4300
4301 var actions = {
4302 push: function() {
4303 if (key === undefined)
4304 return;
4305
4306 keys.push(key);
4307 key = undefined;
4308 },
4309
4310 append: function() {
4311 if (key === undefined)
4312 key = newChar
4313 else
4314 key += newChar;
4315 }
4316 };
4317
4318 function maybeUnescapeQuote() {
4319 if (index >= path.length)
4320 return;
4321
4322 var nextChar = path[index + 1];
4323 if ((mode == 'inSingleQuote' && nextChar == "'") ||
4324 (mode == 'inDoubleQuote' && nextChar == '"')) {
4325 index++;
4326 newChar = nextChar;
4327 actions.append();
4328 return true;
4329 }
4330 }
4331
4332 while (mode) {
4333 index++;
4334 c = path[index];
4335
4336 if (c == '\\' && maybeUnescapeQuote(mode))
4337 continue;
4338
4339 type = getPathCharType(c);
4340 typeMap = pathStateMachine[mode];
4341 transition = typeMap[type] || typeMap['else'] || 'error';
4342
4343 if (transition == 'error')
4344 return; // parse error;
4345
4346 mode = transition[0];
4347 action = actions[transition[1]] || noop;
4348 newChar = transition[2] === undefined ? c : transition[2];
4349 action();
4350
4351 if (mode === 'afterPath') {
4352 return keys;
4353 }
4354 }
4355
4356 return; // parse error
4357 }
4358
4359 function isIdent(s) {
4360 return identRegExp.test(s);
4361 }
4362
4363 var constructorIsPrivate = {};
4364
4365 function Path(parts, privateToken) {
4366 if (privateToken !== constructorIsPrivate)
4367 throw Error('Use Path.get to retrieve path objects');
4368
4369 for (var i = 0; i < parts.length; i++) {
4370 this.push(String(parts[i]));
4371 }
4372
4373 if (hasEval && this.length) {
4374 this.getValueFrom = this.compiledGetValueFromFn();
4375 }
4376 }
4377
4378 // TODO(rafaelw): Make simple LRU cache
4379 var pathCache = {};
4380
4381 function getPath(pathString) {
4382 if (pathString instanceof Path)
4383 return pathString;
4384
4385 if (pathString == null || pathString.length == 0)
4386 pathString = '';
4387
4388 if (typeof pathString != 'string') {
4389 if (isIndex(pathString.length)) {
4390 // Constructed with array-like (pre-parsed) keys
4391 return new Path(pathString, constructorIsPrivate);
4392 }
4393
4394 pathString = String(pathString);
4395 }
4396
4397 var path = pathCache[pathString];
4398 if (path)
4399 return path;
4400
4401 var parts = parsePath(pathString);
4402 if (!parts)
4403 return invalidPath;
4404
4405 var path = new Path(parts, constructorIsPrivate);
4406 pathCache[pathString] = path;
4407 return path;
4408 }
4409
4410 Path.get = getPath;
4411
4412 function formatAccessor(key) {
4413 if (isIndex(key)) {
4414 return '[' + key + ']';
4415 } else {
4416 return '["' + key.replace(/"/g, '\\"') + '"]';
4417 }
4418 }
4419
4420 Path.prototype = createObject({
4421 __proto__: [],
4422 valid: true,
4423
4424 toString: function() {
4425 var pathString = '';
4426 for (var i = 0; i < this.length; i++) {
4427 var key = this[i];
4428 if (isIdent(key)) {
4429 pathString += i ? '.' + key : key;
4430 } else {
4431 pathString += formatAccessor(key);
4432 }
4433 }
4434
4435 return pathString;
4436 },
4437
4438 getValueFrom: function(obj, directObserver) {
4439 for (var i = 0; i < this.length; i++) {
4440 if (obj == null)
4441 return;
4442 obj = obj[this[i]];
4443 }
4444 return obj;
4445 },
4446
4447 iterateObjects: function(obj, observe) {
4448 for (var i = 0; i < this.length; i++) {
4449 if (i)
4450 obj = obj[this[i - 1]];
4451 if (!isObject(obj))
4452 return;
4453 observe(obj, this[0]);
4454 }
4455 },
4456
4457 compiledGetValueFromFn: function() {
4458 var str = '';
4459 var pathString = 'obj';
4460 str += 'if (obj != null';
4461 var i = 0;
4462 var key;
4463 for (; i < (this.length - 1); i++) {
4464 key = this[i];
4465 pathString += isIdent(key) ? '.' + key : formatAccessor(key);
4466 str += ' &&\n ' + pathString + ' != null';
4467 }
4468 str += ')\n';
4469
4470 var key = this[i];
4471 pathString += isIdent(key) ? '.' + key : formatAccessor(key);
4472
4473 str += ' return ' + pathString + ';\nelse\n return undefined;';
4474 return new Function('obj', str);
4475 },
4476
4477 setValueFrom: function(obj, value) {
4478 if (!this.length)
4479 return false;
4480
4481 for (var i = 0; i < this.length - 1; i++) {
4482 if (!isObject(obj))
4483 return false;
4484 obj = obj[this[i]];
4485 }
4486
4487 if (!isObject(obj))
4488 return false;
4489
4490 obj[this[i]] = value;
4491 return true;
4492 }
4493 });
4494
4495 var invalidPath = new Path('', constructorIsPrivate);
4496 invalidPath.valid = false;
4497 invalidPath.getValueFrom = invalidPath.setValueFrom = function() {};
4498
4499 var MAX_DIRTY_CHECK_CYCLES = 1000;
4500
4501 function dirtyCheck(observer) {
4502 var cycles = 0;
4503 while (cycles < MAX_DIRTY_CHECK_CYCLES && observer.check_()) {
4504 cycles++;
4505 }
4506 if (testingExposeCycleCount)
4507 global.dirtyCheckCycleCount = cycles;
4508
4509 return cycles > 0;
4510 }
4511
4512 function objectIsEmpty(object) {
4513 for (var prop in object)
4514 return false;
4515 return true;
4516 }
4517
4518 function diffIsEmpty(diff) {
4519 return objectIsEmpty(diff.added) &&
4520 objectIsEmpty(diff.removed) &&
4521 objectIsEmpty(diff.changed);
4522 }
4523
4524 function diffObjectFromOldObject(object, oldObject) {
4525 var added = {};
4526 var removed = {};
4527 var changed = {};
4528
4529 for (var prop in oldObject) {
4530 var newValue = object[prop];
4531
4532 if (newValue !== undefined && newValue === oldObject[prop])
4533 continue;
4534
4535 if (!(prop in object)) {
4536 removed[prop] = undefined;
4537 continue;
4538 }
4539
4540 if (newValue !== oldObject[prop])
4541 changed[prop] = newValue;
4542 }
4543
4544 for (var prop in object) {
4545 if (prop in oldObject)
4546 continue;
4547
4548 added[prop] = object[prop];
4549 }
4550
4551 if (Array.isArray(object) && object.length !== oldObject.length)
4552 changed.length = object.length;
4553
4554 return {
4555 added: added,
4556 removed: removed,
4557 changed: changed
4558 };
4559 }
4560
4561 var eomTasks = [];
4562 function runEOMTasks() {
4563 if (!eomTasks.length)
4564 return false;
4565
4566 for (var i = 0; i < eomTasks.length; i++) {
4567 eomTasks[i]();
4568 }
4569 eomTasks.length = 0;
4570 return true;
4571 }
4572
4573 var runEOM = hasObserve ? (function(){
4574 var eomObj = { pingPong: true };
4575 var eomRunScheduled = false;
4576
4577 Object.observe(eomObj, function() {
4578 runEOMTasks();
4579 eomRunScheduled = false;
4580 });
4581
4582 return function(fn) {
4583 eomTasks.push(fn);
4584 if (!eomRunScheduled) {
4585 eomRunScheduled = true;
4586 eomObj.pingPong = !eomObj.pingPong;
4587 }
4588 };
4589 })() :
4590 (function() {
4591 return function(fn) {
4592 eomTasks.push(fn);
4593 };
4594 })();
4595
4596 var observedObjectCache = [];
4597
4598 function newObservedObject() {
4599 var observer;
4600 var object;
4601 var discardRecords = false;
4602 var first = true;
4603
4604 function callback(records) {
4605 if (observer && observer.state_ === OPENED && !discardRecords)
4606 observer.check_(records);
4607 }
4608
4609 return {
4610 open: function(obs) {
4611 if (observer)
4612 throw Error('ObservedObject in use');
4613
4614 if (!first)
4615 Object.deliverChangeRecords(callback);
4616
4617 observer = obs;
4618 first = false;
4619 },
4620 observe: function(obj, arrayObserve) {
4621 object = obj;
4622 if (arrayObserve)
4623 Array.observe(object, callback);
4624 else
4625 Object.observe(object, callback);
4626 },
4627 deliver: function(discard) {
4628 discardRecords = discard;
4629 Object.deliverChangeRecords(callback);
4630 discardRecords = false;
4631 },
4632 close: function() {
4633 observer = undefined;
4634 Object.unobserve(object, callback);
4635 observedObjectCache.push(this);
4636 }
4637 };
4638 }
4639
4640 /*
4641 * The observedSet abstraction is a perf optimization which reduces the total
4642 * number of Object.observe observations of a set of objects. The idea is that
4643 * groups of Observers will have some object dependencies in common and this
4644 * observed set ensures that each object in the transitive closure of
4645 * dependencies is only observed once. The observedSet acts as a write barrier
4646 * such that whenever any change comes through, all Observers are checked for
4647 * changed values.
4648 *
4649 * Note that this optimization is explicitly moving work from setup-time to
4650 * change-time.
4651 *
4652 * TODO(rafaelw): Implement "garbage collection". In order to move work off
4653 * the critical path, when Observers are closed, their observed objects are
4654 * not Object.unobserve(d). As a result, it's possible that if the observedSet
4655 * is kept open, but some Observers have been closed, it could cause "leaks"
4656 * (prevent otherwise collectable objects from being collected). At some
4657 * point, we should implement incremental "gc" which keeps a list of
4658 * observedSets which may need clean-up and does small amounts of cleanup on a
4659 * timeout until all is clean.
4660 */
4661
4662 function getObservedObject(observer, object, arrayObserve) {
4663 var dir = observedObjectCache.pop() || newObservedObject();
4664 dir.open(observer);
4665 dir.observe(object, arrayObserve);
4666 return dir;
4667 }
4668
4669 var observedSetCache = [];
4670
4671 function newObservedSet() {
4672 var observerCount = 0;
4673 var observers = [];
4674 var objects = [];
4675 var rootObj;
4676 var rootObjProps;
4677
4678 function observe(obj, prop) {
4679 if (!obj)
4680 return;
4681
4682 if (obj === rootObj)
4683 rootObjProps[prop] = true;
4684
4685 if (objects.indexOf(obj) < 0) {
4686 objects.push(obj);
4687 Object.observe(obj, callback);
4688 }
4689
4690 observe(Object.getPrototypeOf(obj), prop);
4691 }
4692
4693 function allRootObjNonObservedProps(recs) {
4694 for (var i = 0; i < recs.length; i++) {
4695 var rec = recs[i];
4696 if (rec.object !== rootObj ||
4697 rootObjProps[rec.name] ||
4698 rec.type === 'setPrototype') {
4699 return false;
4700 }
4701 }
4702 return true;
4703 }
4704
4705 function callback(recs) {
4706 if (allRootObjNonObservedProps(recs))
4707 return;
4708
4709 var observer;
4710 for (var i = 0; i < observers.length; i++) {
4711 observer = observers[i];
4712 if (observer.state_ == OPENED) {
4713 observer.iterateObjects_(observe);
4714 }
4715 }
4716
4717 for (var i = 0; i < observers.length; i++) {
4718 observer = observers[i];
4719 if (observer.state_ == OPENED) {
4720 observer.check_();
4721 }
4722 }
4723 }
4724
4725 var record = {
4726 object: undefined,
4727 objects: objects,
4728 open: function(obs, object) {
4729 if (!rootObj) {
4730 rootObj = object;
4731 rootObjProps = {};
4732 }
4733
4734 observers.push(obs);
4735 observerCount++;
4736 obs.iterateObjects_(observe);
4737 },
4738 close: function(obs) {
4739 observerCount--;
4740 if (observerCount > 0) {
4741 return;
4742 }
4743
4744 for (var i = 0; i < objects.length; i++) {
4745 Object.unobserve(objects[i], callback);
4746 Observer.unobservedCount++;
4747 }
4748
4749 observers.length = 0;
4750 objects.length = 0;
4751 rootObj = undefined;
4752 rootObjProps = undefined;
4753 observedSetCache.push(this);
4754 }
4755 };
4756
4757 return record;
4758 }
4759
4760 var lastObservedSet;
4761
4762 function getObservedSet(observer, obj) {
4763 if (!lastObservedSet || lastObservedSet.object !== obj) {
4764 lastObservedSet = observedSetCache.pop() || newObservedSet();
4765 lastObservedSet.object = obj;
4766 }
4767 lastObservedSet.open(observer, obj);
4768 return lastObservedSet;
4769 }
4770
4771 var UNOPENED = 0;
4772 var OPENED = 1;
4773 var CLOSED = 2;
4774 var RESETTING = 3;
4775
4776 var nextObserverId = 1;
4777
4778 function Observer() {
4779 this.state_ = UNOPENED;
4780 this.callback_ = undefined;
4781 this.target_ = undefined; // TODO(rafaelw): Should be WeakRef
4782 this.directObserver_ = undefined;
4783 this.value_ = undefined;
4784 this.id_ = nextObserverId++;
4785 }
4786
4787 Observer.prototype = {
4788 open: function(callback, target) {
4789 if (this.state_ != UNOPENED)
4790 throw Error('Observer has already been opened.');
4791
4792 addToAll(this);
4793 this.callback_ = callback;
4794 this.target_ = target;
4795 this.connect_();
4796 this.state_ = OPENED;
4797 return this.value_;
4798 },
4799
4800 close: function() {
4801 if (this.state_ != OPENED)
4802 return;
4803
4804 removeFromAll(this);
4805 this.disconnect_();
4806 this.value_ = undefined;
4807 this.callback_ = undefined;
4808 this.target_ = undefined;
4809 this.state_ = CLOSED;
4810 },
4811
4812 deliver: function() {
4813 if (this.state_ != OPENED)
4814 return;
4815
4816 dirtyCheck(this);
4817 },
4818
4819 report_: function(changes) {
4820 try {
4821 this.callback_.apply(this.target_, changes);
4822 } catch (ex) {
4823 Observer._errorThrownDuringCallback = true;
4824 console.error('Exception caught during observer callback: ' +
4825 (ex.stack || ex));
4826 }
4827 },
4828
4829 discardChanges: function() {
4830 this.check_(undefined, true);
4831 return this.value_;
4832 }
4833 }
4834
4835 var collectObservers = !hasObserve;
4836 var allObservers;
4837 Observer._allObserversCount = 0;
4838
4839 if (collectObservers) {
4840 allObservers = [];
4841 }
4842
4843 function addToAll(observer) {
4844 Observer._allObserversCount++;
4845 if (!collectObservers)
4846 return;
4847
4848 allObservers.push(observer);
4849 }
4850
4851 function removeFromAll(observer) {
4852 Observer._allObserversCount--;
4853 }
4854
4855 var runningMicrotaskCheckpoint = false;
4856
4857 var hasDebugForceFullDelivery = hasObserve && hasEval && (function() {
4858 try {
4859 eval('%RunMicrotasks()');
4860 return true;
4861 } catch (ex) {
4862 return false;
4863 }
4864 })();
4865
4866 global.Platform = global.Platform || {};
4867
4868 global.Platform.performMicrotaskCheckpoint = function() {
4869 if (runningMicrotaskCheckpoint)
4870 return;
4871
4872 if (hasDebugForceFullDelivery) {
4873 eval('%RunMicrotasks()');
4874 return;
4875 }
4876
4877 if (!collectObservers)
4878 return;
4879
4880 runningMicrotaskCheckpoint = true;
4881
4882 var cycles = 0;
4883 var anyChanged, toCheck;
4884
4885 do {
4886 cycles++;
4887 toCheck = allObservers;
4888 allObservers = [];
4889 anyChanged = false;
4890
4891 for (var i = 0; i < toCheck.length; i++) {
4892 var observer = toCheck[i];
4893 if (observer.state_ != OPENED)
4894 continue;
4895
4896 if (observer.check_())
4897 anyChanged = true;
4898
4899 allObservers.push(observer);
4900 }
4901 if (runEOMTasks())
4902 anyChanged = true;
4903 } while (cycles < MAX_DIRTY_CHECK_CYCLES && anyChanged);
4904
4905 if (testingExposeCycleCount)
4906 global.dirtyCheckCycleCount = cycles;
4907
4908 runningMicrotaskCheckpoint = false;
4909 };
4910
4911 if (collectObservers) {
4912 global.Platform.clearObservers = function() {
4913 allObservers = [];
4914 };
4915 }
4916
4917 function ObjectObserver(object) {
4918 Observer.call(this);
4919 this.value_ = object;
4920 this.oldObject_ = undefined;
4921 }
4922
4923 ObjectObserver.prototype = createObject({
4924 __proto__: Observer.prototype,
4925
4926 arrayObserve: false,
4927
4928 connect_: function(callback, target) {
4929 if (hasObserve) {
4930 this.directObserver_ = getObservedObject(this, this.value_,
4931 this.arrayObserve);
4932 } else {
4933 this.oldObject_ = this.copyObject(this.value_);
4934 }
4935
4936 },
4937
4938 copyObject: function(object) {
4939 var copy = Array.isArray(object) ? [] : {};
4940 for (var prop in object) {
4941 copy[prop] = object[prop];
4942 };
4943 if (Array.isArray(object))
4944 copy.length = object.length;
4945 return copy;
4946 },
4947
4948 check_: function(changeRecords, skipChanges) {
4949 var diff;
4950 var oldValues;
4951 if (hasObserve) {
4952 if (!changeRecords)
4953 return false;
4954
4955 oldValues = {};
4956 diff = diffObjectFromChangeRecords(this.value_, changeRecords,
4957 oldValues);
4958 } else {
4959 oldValues = this.oldObject_;
4960 diff = diffObjectFromOldObject(this.value_, this.oldObject_);
4961 }
4962
4963 if (diffIsEmpty(diff))
4964 return false;
4965
4966 if (!hasObserve)
4967 this.oldObject_ = this.copyObject(this.value_);
4968
4969 this.report_([
4970 diff.added || {},
4971 diff.removed || {},
4972 diff.changed || {},
4973 function(property) {
4974 return oldValues[property];
4975 }
4976 ]);
4977
4978 return true;
4979 },
4980
4981 disconnect_: function() {
4982 if (hasObserve) {
4983 this.directObserver_.close();
4984 this.directObserver_ = undefined;
4985 } else {
4986 this.oldObject_ = undefined;
4987 }
4988 },
4989
4990 deliver: function() {
4991 if (this.state_ != OPENED)
4992 return;
4993
4994 if (hasObserve)
4995 this.directObserver_.deliver(false);
4996 else
4997 dirtyCheck(this);
4998 },
4999
5000 discardChanges: function() {
5001 if (this.directObserver_)
5002 this.directObserver_.deliver(true);
5003 else
5004 this.oldObject_ = this.copyObject(this.value_);
5005
5006 return this.value_;
5007 }
5008 });
5009
5010 function ArrayObserver(array) {
5011 if (!Array.isArray(array))
5012 throw Error('Provided object is not an Array');
5013 ObjectObserver.call(this, array);
5014 }
5015
5016 ArrayObserver.prototype = createObject({
5017
5018 __proto__: ObjectObserver.prototype,
5019
5020 arrayObserve: true,
5021
5022 copyObject: function(arr) {
5023 return arr.slice();
5024 },
5025
5026 check_: function(changeRecords) {
5027 var splices;
5028 if (hasObserve) {
5029 if (!changeRecords)
5030 return false;
5031 splices = projectArraySplices(this.value_, changeRecords);
5032 } else {
5033 splices = calcSplices(this.value_, 0, this.value_.length,
5034 this.oldObject_, 0, this.oldObject_.length);
5035 }
5036
5037 if (!splices || !splices.length)
5038 return false;
5039
5040 if (!hasObserve)
5041 this.oldObject_ = this.copyObject(this.value_);
5042
5043 this.report_([splices]);
5044 return true;
5045 }
5046 });
5047
5048 ArrayObserver.applySplices = function(previous, current, splices) {
5049 splices.forEach(function(splice) {
5050 var spliceArgs = [splice.index, splice.removed.length];
5051 var addIndex = splice.index;
5052 while (addIndex < splice.index + splice.addedCount) {
5053 spliceArgs.push(current[addIndex]);
5054 addIndex++;
5055 }
5056
5057 Array.prototype.splice.apply(previous, spliceArgs);
5058 });
5059 };
5060
5061 function PathObserver(object, path) {
5062 Observer.call(this);
5063
5064 this.object_ = object;
5065 this.path_ = getPath(path);
5066 this.directObserver_ = undefined;
5067 }
5068
5069 PathObserver.prototype = createObject({
5070 __proto__: Observer.prototype,
5071
5072 get path() {
5073 return this.path_;
5074 },
5075
5076 connect_: function() {
5077 if (hasObserve)
5078 this.directObserver_ = getObservedSet(this, this.object_);
5079
5080 this.check_(undefined, true);
5081 },
5082
5083 disconnect_: function() {
5084 this.value_ = undefined;
5085
5086 if (this.directObserver_) {
5087 this.directObserver_.close(this);
5088 this.directObserver_ = undefined;
5089 }
5090 },
5091
5092 iterateObjects_: function(observe) {
5093 this.path_.iterateObjects(this.object_, observe);
5094 },
5095
5096 check_: function(changeRecords, skipChanges) {
5097 var oldValue = this.value_;
5098 this.value_ = this.path_.getValueFrom(this.object_);
5099 if (skipChanges || areSameValue(this.value_, oldValue))
5100 return false;
5101
5102 this.report_([this.value_, oldValue, this]);
5103 return true;
5104 },
5105
5106 setValue: function(newValue) {
5107 if (this.path_)
5108 this.path_.setValueFrom(this.object_, newValue);
5109 }
5110 });
5111
5112 function CompoundObserver(reportChangesOnOpen) {
5113 Observer.call(this);
5114
5115 this.reportChangesOnOpen_ = reportChangesOnOpen;
5116 this.value_ = [];
5117 this.directObserver_ = undefined;
5118 this.observed_ = [];
5119 }
5120
5121 var observerSentinel = {};
5122
5123 CompoundObserver.prototype = createObject({
5124 __proto__: Observer.prototype,
5125
5126 connect_: function() {
5127 if (hasObserve) {
5128 var object;
5129 var needsDirectObserver = false;
5130 for (var i = 0; i < this.observed_.length; i += 2) {
5131 object = this.observed_[i]
5132 if (object !== observerSentinel) {
5133 needsDirectObserver = true;
5134 break;
5135 }
5136 }
5137
5138 if (needsDirectObserver)
5139 this.directObserver_ = getObservedSet(this, object);
5140 }
5141
5142 this.check_(undefined, !this.reportChangesOnOpen_);
5143 },
5144
5145 disconnect_: function() {
5146 for (var i = 0; i < this.observed_.length; i += 2) {
5147 if (this.observed_[i] === observerSentinel)
5148 this.observed_[i + 1].close();
5149 }
5150 this.observed_.length = 0;
5151 this.value_.length = 0;
5152
5153 if (this.directObserver_) {
5154 this.directObserver_.close(this);
5155 this.directObserver_ = undefined;
5156 }
5157 },
5158
5159 addPath: function(object, path) {
5160 if (this.state_ != UNOPENED && this.state_ != RESETTING)
5161 throw Error('Cannot add paths once started.');
5162
5163 var path = getPath(path);
5164 this.observed_.push(object, path);
5165 if (!this.reportChangesOnOpen_)
5166 return;
5167 var index = this.observed_.length / 2 - 1;
5168 this.value_[index] = path.getValueFrom(object);
5169 },
5170
5171 addObserver: function(observer) {
5172 if (this.state_ != UNOPENED && this.state_ != RESETTING)
5173 throw Error('Cannot add observers once started.');
5174
5175 this.observed_.push(observerSentinel, observer);
5176 if (!this.reportChangesOnOpen_)
5177 return;
5178 var index = this.observed_.length / 2 - 1;
5179 this.value_[index] = observer.open(this.deliver, this);
5180 },
5181
5182 startReset: function() {
5183 if (this.state_ != OPENED)
5184 throw Error('Can only reset while open');
5185
5186 this.state_ = RESETTING;
5187 this.disconnect_();
5188 },
5189
5190 finishReset: function() {
5191 if (this.state_ != RESETTING)
5192 throw Error('Can only finishReset after startReset');
5193 this.state_ = OPENED;
5194 this.connect_();
5195
5196 return this.value_;
5197 },
5198
5199 iterateObjects_: function(observe) {
5200 var object;
5201 for (var i = 0; i < this.observed_.length; i += 2) {
5202 object = this.observed_[i]
5203 if (object !== observerSentinel)
5204 this.observed_[i + 1].iterateObjects(object, observe)
5205 }
5206 },
5207
5208 check_: function(changeRecords, skipChanges) {
5209 var oldValues;
5210 for (var i = 0; i < this.observed_.length; i += 2) {
5211 var object = this.observed_[i];
5212 var path = this.observed_[i+1];
5213 var value;
5214 if (object === observerSentinel) {
5215 var observable = path;
5216 value = this.state_ === UNOPENED ?
5217 observable.open(this.deliver, this) :
5218 observable.discardChanges();
5219 } else {
5220 value = path.getValueFrom(object);
5221 }
5222
5223 if (skipChanges) {
5224 this.value_[i / 2] = value;
5225 continue;
5226 }
5227
5228 if (areSameValue(value, this.value_[i / 2]))
5229 continue;
5230
5231 oldValues = oldValues || [];
5232 oldValues[i / 2] = this.value_[i / 2];
5233 this.value_[i / 2] = value;
5234 }
5235
5236 if (!oldValues)
5237 return false;
5238
5239 // TODO(rafaelw): Having observed_ as the third callback arg here is
5240 // pretty lame API. Fix.
5241 this.report_([this.value_, oldValues, this.observed_]);
5242 return true;
5243 }
5244 });
5245
5246 function identFn(value) { return value; }
5247
5248 function ObserverTransform(observable, getValueFn, setValueFn,
5249 dontPassThroughSet) {
5250 this.callback_ = undefined;
5251 this.target_ = undefined;
5252 this.value_ = undefined;
5253 this.observable_ = observable;
5254 this.getValueFn_ = getValueFn || identFn;
5255 this.setValueFn_ = setValueFn || identFn;
5256 // TODO(rafaelw): This is a temporary hack. PolymerExpressions needs this
5257 // at the moment because of a bug in it's dependency tracking.
5258 this.dontPassThroughSet_ = dontPassThroughSet;
5259 }
5260
5261 ObserverTransform.prototype = {
5262 open: function(callback, target) {
5263 this.callback_ = callback;
5264 this.target_ = target;
5265 this.value_ =
5266 this.getValueFn_(this.observable_.open(this.observedCallback_, this));
5267 return this.value_;
5268 },
5269
5270 observedCallback_: function(value) {
5271 value = this.getValueFn_(value);
5272 if (areSameValue(value, this.value_))
5273 return;
5274 var oldValue = this.value_;
5275 this.value_ = value;
5276 this.callback_.call(this.target_, this.value_, oldValue);
5277 },
5278
5279 discardChanges: function() {
5280 this.value_ = this.getValueFn_(this.observable_.discardChanges());
5281 return this.value_;
5282 },
5283
5284 deliver: function() {
5285 return this.observable_.deliver();
5286 },
5287
5288 setValue: function(value) {
5289 value = this.setValueFn_(value);
5290 if (!this.dontPassThroughSet_ && this.observable_.setValue)
5291 return this.observable_.setValue(value);
5292 },
5293
5294 close: function() {
5295 if (this.observable_)
5296 this.observable_.close();
5297 this.callback_ = undefined;
5298 this.target_ = undefined;
5299 this.observable_ = undefined;
5300 this.value_ = undefined;
5301 this.getValueFn_ = undefined;
5302 this.setValueFn_ = undefined;
5303 }
5304 }
5305
5306 var expectedRecordTypes = {
5307 add: true,
5308 update: true,
5309 delete: true
5310 };
5311
5312 function diffObjectFromChangeRecords(object, changeRecords, oldValues) {
5313 var added = {};
5314 var removed = {};
5315
5316 for (var i = 0; i < changeRecords.length; i++) {
5317 var record = changeRecords[i];
5318 if (!expectedRecordTypes[record.type]) {
5319 console.error('Unknown changeRecord type: ' + record.type);
5320 console.error(record);
5321 continue;
5322 }
5323
5324 if (!(record.name in oldValues))
5325 oldValues[record.name] = record.oldValue;
5326
5327 if (record.type == 'update')
5328 continue;
5329
5330 if (record.type == 'add') {
5331 if (record.name in removed)
5332 delete removed[record.name];
5333 else
5334 added[record.name] = true;
5335
5336 continue;
5337 }
5338
5339 // type = 'delete'
5340 if (record.name in added) {
5341 delete added[record.name];
5342 delete oldValues[record.name];
5343 } else {
5344 removed[record.name] = true;
5345 }
5346 }
5347
5348 for (var prop in added)
5349 added[prop] = object[prop];
5350
5351 for (var prop in removed)
5352 removed[prop] = undefined;
5353
5354 var changed = {};
5355 for (var prop in oldValues) {
5356 if (prop in added || prop in removed)
5357 continue;
5358
5359 var newValue = object[prop];
5360 if (oldValues[prop] !== newValue)
5361 changed[prop] = newValue;
5362 }
5363
5364 return {
5365 added: added,
5366 removed: removed,
5367 changed: changed
5368 };
5369 }
5370
5371 function newSplice(index, removed, addedCount) {
5372 return {
5373 index: index,
5374 removed: removed,
5375 addedCount: addedCount
5376 };
5377 }
5378
5379 var EDIT_LEAVE = 0;
5380 var EDIT_UPDATE = 1;
5381 var EDIT_ADD = 2;
5382 var EDIT_DELETE = 3;
5383
5384 function ArraySplice() {}
5385
5386 ArraySplice.prototype = {
5387
5388 // Note: This function is *based* on the computation of the Levenshtein
5389 // "edit" distance. The one change is that "updates" are treated as two
5390 // edits - not one. With Array splices, an update is really a delete
5391 // followed by an add. By retaining this, we optimize for "keeping" the
5392 // maximum array items in the original array. For example:
5393 //
5394 // 'xxxx123' -> '123yyyy'
5395 //
5396 // With 1-edit updates, the shortest path would be just to update all seven
5397 // characters. With 2-edit updates, we delete 4, leave 3, and add 4. This
5398 // leaves the substring '123' intact.
5399 calcEditDistances: function(current, currentStart, currentEnd,
5400 old, oldStart, oldEnd) {
5401 // "Deletion" columns
5402 var rowCount = oldEnd - oldStart + 1;
5403 var columnCount = currentEnd - currentStart + 1;
5404 var distances = new Array(rowCount);
5405
5406 // "Addition" rows. Initialize null column.
5407 for (var i = 0; i < rowCount; i++) {
5408 distances[i] = new Array(columnCount);
5409 distances[i][0] = i;
5410 }
5411
5412 // Initialize null row
5413 for (var j = 0; j < columnCount; j++)
5414 distances[0][j] = j;
5415
5416 for (var i = 1; i < rowCount; i++) {
5417 for (var j = 1; j < columnCount; j++) {
5418 if (this.equals(current[currentStart + j - 1], old[oldStart + i - 1]))
5419 distances[i][j] = distances[i - 1][j - 1];
5420 else {
5421 var north = distances[i - 1][j] + 1;
5422 var west = distances[i][j - 1] + 1;
5423 distances[i][j] = north < west ? north : west;
5424 }
5425 }
5426 }
5427
5428 return distances;
5429 },
5430
5431 // This starts at the final weight, and walks "backward" by finding
5432 // the minimum previous weight recursively until the origin of the weight
5433 // matrix.
5434 spliceOperationsFromEditDistances: function(distances) {
5435 var i = distances.length - 1;
5436 var j = distances[0].length - 1;
5437 var current = distances[i][j];
5438 var edits = [];
5439 while (i > 0 || j > 0) {
5440 if (i == 0) {
5441 edits.push(EDIT_ADD);
5442 j--;
5443 continue;
5444 }
5445 if (j == 0) {
5446 edits.push(EDIT_DELETE);
5447 i--;
5448 continue;
5449 }
5450 var northWest = distances[i - 1][j - 1];
5451 var west = distances[i - 1][j];
5452 var north = distances[i][j - 1];
5453
5454 var min;
5455 if (west < north)
5456 min = west < northWest ? west : northWest;
5457 else
5458 min = north < northWest ? north : northWest;
5459
5460 if (min == northWest) {
5461 if (northWest == current) {
5462 edits.push(EDIT_LEAVE);
5463 } else {
5464 edits.push(EDIT_UPDATE);
5465 current = northWest;
5466 }
5467 i--;
5468 j--;
5469 } else if (min == west) {
5470 edits.push(EDIT_DELETE);
5471 i--;
5472 current = west;
5473 } else {
5474 edits.push(EDIT_ADD);
5475 j--;
5476 current = north;
5477 }
5478 }
5479
5480 edits.reverse();
5481 return edits;
5482 },
5483
5484 /**
5485 * Splice Projection functions:
5486 *
5487 * A splice map is a representation of how a previous array of items
5488 * was transformed into a new array of items. Conceptually it is a list of
5489 * tuples of
5490 *
5491 * <index, removed, addedCount>
5492 *
5493 * which are kept in ascending index order of. The tuple represents that at
5494 * the |index|, |removed| sequence of items were removed, and counting forwa rd
5495 * from |index|, |addedCount| items were added.
5496 */
5497
5498 /**
5499 * Lacking individual splice mutation information, the minimal set of
5500 * splices can be synthesized given the previous state and final state of an
5501 * array. The basic approach is to calculate the edit distance matrix and
5502 * choose the shortest path through it.
5503 *
5504 * Complexity: O(l * p)
5505 * l: The length of the current array
5506 * p: The length of the old array
5507 */
5508 calcSplices: function(current, currentStart, currentEnd,
5509 old, oldStart, oldEnd) {
5510 var prefixCount = 0;
5511 var suffixCount = 0;
5512
5513 var minLength = Math.min(currentEnd - currentStart, oldEnd - oldStart);
5514 if (currentStart == 0 && oldStart == 0)
5515 prefixCount = this.sharedPrefix(current, old, minLength);
5516
5517 if (currentEnd == current.length && oldEnd == old.length)
5518 suffixCount = this.sharedSuffix(current, old, minLength - prefixCount);
5519
5520 currentStart += prefixCount;
5521 oldStart += prefixCount;
5522 currentEnd -= suffixCount;
5523 oldEnd -= suffixCount;
5524
5525 if (currentEnd - currentStart == 0 && oldEnd - oldStart == 0)
5526 return [];
5527
5528 if (currentStart == currentEnd) {
5529 var splice = newSplice(currentStart, [], 0);
5530 while (oldStart < oldEnd)
5531 splice.removed.push(old[oldStart++]);
5532
5533 return [ splice ];
5534 } else if (oldStart == oldEnd)
5535 return [ newSplice(currentStart, [], currentEnd - currentStart) ];
5536
5537 var ops = this.spliceOperationsFromEditDistances(
5538 this.calcEditDistances(current, currentStart, currentEnd,
5539 old, oldStart, oldEnd));
5540
5541 var splice = undefined;
5542 var splices = [];
5543 var index = currentStart;
5544 var oldIndex = oldStart;
5545 for (var i = 0; i < ops.length; i++) {
5546 switch(ops[i]) {
5547 case EDIT_LEAVE:
5548 if (splice) {
5549 splices.push(splice);
5550 splice = undefined;
5551 }
5552
5553 index++;
5554 oldIndex++;
5555 break;
5556 case EDIT_UPDATE:
5557 if (!splice)
5558 splice = newSplice(index, [], 0);
5559
5560 splice.addedCount++;
5561 index++;
5562
5563 splice.removed.push(old[oldIndex]);
5564 oldIndex++;
5565 break;
5566 case EDIT_ADD:
5567 if (!splice)
5568 splice = newSplice(index, [], 0);
5569
5570 splice.addedCount++;
5571 index++;
5572 break;
5573 case EDIT_DELETE:
5574 if (!splice)
5575 splice = newSplice(index, [], 0);
5576
5577 splice.removed.push(old[oldIndex]);
5578 oldIndex++;
5579 break;
5580 }
5581 }
5582
5583 if (splice) {
5584 splices.push(splice);
5585 }
5586 return splices;
5587 },
5588
5589 sharedPrefix: function(current, old, searchLength) {
5590 for (var i = 0; i < searchLength; i++)
5591 if (!this.equals(current[i], old[i]))
5592 return i;
5593 return searchLength;
5594 },
5595
5596 sharedSuffix: function(current, old, searchLength) {
5597 var index1 = current.length;
5598 var index2 = old.length;
5599 var count = 0;
5600 while (count < searchLength && this.equals(current[--index1], old[--index2 ]))
5601 count++;
5602
5603 return count;
5604 },
5605
5606 calculateSplices: function(current, previous) {
5607 return this.calcSplices(current, 0, current.length, previous, 0,
5608 previous.length);
5609 },
5610
5611 equals: function(currentValue, previousValue) {
5612 return currentValue === previousValue;
5613 }
5614 };
5615
5616 var arraySplice = new ArraySplice();
5617
5618 function calcSplices(current, currentStart, currentEnd,
5619 old, oldStart, oldEnd) {
5620 return arraySplice.calcSplices(current, currentStart, currentEnd,
5621 old, oldStart, oldEnd);
5622 }
5623
5624 function intersect(start1, end1, start2, end2) {
5625 // Disjoint
5626 if (end1 < start2 || end2 < start1)
5627 return -1;
5628
5629 // Adjacent
5630 if (end1 == start2 || end2 == start1)
5631 return 0;
5632
5633 // Non-zero intersect, span1 first
5634 if (start1 < start2) {
5635 if (end1 < end2)
5636 return end1 - start2; // Overlap
5637 else
5638 return end2 - start2; // Contained
5639 } else {
5640 // Non-zero intersect, span2 first
5641 if (end2 < end1)
5642 return end2 - start1; // Overlap
5643 else
5644 return end1 - start1; // Contained
5645 }
5646 }
5647
5648 function mergeSplice(splices, index, removed, addedCount) {
5649
5650 var splice = newSplice(index, removed, addedCount);
5651
5652 var inserted = false;
5653 var insertionOffset = 0;
5654
5655 for (var i = 0; i < splices.length; i++) {
5656 var current = splices[i];
5657 current.index += insertionOffset;
5658
5659 if (inserted)
5660 continue;
5661
5662 var intersectCount = intersect(splice.index,
5663 splice.index + splice.removed.length,
5664 current.index,
5665 current.index + current.addedCount);
5666
5667 if (intersectCount >= 0) {
5668 // Merge the two splices
5669
5670 splices.splice(i, 1);
5671 i--;
5672
5673 insertionOffset -= current.addedCount - current.removed.length;
5674
5675 splice.addedCount += current.addedCount - intersectCount;
5676 var deleteCount = splice.removed.length +
5677 current.removed.length - intersectCount;
5678
5679 if (!splice.addedCount && !deleteCount) {
5680 // merged splice is a noop. discard.
5681 inserted = true;
5682 } else {
5683 var removed = current.removed;
5684
5685 if (splice.index < current.index) {
5686 // some prefix of splice.removed is prepended to current.removed.
5687 var prepend = splice.removed.slice(0, current.index - splice.index);
5688 Array.prototype.push.apply(prepend, removed);
5689 removed = prepend;
5690 }
5691
5692 if (splice.index + splice.removed.length > current.index + current.add edCount) {
5693 // some suffix of splice.removed is appended to current.removed.
5694 var append = splice.removed.slice(current.index + current.addedCount - splice.index);
5695 Array.prototype.push.apply(removed, append);
5696 }
5697
5698 splice.removed = removed;
5699 if (current.index < splice.index) {
5700 splice.index = current.index;
5701 }
5702 }
5703 } else if (splice.index < current.index) {
5704 // Insert splice here.
5705
5706 inserted = true;
5707
5708 splices.splice(i, 0, splice);
5709 i++;
5710
5711 var offset = splice.addedCount - splice.removed.length
5712 current.index += offset;
5713 insertionOffset += offset;
5714 }
5715 }
5716
5717 if (!inserted)
5718 splices.push(splice);
5719 }
5720
5721 function createInitialSplices(array, changeRecords) {
5722 var splices = [];
5723
5724 for (var i = 0; i < changeRecords.length; i++) {
5725 var record = changeRecords[i];
5726 switch(record.type) {
5727 case 'splice':
5728 mergeSplice(splices, record.index, record.removed.slice(), record.adde dCount);
5729 break;
5730 case 'add':
5731 case 'update':
5732 case 'delete':
5733 if (!isIndex(record.name))
5734 continue;
5735 var index = toNumber(record.name);
5736 if (index < 0)
5737 continue;
5738 mergeSplice(splices, index, [record.oldValue], 1);
5739 break;
5740 default:
5741 console.error('Unexpected record type: ' + JSON.stringify(record));
5742 break;
5743 }
5744 }
5745
5746 return splices;
5747 }
5748
5749 function projectArraySplices(array, changeRecords) {
5750 var splices = [];
5751
5752 createInitialSplices(array, changeRecords).forEach(function(splice) {
5753 if (splice.addedCount == 1 && splice.removed.length == 1) {
5754 if (splice.removed[0] !== array[splice.index])
5755 splices.push(splice);
5756
5757 return
5758 };
5759
5760 splices = splices.concat(calcSplices(array, splice.index, splice.index + s plice.addedCount,
5761 splice.removed, 0, splice.removed.len gth));
5762 });
5763
5764 return splices;
5765 }
5766
5767 global.Observer = Observer;
5768 global.Observer.runEOM_ = runEOM;
5769 global.Observer.observerSentinel_ = observerSentinel; // for testing.
5770 global.Observer.hasObjectObserve = hasObserve;
5771 global.ArrayObserver = ArrayObserver;
5772 global.ArrayObserver.calculateSplices = function(current, previous) {
5773 return arraySplice.calculateSplices(current, previous);
5774 };
5775
5776 global.ArraySplice = ArraySplice;
5777 global.ObjectObserver = ObjectObserver;
5778 global.PathObserver = PathObserver;
5779 global.CompoundObserver = CompoundObserver;
5780 global.Path = Path;
5781 global.ObserverTransform = ObserverTransform;
5782 })(typeof global !== 'undefined' && global && typeof module !== 'undefined' && m odule ? global : this || window);
5783
5784 // Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
5785 // This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
5786 // The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
5787 // The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
5788 // Code distributed by Google as part of the polymer project is also
5789 // subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
5790
5791 (function(global) {
5792 'use strict';
5793
5794 var filter = Array.prototype.filter.call.bind(Array.prototype.filter);
5795
5796 function getTreeScope(node) {
5797 while (node.parentNode) {
5798 node = node.parentNode;
5799 }
5800
5801 return typeof node.getElementById === 'function' ? node : null;
5802 }
5803
5804 Node.prototype.bind = function(name, observable) {
5805 console.error('Unhandled binding to Node: ', this, name, observable);
5806 };
5807
5808 Node.prototype.bindFinished = function() {};
5809
5810 function updateBindings(node, name, binding) {
5811 var bindings = node.bindings_;
5812 if (!bindings)
5813 bindings = node.bindings_ = {};
5814
5815 if (bindings[name])
5816 binding[name].close();
5817
5818 return bindings[name] = binding;
5819 }
5820
5821 function returnBinding(node, name, binding) {
5822 return binding;
5823 }
5824
5825 function sanitizeValue(value) {
5826 return value == null ? '' : value;
5827 }
5828
5829 function updateText(node, value) {
5830 node.data = sanitizeValue(value);
5831 }
5832
5833 function textBinding(node) {
5834 return function(value) {
5835 return updateText(node, value);
5836 };
5837 }
5838
5839 var maybeUpdateBindings = returnBinding;
5840
5841 Object.defineProperty(Platform, 'enableBindingsReflection', {
5842 get: function() {
5843 return maybeUpdateBindings === updateBindings;
5844 },
5845 set: function(enable) {
5846 maybeUpdateBindings = enable ? updateBindings : returnBinding;
5847 return enable;
5848 },
5849 configurable: true
5850 });
5851
5852 Text.prototype.bind = function(name, value, oneTime) {
5853 if (name !== 'textContent')
5854 return Node.prototype.bind.call(this, name, value, oneTime);
5855
5856 if (oneTime)
5857 return updateText(this, value);
5858
5859 var observable = value;
5860 updateText(this, observable.open(textBinding(this)));
5861 return maybeUpdateBindings(this, name, observable);
5862 }
5863
5864 function updateAttribute(el, name, conditional, value) {
5865 if (conditional) {
5866 if (value)
5867 el.setAttribute(name, '');
5868 else
5869 el.removeAttribute(name);
5870 return;
5871 }
5872
5873 el.setAttribute(name, sanitizeValue(value));
5874 }
5875
5876 function attributeBinding(el, name, conditional) {
5877 return function(value) {
5878 updateAttribute(el, name, conditional, value);
5879 };
5880 }
5881
5882 Element.prototype.bind = function(name, value, oneTime) {
5883 var conditional = name[name.length - 1] == '?';
5884 if (conditional) {
5885 this.removeAttribute(name);
5886 name = name.slice(0, -1);
5887 }
5888
5889 if (oneTime)
5890 return updateAttribute(this, name, conditional, value);
5891
5892
5893 var observable = value;
5894 updateAttribute(this, name, conditional,
5895 observable.open(attributeBinding(this, name, conditional)));
5896
5897 return maybeUpdateBindings(this, name, observable);
5898 };
5899
5900 var checkboxEventType;
5901 (function() {
5902 // Attempt to feature-detect which event (change or click) is fired first
5903 // for checkboxes.
5904 var div = document.createElement('div');
5905 var checkbox = div.appendChild(document.createElement('input'));
5906 checkbox.setAttribute('type', 'checkbox');
5907 var first;
5908 var count = 0;
5909 checkbox.addEventListener('click', function(e) {
5910 count++;
5911 first = first || 'click';
5912 });
5913 checkbox.addEventListener('change', function() {
5914 count++;
5915 first = first || 'change';
5916 });
5917
5918 var event = document.createEvent('MouseEvent');
5919 event.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false,
5920 false, false, false, 0, null);
5921 checkbox.dispatchEvent(event);
5922 // WebKit/Blink don't fire the change event if the element is outside the
5923 // document, so assume 'change' for that case.
5924 checkboxEventType = count == 1 ? 'change' : first;
5925 })();
5926
5927 function getEventForInputType(element) {
5928 switch (element.type) {
5929 case 'checkbox':
5930 return checkboxEventType;
5931 case 'radio':
5932 case 'select-multiple':
5933 case 'select-one':
5934 return 'change';
5935 case 'range':
5936 if (/Trident|MSIE/.test(navigator.userAgent))
5937 return 'change';
5938 default:
5939 return 'input';
5940 }
5941 }
5942
5943 function updateInput(input, property, value, santizeFn) {
5944 input[property] = (santizeFn || sanitizeValue)(value);
5945 }
5946
5947 function inputBinding(input, property, santizeFn) {
5948 return function(value) {
5949 return updateInput(input, property, value, santizeFn);
5950 }
5951 }
5952
5953 function noop() {}
5954
5955 function bindInputEvent(input, property, observable, postEventFn) {
5956 var eventType = getEventForInputType(input);
5957
5958 function eventHandler() {
5959 observable.setValue(input[property]);
5960 observable.discardChanges();
5961 (postEventFn || noop)(input);
5962 Platform.performMicrotaskCheckpoint();
5963 }
5964 input.addEventListener(eventType, eventHandler);
5965
5966 return {
5967 close: function() {
5968 input.removeEventListener(eventType, eventHandler);
5969 observable.close();
5970 },
5971
5972 observable_: observable
5973 }
5974 }
5975
5976 function booleanSanitize(value) {
5977 return Boolean(value);
5978 }
5979
5980 // |element| is assumed to be an HTMLInputElement with |type| == 'radio'.
5981 // Returns an array containing all radio buttons other than |element| that
5982 // have the same |name|, either in the form that |element| belongs to or,
5983 // if no form, in the document tree to which |element| belongs.
5984 //
5985 // This implementation is based upon the HTML spec definition of a
5986 // "radio button group":
5987 // http://www.whatwg.org/specs/web-apps/current-work/multipage/number-state. html#radio-button-group
5988 //
5989 function getAssociatedRadioButtons(element) {
5990 if (element.form) {
5991 return filter(element.form.elements, function(el) {
5992 return el != element &&
5993 el.tagName == 'INPUT' &&
5994 el.type == 'radio' &&
5995 el.name == element.name;
5996 });
5997 } else {
5998 var treeScope = getTreeScope(element);
5999 if (!treeScope)
6000 return [];
6001 var radios = treeScope.querySelectorAll(
6002 'input[type="radio"][name="' + element.name + '"]');
6003 return filter(radios, function(el) {
6004 return el != element && !el.form;
6005 });
6006 }
6007 }
6008
6009 function checkedPostEvent(input) {
6010 // Only the radio button that is getting checked gets an event. We
6011 // therefore find all the associated radio buttons and update their
6012 // check binding manually.
6013 if (input.tagName === 'INPUT' &&
6014 input.type === 'radio') {
6015 getAssociatedRadioButtons(input).forEach(function(radio) {
6016 var checkedBinding = radio.bindings_.checked;
6017 if (checkedBinding) {
6018 // Set the value directly to avoid an infinite call stack.
6019 checkedBinding.observable_.setValue(false);
6020 }
6021 });
6022 }
6023 }
6024
6025 HTMLInputElement.prototype.bind = function(name, value, oneTime) {
6026 if (name !== 'value' && name !== 'checked')
6027 return HTMLElement.prototype.bind.call(this, name, value, oneTime);
6028
6029 this.removeAttribute(name);
6030 var sanitizeFn = name == 'checked' ? booleanSanitize : sanitizeValue;
6031 var postEventFn = name == 'checked' ? checkedPostEvent : noop;
6032
6033 if (oneTime)
6034 return updateInput(this, name, value, sanitizeFn);
6035
6036
6037 var observable = value;
6038 var binding = bindInputEvent(this, name, observable, postEventFn);
6039 updateInput(this, name,
6040 observable.open(inputBinding(this, name, sanitizeFn)),
6041 sanitizeFn);
6042
6043 // Checkboxes may need to update bindings of other checkboxes.
6044 return updateBindings(this, name, binding);
6045 }
6046
6047 HTMLTextAreaElement.prototype.bind = function(name, value, oneTime) {
6048 if (name !== 'value')
6049 return HTMLElement.prototype.bind.call(this, name, value, oneTime);
6050
6051 this.removeAttribute('value');
6052
6053 if (oneTime)
6054 return updateInput(this, 'value', value);
6055
6056 var observable = value;
6057 var binding = bindInputEvent(this, 'value', observable);
6058 updateInput(this, 'value',
6059 observable.open(inputBinding(this, 'value', sanitizeValue)));
6060 return maybeUpdateBindings(this, name, binding);
6061 }
6062
6063 function updateOption(option, value) {
6064 var parentNode = option.parentNode;;
6065 var select;
6066 var selectBinding;
6067 var oldValue;
6068 if (parentNode instanceof HTMLSelectElement &&
6069 parentNode.bindings_ &&
6070 parentNode.bindings_.value) {
6071 select = parentNode;
6072 selectBinding = select.bindings_.value;
6073 oldValue = select.value;
6074 }
6075
6076 option.value = sanitizeValue(value);
6077
6078 if (select && select.value != oldValue) {
6079 selectBinding.observable_.setValue(select.value);
6080 selectBinding.observable_.discardChanges();
6081 Platform.performMicrotaskCheckpoint();
6082 }
6083 }
6084
6085 function optionBinding(option) {
6086 return function(value) {
6087 updateOption(option, value);
6088 }
6089 }
6090
6091 HTMLOptionElement.prototype.bind = function(name, value, oneTime) {
6092 if (name !== 'value')
6093 return HTMLElement.prototype.bind.call(this, name, value, oneTime);
6094
6095 this.removeAttribute('value');
6096
6097 if (oneTime)
6098 return updateOption(this, value);
6099
6100 var observable = value;
6101 var binding = bindInputEvent(this, 'value', observable);
6102 updateOption(this, observable.open(optionBinding(this)));
6103 return maybeUpdateBindings(this, name, binding);
6104 }
6105
6106 HTMLSelectElement.prototype.bind = function(name, value, oneTime) {
6107 if (name === 'selectedindex')
6108 name = 'selectedIndex';
6109
6110 if (name !== 'selectedIndex' && name !== 'value')
6111 return HTMLElement.prototype.bind.call(this, name, value, oneTime);
6112
6113 this.removeAttribute(name);
6114
6115 if (oneTime)
6116 return updateInput(this, name, value);
6117
6118 var observable = value;
6119 var binding = bindInputEvent(this, name, observable);
6120 updateInput(this, name,
6121 observable.open(inputBinding(this, name)));
6122
6123 // Option update events may need to access select bindings.
6124 return updateBindings(this, name, binding);
6125 }
6126 })(this);
6127
6128 // Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
6129 // This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
6130 // The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
6131 // The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
6132 // Code distributed by Google as part of the polymer project is also
6133 // subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
6134
6135 (function(global) {
6136 'use strict';
6137
6138 function assert(v) {
6139 if (!v)
6140 throw new Error('Assertion failed');
6141 }
6142
6143 var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
6144
6145 function getFragmentRoot(node) {
6146 var p;
6147 while (p = node.parentNode) {
6148 node = p;
6149 }
6150
6151 return node;
6152 }
6153
6154 function searchRefId(node, id) {
6155 if (!id)
6156 return;
6157
6158 var ref;
6159 var selector = '#' + id;
6160 while (!ref) {
6161 node = getFragmentRoot(node);
6162
6163 if (node.protoContent_)
6164 ref = node.protoContent_.querySelector(selector);
6165 else if (node.getElementById)
6166 ref = node.getElementById(id);
6167
6168 if (ref || !node.templateCreator_)
6169 break
6170
6171 node = node.templateCreator_;
6172 }
6173
6174 return ref;
6175 }
6176
6177 function getInstanceRoot(node) {
6178 while (node.parentNode) {
6179 node = node.parentNode;
6180 }
6181 return node.templateCreator_ ? node : null;
6182 }
6183
6184 var Map;
6185 if (global.Map && typeof global.Map.prototype.forEach === 'function') {
6186 Map = global.Map;
6187 } else {
6188 Map = function() {
6189 this.keys = [];
6190 this.values = [];
6191 };
6192
6193 Map.prototype = {
6194 set: function(key, value) {
6195 var index = this.keys.indexOf(key);
6196 if (index < 0) {
6197 this.keys.push(key);
6198 this.values.push(value);
6199 } else {
6200 this.values[index] = value;
6201 }
6202 },
6203
6204 get: function(key) {
6205 var index = this.keys.indexOf(key);
6206 if (index < 0)
6207 return;
6208
6209 return this.values[index];
6210 },
6211
6212 delete: function(key, value) {
6213 var index = this.keys.indexOf(key);
6214 if (index < 0)
6215 return false;
6216
6217 this.keys.splice(index, 1);
6218 this.values.splice(index, 1);
6219 return true;
6220 },
6221
6222 forEach: function(f, opt_this) {
6223 for (var i = 0; i < this.keys.length; i++)
6224 f.call(opt_this || this, this.values[i], this.keys[i], this);
6225 }
6226 };
6227 }
6228
6229 // JScript does not have __proto__. We wrap all object literals with
6230 // createObject which uses Object.create, Object.defineProperty and
6231 // Object.getOwnPropertyDescriptor to create a new object that does the exact
6232 // same thing. The main downside to this solution is that we have to extract
6233 // all those property descriptors for IE.
6234 var createObject = ('__proto__' in {}) ?
6235 function(obj) { return obj; } :
6236 function(obj) {
6237 var proto = obj.__proto__;
6238 if (!proto)
6239 return obj;
6240 var newObject = Object.create(proto);
6241 Object.getOwnPropertyNames(obj).forEach(function(name) {
6242 Object.defineProperty(newObject, name,
6243 Object.getOwnPropertyDescriptor(obj, name));
6244 });
6245 return newObject;
6246 };
6247
6248 // IE does not support have Document.prototype.contains.
6249 if (typeof document.contains != 'function') {
6250 Document.prototype.contains = function(node) {
6251 if (node === this || node.parentNode === this)
6252 return true;
6253 return this.documentElement.contains(node);
6254 }
6255 }
6256
6257 var BIND = 'bind';
6258 var REPEAT = 'repeat';
6259 var IF = 'if';
6260
6261 var templateAttributeDirectives = {
6262 'template': true,
6263 'repeat': true,
6264 'bind': true,
6265 'ref': true
6266 };
6267
6268 var semanticTemplateElements = {
6269 'THEAD': true,
6270 'TBODY': true,
6271 'TFOOT': true,
6272 'TH': true,
6273 'TR': true,
6274 'TD': true,
6275 'COLGROUP': true,
6276 'COL': true,
6277 'CAPTION': true,
6278 'OPTION': true,
6279 'OPTGROUP': true
6280 };
6281
6282 var hasTemplateElement = typeof HTMLTemplateElement !== 'undefined';
6283 if (hasTemplateElement) {
6284 // TODO(rafaelw): Remove when fix for
6285 // https://codereview.chromium.org/164803002/
6286 // makes it to Chrome release.
6287 (function() {
6288 var t = document.createElement('template');
6289 var d = t.content.ownerDocument;
6290 var html = d.appendChild(d.createElement('html'));
6291 var head = html.appendChild(d.createElement('head'));
6292 var base = d.createElement('base');
6293 base.href = document.baseURI;
6294 head.appendChild(base);
6295 })();
6296 }
6297
6298 var allTemplatesSelectors = 'template, ' +
6299 Object.keys(semanticTemplateElements).map(function(tagName) {
6300 return tagName.toLowerCase() + '[template]';
6301 }).join(', ');
6302
6303 function isSVGTemplate(el) {
6304 return el.tagName == 'template' &&
6305 el.namespaceURI == 'http://www.w3.org/2000/svg';
6306 }
6307
6308 function isHTMLTemplate(el) {
6309 return el.tagName == 'TEMPLATE' &&
6310 el.namespaceURI == 'http://www.w3.org/1999/xhtml';
6311 }
6312
6313 function isAttributeTemplate(el) {
6314 return Boolean(semanticTemplateElements[el.tagName] &&
6315 el.hasAttribute('template'));
6316 }
6317
6318 function isTemplate(el) {
6319 if (el.isTemplate_ === undefined)
6320 el.isTemplate_ = el.tagName == 'TEMPLATE' || isAttributeTemplate(el);
6321
6322 return el.isTemplate_;
6323 }
6324
6325 // FIXME: Observe templates being added/removed from documents
6326 // FIXME: Expose imperative API to decorate and observe templates in
6327 // "disconnected tress" (e.g. ShadowRoot)
6328 document.addEventListener('DOMContentLoaded', function(e) {
6329 bootstrapTemplatesRecursivelyFrom(document);
6330 // FIXME: Is this needed? Seems like it shouldn't be.
6331 Platform.performMicrotaskCheckpoint();
6332 }, false);
6333
6334 function forAllTemplatesFrom(node, fn) {
6335 var subTemplates = node.querySelectorAll(allTemplatesSelectors);
6336
6337 if (isTemplate(node))
6338 fn(node)
6339 forEach(subTemplates, fn);
6340 }
6341
6342 function bootstrapTemplatesRecursivelyFrom(node) {
6343 function bootstrap(template) {
6344 if (!HTMLTemplateElement.decorate(template))
6345 bootstrapTemplatesRecursivelyFrom(template.content);
6346 }
6347
6348 forAllTemplatesFrom(node, bootstrap);
6349 }
6350
6351 if (!hasTemplateElement) {
6352 /**
6353 * This represents a <template> element.
6354 * @constructor
6355 * @extends {HTMLElement}
6356 */
6357 global.HTMLTemplateElement = function() {
6358 throw TypeError('Illegal constructor');
6359 };
6360 }
6361
6362 var hasProto = '__proto__' in {};
6363
6364 function mixin(to, from) {
6365 Object.getOwnPropertyNames(from).forEach(function(name) {
6366 Object.defineProperty(to, name,
6367 Object.getOwnPropertyDescriptor(from, name));
6368 });
6369 }
6370
6371 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html# dfn-template-contents-owner
6372 function getOrCreateTemplateContentsOwner(template) {
6373 var doc = template.ownerDocument
6374 if (!doc.defaultView)
6375 return doc;
6376 var d = doc.templateContentsOwner_;
6377 if (!d) {
6378 // TODO(arv): This should either be a Document or HTMLDocument depending
6379 // on doc.
6380 d = doc.implementation.createHTMLDocument('');
6381 while (d.lastChild) {
6382 d.removeChild(d.lastChild);
6383 }
6384 doc.templateContentsOwner_ = d;
6385 }
6386 return d;
6387 }
6388
6389 function getTemplateStagingDocument(template) {
6390 if (!template.stagingDocument_) {
6391 var owner = template.ownerDocument;
6392 if (!owner.stagingDocument_) {
6393 owner.stagingDocument_ = owner.implementation.createHTMLDocument('');
6394 owner.stagingDocument_.isStagingDocument = true;
6395 // TODO(rafaelw): Remove when fix for
6396 // https://codereview.chromium.org/164803002/
6397 // makes it to Chrome release.
6398 var base = owner.stagingDocument_.createElement('base');
6399 base.href = document.baseURI;
6400 owner.stagingDocument_.head.appendChild(base);
6401
6402 owner.stagingDocument_.stagingDocument_ = owner.stagingDocument_;
6403 }
6404
6405 template.stagingDocument_ = owner.stagingDocument_;
6406 }
6407
6408 return template.stagingDocument_;
6409 }
6410
6411 // For non-template browsers, the parser will disallow <template> in certain
6412 // locations, so we allow "attribute templates" which combine the template
6413 // element with the top-level container node of the content, e.g.
6414 //
6415 // <tr template repeat="{{ foo }}"" class="bar"><td>Bar</td></tr>
6416 //
6417 // becomes
6418 //
6419 // <template repeat="{{ foo }}">
6420 // + #document-fragment
6421 // + <tr class="bar">
6422 // + <td>Bar</td>
6423 //
6424 function extractTemplateFromAttributeTemplate(el) {
6425 var template = el.ownerDocument.createElement('template');
6426 el.parentNode.insertBefore(template, el);
6427
6428 var attribs = el.attributes;
6429 var count = attribs.length;
6430 while (count-- > 0) {
6431 var attrib = attribs[count];
6432 if (templateAttributeDirectives[attrib.name]) {
6433 if (attrib.name !== 'template')
6434 template.setAttribute(attrib.name, attrib.value);
6435 el.removeAttribute(attrib.name);
6436 }
6437 }
6438
6439 return template;
6440 }
6441
6442 function extractTemplateFromSVGTemplate(el) {
6443 var template = el.ownerDocument.createElement('template');
6444 el.parentNode.insertBefore(template, el);
6445
6446 var attribs = el.attributes;
6447 var count = attribs.length;
6448 while (count-- > 0) {
6449 var attrib = attribs[count];
6450 template.setAttribute(attrib.name, attrib.value);
6451 el.removeAttribute(attrib.name);
6452 }
6453
6454 el.parentNode.removeChild(el);
6455 return template;
6456 }
6457
6458 function liftNonNativeTemplateChildrenIntoContent(template, el, useRoot) {
6459 var content = template.content;
6460 if (useRoot) {
6461 content.appendChild(el);
6462 return;
6463 }
6464
6465 var child;
6466 while (child = el.firstChild) {
6467 content.appendChild(child);
6468 }
6469 }
6470
6471 var templateObserver;
6472 if (typeof MutationObserver == 'function') {
6473 templateObserver = new MutationObserver(function(records) {
6474 for (var i = 0; i < records.length; i++) {
6475 records[i].target.refChanged_();
6476 }
6477 });
6478 }
6479
6480 /**
6481 * Ensures proper API and content model for template elements.
6482 * @param {HTMLTemplateElement} opt_instanceRef The template element which
6483 * |el| template element will return as the value of its ref(), and whose
6484 * content will be used as source when createInstance() is invoked.
6485 */
6486 HTMLTemplateElement.decorate = function(el, opt_instanceRef) {
6487 if (el.templateIsDecorated_)
6488 return false;
6489
6490 var templateElement = el;
6491 templateElement.templateIsDecorated_ = true;
6492
6493 var isNativeHTMLTemplate = isHTMLTemplate(templateElement) &&
6494 hasTemplateElement;
6495 var bootstrapContents = isNativeHTMLTemplate;
6496 var liftContents = !isNativeHTMLTemplate;
6497 var liftRoot = false;
6498
6499 if (!isNativeHTMLTemplate) {
6500 if (isAttributeTemplate(templateElement)) {
6501 assert(!opt_instanceRef);
6502 templateElement = extractTemplateFromAttributeTemplate(el);
6503 templateElement.templateIsDecorated_ = true;
6504 isNativeHTMLTemplate = hasTemplateElement;
6505 liftRoot = true;
6506 } else if (isSVGTemplate(templateElement)) {
6507 templateElement = extractTemplateFromSVGTemplate(el);
6508 templateElement.templateIsDecorated_ = true;
6509 isNativeHTMLTemplate = hasTemplateElement;
6510 }
6511 }
6512
6513 if (!isNativeHTMLTemplate) {
6514 fixTemplateElementPrototype(templateElement);
6515 var doc = getOrCreateTemplateContentsOwner(templateElement);
6516 templateElement.content_ = doc.createDocumentFragment();
6517 }
6518
6519 if (opt_instanceRef) {
6520 // template is contained within an instance, its direct content must be
6521 // empty
6522 templateElement.instanceRef_ = opt_instanceRef;
6523 } else if (liftContents) {
6524 liftNonNativeTemplateChildrenIntoContent(templateElement,
6525 el,
6526 liftRoot);
6527 } else if (bootstrapContents) {
6528 bootstrapTemplatesRecursivelyFrom(templateElement.content);
6529 }
6530
6531 return true;
6532 };
6533
6534 // TODO(rafaelw): This used to decorate recursively all templates from a given
6535 // node. This happens by default on 'DOMContentLoaded', but may be needed
6536 // in subtrees not descendent from document (e.g. ShadowRoot).
6537 // Review whether this is the right public API.
6538 HTMLTemplateElement.bootstrap = bootstrapTemplatesRecursivelyFrom;
6539
6540 var htmlElement = global.HTMLUnknownElement || HTMLElement;
6541
6542 var contentDescriptor = {
6543 get: function() {
6544 return this.content_;
6545 },
6546 enumerable: true,
6547 configurable: true
6548 };
6549
6550 if (!hasTemplateElement) {
6551 // Gecko is more picky with the prototype than WebKit. Make sure to use the
6552 // same prototype as created in the constructor.
6553 HTMLTemplateElement.prototype = Object.create(htmlElement.prototype);
6554
6555 Object.defineProperty(HTMLTemplateElement.prototype, 'content',
6556 contentDescriptor);
6557 }
6558
6559 function fixTemplateElementPrototype(el) {
6560 if (hasProto)
6561 el.__proto__ = HTMLTemplateElement.prototype;
6562 else
6563 mixin(el, HTMLTemplateElement.prototype);
6564 }
6565
6566 function ensureSetModelScheduled(template) {
6567 if (!template.setModelFn_) {
6568 template.setModelFn_ = function() {
6569 template.setModelFnScheduled_ = false;
6570 var map = getBindings(template,
6571 template.delegate_ && template.delegate_.prepareBinding);
6572 processBindings(template, map, template.model_);
6573 };
6574 }
6575
6576 if (!template.setModelFnScheduled_) {
6577 template.setModelFnScheduled_ = true;
6578 Observer.runEOM_(template.setModelFn_);
6579 }
6580 }
6581
6582 mixin(HTMLTemplateElement.prototype, {
6583 bind: function(name, value, oneTime) {
6584 if (name != 'ref')
6585 return Element.prototype.bind.call(this, name, value, oneTime);
6586
6587 var self = this;
6588 var ref = oneTime ? value : value.open(function(ref) {
6589 self.setAttribute('ref', ref);
6590 self.refChanged_();
6591 });
6592
6593 this.setAttribute('ref', ref);
6594 this.refChanged_();
6595 if (oneTime)
6596 return;
6597
6598 if (!this.bindings_) {
6599 this.bindings_ = { ref: value };
6600 } else {
6601 this.bindings_.ref = value;
6602 }
6603
6604 return value;
6605 },
6606
6607 processBindingDirectives_: function(directives) {
6608 if (this.iterator_)
6609 this.iterator_.closeDeps();
6610
6611 if (!directives.if && !directives.bind && !directives.repeat) {
6612 if (this.iterator_) {
6613 this.iterator_.close();
6614 this.iterator_ = undefined;
6615 }
6616
6617 return;
6618 }
6619
6620 if (!this.iterator_) {
6621 this.iterator_ = new TemplateIterator(this);
6622 }
6623
6624 this.iterator_.updateDependencies(directives, this.model_);
6625
6626 if (templateObserver) {
6627 templateObserver.observe(this, { attributes: true,
6628 attributeFilter: ['ref'] });
6629 }
6630
6631 return this.iterator_;
6632 },
6633
6634 createInstance: function(model, bindingDelegate, delegate_) {
6635 if (bindingDelegate)
6636 delegate_ = this.newDelegate_(bindingDelegate);
6637 else if (!delegate_)
6638 delegate_ = this.delegate_;
6639
6640 if (!this.refContent_)
6641 this.refContent_ = this.ref_.content;
6642 var content = this.refContent_;
6643 if (content.firstChild === null)
6644 return emptyInstance;
6645
6646 var map = getInstanceBindingMap(content, delegate_);
6647 var stagingDocument = getTemplateStagingDocument(this);
6648 var instance = stagingDocument.createDocumentFragment();
6649 instance.templateCreator_ = this;
6650 instance.protoContent_ = content;
6651 instance.bindings_ = [];
6652 instance.terminator_ = null;
6653 var instanceRecord = instance.templateInstance_ = {
6654 firstNode: null,
6655 lastNode: null,
6656 model: model
6657 };
6658
6659 var i = 0;
6660 var collectTerminator = false;
6661 for (var child = content.firstChild; child; child = child.nextSibling) {
6662 // The terminator of the instance is the clone of the last child of the
6663 // content. If the last child is an active template, it may produce
6664 // instances as a result of production, so simply collecting the last
6665 // child of the instance after it has finished producing may be wrong.
6666 if (child.nextSibling === null)
6667 collectTerminator = true;
6668
6669 var clone = cloneAndBindInstance(child, instance, stagingDocument,
6670 map.children[i++],
6671 model,
6672 delegate_,
6673 instance.bindings_);
6674 clone.templateInstance_ = instanceRecord;
6675 if (collectTerminator)
6676 instance.terminator_ = clone;
6677 }
6678
6679 instanceRecord.firstNode = instance.firstChild;
6680 instanceRecord.lastNode = instance.lastChild;
6681 instance.templateCreator_ = undefined;
6682 instance.protoContent_ = undefined;
6683 return instance;
6684 },
6685
6686 get model() {
6687 return this.model_;
6688 },
6689
6690 set model(model) {
6691 this.model_ = model;
6692 ensureSetModelScheduled(this);
6693 },
6694
6695 get bindingDelegate() {
6696 return this.delegate_ && this.delegate_.raw;
6697 },
6698
6699 refChanged_: function() {
6700 if (!this.iterator_ || this.refContent_ === this.ref_.content)
6701 return;
6702
6703 this.refContent_ = undefined;
6704 this.iterator_.valueChanged();
6705 this.iterator_.updateIteratedValue(this.iterator_.getUpdatedValue());
6706 },
6707
6708 clear: function() {
6709 this.model_ = undefined;
6710 this.delegate_ = undefined;
6711 if (this.bindings_ && this.bindings_.ref)
6712 this.bindings_.ref.close()
6713 this.refContent_ = undefined;
6714 if (!this.iterator_)
6715 return;
6716 this.iterator_.valueChanged();
6717 this.iterator_.close()
6718 this.iterator_ = undefined;
6719 },
6720
6721 setDelegate_: function(delegate) {
6722 this.delegate_ = delegate;
6723 this.bindingMap_ = undefined;
6724 if (this.iterator_) {
6725 this.iterator_.instancePositionChangedFn_ = undefined;
6726 this.iterator_.instanceModelFn_ = undefined;
6727 }
6728 },
6729
6730 newDelegate_: function(bindingDelegate) {
6731 if (!bindingDelegate)
6732 return;
6733
6734 function delegateFn(name) {
6735 var fn = bindingDelegate && bindingDelegate[name];
6736 if (typeof fn != 'function')
6737 return;
6738
6739 return function() {
6740 return fn.apply(bindingDelegate, arguments);
6741 };
6742 }
6743
6744 return {
6745 bindingMaps: {},
6746 raw: bindingDelegate,
6747 prepareBinding: delegateFn('prepareBinding'),
6748 prepareInstanceModel: delegateFn('prepareInstanceModel'),
6749 prepareInstancePositionChanged:
6750 delegateFn('prepareInstancePositionChanged')
6751 };
6752 },
6753
6754 set bindingDelegate(bindingDelegate) {
6755 if (this.delegate_) {
6756 throw Error('Template must be cleared before a new bindingDelegate ' +
6757 'can be assigned');
6758 }
6759
6760 this.setDelegate_(this.newDelegate_(bindingDelegate));
6761 },
6762
6763 get ref_() {
6764 var ref = searchRefId(this, this.getAttribute('ref'));
6765 if (!ref)
6766 ref = this.instanceRef_;
6767
6768 if (!ref)
6769 return this;
6770
6771 var nextRef = ref.ref_;
6772 return nextRef ? nextRef : ref;
6773 }
6774 });
6775
6776 // Returns
6777 // a) undefined if there are no mustaches.
6778 // b) [TEXT, (ONE_TIME?, PATH, DELEGATE_FN, TEXT)+] if there is at least one mustache.
6779 function parseMustaches(s, name, node, prepareBindingFn) {
6780 if (!s || !s.length)
6781 return;
6782
6783 var tokens;
6784 var length = s.length;
6785 var startIndex = 0, lastIndex = 0, endIndex = 0;
6786 var onlyOneTime = true;
6787 while (lastIndex < length) {
6788 var startIndex = s.indexOf('{{', lastIndex);
6789 var oneTimeStart = s.indexOf('[[', lastIndex);
6790 var oneTime = false;
6791 var terminator = '}}';
6792
6793 if (oneTimeStart >= 0 &&
6794 (startIndex < 0 || oneTimeStart < startIndex)) {
6795 startIndex = oneTimeStart;
6796 oneTime = true;
6797 terminator = ']]';
6798 }
6799
6800 endIndex = startIndex < 0 ? -1 : s.indexOf(terminator, startIndex + 2);
6801
6802 if (endIndex < 0) {
6803 if (!tokens)
6804 return;
6805
6806 tokens.push(s.slice(lastIndex)); // TEXT
6807 break;
6808 }
6809
6810 tokens = tokens || [];
6811 tokens.push(s.slice(lastIndex, startIndex)); // TEXT
6812 var pathString = s.slice(startIndex + 2, endIndex).trim();
6813 tokens.push(oneTime); // ONE_TIME?
6814 onlyOneTime = onlyOneTime && oneTime;
6815 var delegateFn = prepareBindingFn &&
6816 prepareBindingFn(pathString, name, node);
6817 // Don't try to parse the expression if there's a prepareBinding function
6818 if (delegateFn == null) {
6819 tokens.push(Path.get(pathString)); // PATH
6820 } else {
6821 tokens.push(null);
6822 }
6823 tokens.push(delegateFn); // DELEGATE_FN
6824 lastIndex = endIndex + 2;
6825 }
6826
6827 if (lastIndex === length)
6828 tokens.push(''); // TEXT
6829
6830 tokens.hasOnePath = tokens.length === 5;
6831 tokens.isSimplePath = tokens.hasOnePath &&
6832 tokens[0] == '' &&
6833 tokens[4] == '';
6834 tokens.onlyOneTime = onlyOneTime;
6835
6836 tokens.combinator = function(values) {
6837 var newValue = tokens[0];
6838
6839 for (var i = 1; i < tokens.length; i += 4) {
6840 var value = tokens.hasOnePath ? values : values[(i - 1) / 4];
6841 if (value !== undefined)
6842 newValue += value;
6843 newValue += tokens[i + 3];
6844 }
6845
6846 return newValue;
6847 }
6848
6849 return tokens;
6850 };
6851
6852 function processOneTimeBinding(name, tokens, node, model) {
6853 if (tokens.hasOnePath) {
6854 var delegateFn = tokens[3];
6855 var value = delegateFn ? delegateFn(model, node, true) :
6856 tokens[2].getValueFrom(model);
6857 return tokens.isSimplePath ? value : tokens.combinator(value);
6858 }
6859
6860 var values = [];
6861 for (var i = 1; i < tokens.length; i += 4) {
6862 var delegateFn = tokens[i + 2];
6863 values[(i - 1) / 4] = delegateFn ? delegateFn(model, node) :
6864 tokens[i + 1].getValueFrom(model);
6865 }
6866
6867 return tokens.combinator(values);
6868 }
6869
6870 function processSinglePathBinding(name, tokens, node, model) {
6871 var delegateFn = tokens[3];
6872 var observer = delegateFn ? delegateFn(model, node, false) :
6873 new PathObserver(model, tokens[2]);
6874
6875 return tokens.isSimplePath ? observer :
6876 new ObserverTransform(observer, tokens.combinator);
6877 }
6878
6879 function processBinding(name, tokens, node, model) {
6880 if (tokens.onlyOneTime)
6881 return processOneTimeBinding(name, tokens, node, model);
6882
6883 if (tokens.hasOnePath)
6884 return processSinglePathBinding(name, tokens, node, model);
6885
6886 var observer = new CompoundObserver();
6887
6888 for (var i = 1; i < tokens.length; i += 4) {
6889 var oneTime = tokens[i];
6890 var delegateFn = tokens[i + 2];
6891
6892 if (delegateFn) {
6893 var value = delegateFn(model, node, oneTime);
6894 if (oneTime)
6895 observer.addPath(value)
6896 else
6897 observer.addObserver(value);
6898 continue;
6899 }
6900
6901 var path = tokens[i + 1];
6902 if (oneTime)
6903 observer.addPath(path.getValueFrom(model))
6904 else
6905 observer.addPath(model, path);
6906 }
6907
6908 return new ObserverTransform(observer, tokens.combinator);
6909 }
6910
6911 function processBindings(node, bindings, model, instanceBindings) {
6912 for (var i = 0; i < bindings.length; i += 2) {
6913 var name = bindings[i]
6914 var tokens = bindings[i + 1];
6915 var value = processBinding(name, tokens, node, model);
6916 var binding = node.bind(name, value, tokens.onlyOneTime);
6917 if (binding && instanceBindings)
6918 instanceBindings.push(binding);
6919 }
6920
6921 node.bindFinished();
6922 if (!bindings.isTemplate)
6923 return;
6924
6925 node.model_ = model;
6926 var iter = node.processBindingDirectives_(bindings);
6927 if (instanceBindings && iter)
6928 instanceBindings.push(iter);
6929 }
6930
6931 function parseWithDefault(el, name, prepareBindingFn) {
6932 var v = el.getAttribute(name);
6933 return parseMustaches(v == '' ? '{{}}' : v, name, el, prepareBindingFn);
6934 }
6935
6936 function parseAttributeBindings(element, prepareBindingFn) {
6937 assert(element);
6938
6939 var bindings = [];
6940 var ifFound = false;
6941 var bindFound = false;
6942
6943 for (var i = 0; i < element.attributes.length; i++) {
6944 var attr = element.attributes[i];
6945 var name = attr.name;
6946 var value = attr.value;
6947
6948 // Allow bindings expressed in attributes to be prefixed with underbars.
6949 // We do this to allow correct semantics for browsers that don't implement
6950 // <template> where certain attributes might trigger side-effects -- and
6951 // for IE which sanitizes certain attributes, disallowing mustache
6952 // replacements in their text.
6953 while (name[0] === '_') {
6954 name = name.substring(1);
6955 }
6956
6957 if (isTemplate(element) &&
6958 (name === IF || name === BIND || name === REPEAT)) {
6959 continue;
6960 }
6961
6962 var tokens = parseMustaches(value, name, element,
6963 prepareBindingFn);
6964 if (!tokens)
6965 continue;
6966
6967 bindings.push(name, tokens);
6968 }
6969
6970 if (isTemplate(element)) {
6971 bindings.isTemplate = true;
6972 bindings.if = parseWithDefault(element, IF, prepareBindingFn);
6973 bindings.bind = parseWithDefault(element, BIND, prepareBindingFn);
6974 bindings.repeat = parseWithDefault(element, REPEAT, prepareBindingFn);
6975
6976 if (bindings.if && !bindings.bind && !bindings.repeat)
6977 bindings.bind = parseMustaches('{{}}', BIND, element, prepareBindingFn);
6978 }
6979
6980 return bindings;
6981 }
6982
6983 function getBindings(node, prepareBindingFn) {
6984 if (node.nodeType === Node.ELEMENT_NODE)
6985 return parseAttributeBindings(node, prepareBindingFn);
6986
6987 if (node.nodeType === Node.TEXT_NODE) {
6988 var tokens = parseMustaches(node.data, 'textContent', node,
6989 prepareBindingFn);
6990 if (tokens)
6991 return ['textContent', tokens];
6992 }
6993
6994 return [];
6995 }
6996
6997 function cloneAndBindInstance(node, parent, stagingDocument, bindings, model,
6998 delegate,
6999 instanceBindings,
7000 instanceRecord) {
7001 var clone = parent.appendChild(stagingDocument.importNode(node, false));
7002
7003 var i = 0;
7004 for (var child = node.firstChild; child; child = child.nextSibling) {
7005 cloneAndBindInstance(child, clone, stagingDocument,
7006 bindings.children[i++],
7007 model,
7008 delegate,
7009 instanceBindings);
7010 }
7011
7012 if (bindings.isTemplate) {
7013 HTMLTemplateElement.decorate(clone, node);
7014 if (delegate)
7015 clone.setDelegate_(delegate);
7016 }
7017
7018 processBindings(clone, bindings, model, instanceBindings);
7019 return clone;
7020 }
7021
7022 function createInstanceBindingMap(node, prepareBindingFn) {
7023 var map = getBindings(node, prepareBindingFn);
7024 map.children = {};
7025 var index = 0;
7026 for (var child = node.firstChild; child; child = child.nextSibling) {
7027 map.children[index++] = createInstanceBindingMap(child, prepareBindingFn);
7028 }
7029
7030 return map;
7031 }
7032
7033 var contentUidCounter = 1;
7034
7035 // TODO(rafaelw): Setup a MutationObserver on content which clears the id
7036 // so that bindingMaps regenerate when the template.content changes.
7037 function getContentUid(content) {
7038 var id = content.id_;
7039 if (!id)
7040 id = content.id_ = contentUidCounter++;
7041 return id;
7042 }
7043
7044 // Each delegate is associated with a set of bindingMaps, one for each
7045 // content which may be used by a template. The intent is that each binding
7046 // delegate gets the opportunity to prepare the instance (via the prepare*
7047 // delegate calls) once across all uses.
7048 // TODO(rafaelw): Separate out the parse map from the binding map. In the
7049 // current implementation, if two delegates need a binding map for the same
7050 // content, the second will have to reparse.
7051 function getInstanceBindingMap(content, delegate_) {
7052 var contentId = getContentUid(content);
7053 if (delegate_) {
7054 var map = delegate_.bindingMaps[contentId];
7055 if (!map) {
7056 map = delegate_.bindingMaps[contentId] =
7057 createInstanceBindingMap(content, delegate_.prepareBinding) || [];
7058 }
7059 return map;
7060 }
7061
7062 var map = content.bindingMap_;
7063 if (!map) {
7064 map = content.bindingMap_ =
7065 createInstanceBindingMap(content, undefined) || [];
7066 }
7067 return map;
7068 }
7069
7070 Object.defineProperty(Node.prototype, 'templateInstance', {
7071 get: function() {
7072 var instance = this.templateInstance_;
7073 return instance ? instance :
7074 (this.parentNode ? this.parentNode.templateInstance : undefined);
7075 }
7076 });
7077
7078 var emptyInstance = document.createDocumentFragment();
7079 emptyInstance.bindings_ = [];
7080 emptyInstance.terminator_ = null;
7081
7082 function TemplateIterator(templateElement) {
7083 this.closed = false;
7084 this.templateElement_ = templateElement;
7085 this.instances = [];
7086 this.deps = undefined;
7087 this.iteratedValue = [];
7088 this.presentValue = undefined;
7089 this.arrayObserver = undefined;
7090 }
7091
7092 TemplateIterator.prototype = {
7093 closeDeps: function() {
7094 var deps = this.deps;
7095 if (deps) {
7096 if (deps.ifOneTime === false)
7097 deps.ifValue.close();
7098 if (deps.oneTime === false)
7099 deps.value.close();
7100 }
7101 },
7102
7103 updateDependencies: function(directives, model) {
7104 this.closeDeps();
7105
7106 var deps = this.deps = {};
7107 var template = this.templateElement_;
7108
7109 var ifValue = true;
7110 if (directives.if) {
7111 deps.hasIf = true;
7112 deps.ifOneTime = directives.if.onlyOneTime;
7113 deps.ifValue = processBinding(IF, directives.if, template, model);
7114
7115 ifValue = deps.ifValue;
7116
7117 // oneTime if & predicate is false. nothing else to do.
7118 if (deps.ifOneTime && !ifValue) {
7119 this.valueChanged();
7120 return;
7121 }
7122
7123 if (!deps.ifOneTime)
7124 ifValue = ifValue.open(this.updateIfValue, this);
7125 }
7126
7127 if (directives.repeat) {
7128 deps.repeat = true;
7129 deps.oneTime = directives.repeat.onlyOneTime;
7130 deps.value = processBinding(REPEAT, directives.repeat, template, model);
7131 } else {
7132 deps.repeat = false;
7133 deps.oneTime = directives.bind.onlyOneTime;
7134 deps.value = processBinding(BIND, directives.bind, template, model);
7135 }
7136
7137 var value = deps.value;
7138 if (!deps.oneTime)
7139 value = value.open(this.updateIteratedValue, this);
7140
7141 if (!ifValue) {
7142 this.valueChanged();
7143 return;
7144 }
7145
7146 this.updateValue(value);
7147 },
7148
7149 /**
7150 * Gets the updated value of the bind/repeat. This can potentially call
7151 * user code (if a bindingDelegate is set up) so we try to avoid it if we
7152 * already have the value in hand (from Observer.open).
7153 */
7154 getUpdatedValue: function() {
7155 var value = this.deps.value;
7156 if (!this.deps.oneTime)
7157 value = value.discardChanges();
7158 return value;
7159 },
7160
7161 updateIfValue: function(ifValue) {
7162 if (!ifValue) {
7163 this.valueChanged();
7164 return;
7165 }
7166
7167 this.updateValue(this.getUpdatedValue());
7168 },
7169
7170 updateIteratedValue: function(value) {
7171 if (this.deps.hasIf) {
7172 var ifValue = this.deps.ifValue;
7173 if (!this.deps.ifOneTime)
7174 ifValue = ifValue.discardChanges();
7175 if (!ifValue) {
7176 this.valueChanged();
7177 return;
7178 }
7179 }
7180
7181 this.updateValue(value);
7182 },
7183
7184 updateValue: function(value) {
7185 if (!this.deps.repeat)
7186 value = [value];
7187 var observe = this.deps.repeat &&
7188 !this.deps.oneTime &&
7189 Array.isArray(value);
7190 this.valueChanged(value, observe);
7191 },
7192
7193 valueChanged: function(value, observeValue) {
7194 if (!Array.isArray(value))
7195 value = [];
7196
7197 if (value === this.iteratedValue)
7198 return;
7199
7200 this.unobserve();
7201 this.presentValue = value;
7202 if (observeValue) {
7203 this.arrayObserver = new ArrayObserver(this.presentValue);
7204 this.arrayObserver.open(this.handleSplices, this);
7205 }
7206
7207 this.handleSplices(ArrayObserver.calculateSplices(this.presentValue,
7208 this.iteratedValue));
7209 },
7210
7211 getLastInstanceNode: function(index) {
7212 if (index == -1)
7213 return this.templateElement_;
7214 var instance = this.instances[index];
7215 var terminator = instance.terminator_;
7216 if (!terminator)
7217 return this.getLastInstanceNode(index - 1);
7218
7219 if (terminator.nodeType !== Node.ELEMENT_NODE ||
7220 this.templateElement_ === terminator) {
7221 return terminator;
7222 }
7223
7224 var subtemplateIterator = terminator.iterator_;
7225 if (!subtemplateIterator)
7226 return terminator;
7227
7228 return subtemplateIterator.getLastTemplateNode();
7229 },
7230
7231 getLastTemplateNode: function() {
7232 return this.getLastInstanceNode(this.instances.length - 1);
7233 },
7234
7235 insertInstanceAt: function(index, fragment) {
7236 var previousInstanceLast = this.getLastInstanceNode(index - 1);
7237 var parent = this.templateElement_.parentNode;
7238 this.instances.splice(index, 0, fragment);
7239
7240 parent.insertBefore(fragment, previousInstanceLast.nextSibling);
7241 },
7242
7243 extractInstanceAt: function(index) {
7244 var previousInstanceLast = this.getLastInstanceNode(index - 1);
7245 var lastNode = this.getLastInstanceNode(index);
7246 var parent = this.templateElement_.parentNode;
7247 var instance = this.instances.splice(index, 1)[0];
7248
7249 while (lastNode !== previousInstanceLast) {
7250 var node = previousInstanceLast.nextSibling;
7251 if (node == lastNode)
7252 lastNode = previousInstanceLast;
7253
7254 instance.appendChild(parent.removeChild(node));
7255 }
7256
7257 return instance;
7258 },
7259
7260 getDelegateFn: function(fn) {
7261 fn = fn && fn(this.templateElement_);
7262 return typeof fn === 'function' ? fn : null;
7263 },
7264
7265 handleSplices: function(splices) {
7266 if (this.closed || !splices.length)
7267 return;
7268
7269 var template = this.templateElement_;
7270
7271 if (!template.parentNode) {
7272 this.close();
7273 return;
7274 }
7275
7276 ArrayObserver.applySplices(this.iteratedValue, this.presentValue,
7277 splices);
7278
7279 var delegate = template.delegate_;
7280 if (this.instanceModelFn_ === undefined) {
7281 this.instanceModelFn_ =
7282 this.getDelegateFn(delegate && delegate.prepareInstanceModel);
7283 }
7284
7285 if (this.instancePositionChangedFn_ === undefined) {
7286 this.instancePositionChangedFn_ =
7287 this.getDelegateFn(delegate &&
7288 delegate.prepareInstancePositionChanged);
7289 }
7290
7291 // Instance Removals
7292 var instanceCache = new Map;
7293 var removeDelta = 0;
7294 for (var i = 0; i < splices.length; i++) {
7295 var splice = splices[i];
7296 var removed = splice.removed;
7297 for (var j = 0; j < removed.length; j++) {
7298 var model = removed[j];
7299 var instance = this.extractInstanceAt(splice.index + removeDelta);
7300 if (instance !== emptyInstance) {
7301 instanceCache.set(model, instance);
7302 }
7303 }
7304
7305 removeDelta -= splice.addedCount;
7306 }
7307
7308 // Instance Insertions
7309 for (var i = 0; i < splices.length; i++) {
7310 var splice = splices[i];
7311 var addIndex = splice.index;
7312 for (; addIndex < splice.index + splice.addedCount; addIndex++) {
7313 var model = this.iteratedValue[addIndex];
7314 var instance = instanceCache.get(model);
7315 if (instance) {
7316 instanceCache.delete(model);
7317 } else {
7318 if (this.instanceModelFn_) {
7319 model = this.instanceModelFn_(model);
7320 }
7321
7322 if (model === undefined) {
7323 instance = emptyInstance;
7324 } else {
7325 instance = template.createInstance(model, undefined, delegate);
7326 }
7327 }
7328
7329 this.insertInstanceAt(addIndex, instance);
7330 }
7331 }
7332
7333 instanceCache.forEach(function(instance) {
7334 this.closeInstanceBindings(instance);
7335 }, this);
7336
7337 if (this.instancePositionChangedFn_)
7338 this.reportInstancesMoved(splices);
7339 },
7340
7341 reportInstanceMoved: function(index) {
7342 var instance = this.instances[index];
7343 if (instance === emptyInstance)
7344 return;
7345
7346 this.instancePositionChangedFn_(instance.templateInstance_, index);
7347 },
7348
7349 reportInstancesMoved: function(splices) {
7350 var index = 0;
7351 var offset = 0;
7352 for (var i = 0; i < splices.length; i++) {
7353 var splice = splices[i];
7354 if (offset != 0) {
7355 while (index < splice.index) {
7356 this.reportInstanceMoved(index);
7357 index++;
7358 }
7359 } else {
7360 index = splice.index;
7361 }
7362
7363 while (index < splice.index + splice.addedCount) {
7364 this.reportInstanceMoved(index);
7365 index++;
7366 }
7367
7368 offset += splice.addedCount - splice.removed.length;
7369 }
7370
7371 if (offset == 0)
7372 return;
7373
7374 var length = this.instances.length;
7375 while (index < length) {
7376 this.reportInstanceMoved(index);
7377 index++;
7378 }
7379 },
7380
7381 closeInstanceBindings: function(instance) {
7382 var bindings = instance.bindings_;
7383 for (var i = 0; i < bindings.length; i++) {
7384 bindings[i].close();
7385 }
7386 },
7387
7388 unobserve: function() {
7389 if (!this.arrayObserver)
7390 return;
7391
7392 this.arrayObserver.close();
7393 this.arrayObserver = undefined;
7394 },
7395
7396 close: function() {
7397 if (this.closed)
7398 return;
7399 this.unobserve();
7400 for (var i = 0; i < this.instances.length; i++) {
7401 this.closeInstanceBindings(this.instances[i]);
7402 }
7403
7404 this.instances.length = 0;
7405 this.closeDeps();
7406 this.templateElement_.iterator_ = undefined;
7407 this.closed = true;
7408 }
7409 };
7410
7411 // Polyfill-specific API.
7412 HTMLTemplateElement.forAllTemplatesFrom_ = forAllTemplatesFrom;
7413 })(this);
7414
7415 /*
7416 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
7417 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
7418 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
7419 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
7420 * Code distributed by Google as part of the polymer project is also
7421 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
7422 */
7423
7424 (function(scope) {
7425
7426 var iterations = 0;
7427 var callbacks = [];
7428 var twiddle = document.createTextNode('');
7429
7430 function endOfMicrotask(callback) {
7431 twiddle.textContent = iterations++;
7432 callbacks.push(callback);
7433 }
7434
7435 function atEndOfMicrotask() {
7436 while (callbacks.length) {
7437 callbacks.shift()();
7438 }
7439 }
7440
7441 new (window.MutationObserver || JsMutationObserver)(atEndOfMicrotask)
7442 .observe(twiddle, {characterData: true})
7443 ;
7444
7445 // exports
7446
7447 scope.endOfMicrotask = endOfMicrotask;
7448
7449 })(Platform);
7450
7451
7452 /*
7453 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
7454 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
7455 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
7456 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
7457 * Code distributed by Google as part of the polymer project is also
7458 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
7459 */
7460
7461 (function(scope) {
7462
7463 // inject style sheet
7464 var style = document.createElement('style');
7465 style.textContent = 'template {display: none !important;} /* injected by platfor m.js */';
7466 var head = document.querySelector('head');
7467 head.insertBefore(style, head.firstChild);
7468
7469 // flush (with logging)
7470 var flushing;
7471 function flush() {
7472 if (!flushing) {
7473 flushing = true;
7474 scope.endOfMicrotask(function() {
7475 flushing = false;
7476 logFlags.data && console.group('Platform.flush()');
7477 scope.performMicrotaskCheckpoint();
7478 logFlags.data && console.groupEnd();
7479 });
7480 }
7481 };
7482
7483 // polling dirty checker
7484 // flush periodically if platform does not have object observe.
7485 if (!Observer.hasObjectObserve) {
7486 var FLUSH_POLL_INTERVAL = 125;
7487 window.addEventListener('WebComponentsReady', function() {
7488 flush();
7489 scope.flushPoll = setInterval(flush, FLUSH_POLL_INTERVAL);
7490 });
7491 } else {
7492 // make flush a no-op when we have Object.observe
7493 flush = function() {};
7494 }
7495
7496 if (window.CustomElements && !CustomElements.useNative) {
7497 var originalImportNode = Document.prototype.importNode;
7498 Document.prototype.importNode = function(node, deep) {
7499 var imported = originalImportNode.call(this, node, deep);
7500 CustomElements.upgradeAll(imported);
7501 return imported;
7502 }
7503 }
7504
7505 // exports
7506 scope.flush = flush;
7507
7508 })(window.Platform);
7509
7510
7511 /*
7512 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
7513 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
7514 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
7515 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
7516 * Code distributed by Google as part of the polymer project is also
7517 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
7518 */
7519
7520 (function(scope) {
7521
7522 var urlResolver = {
7523 resolveDom: function(root, url) {
7524 url = url || root.ownerDocument.baseURI;
7525 this.resolveAttributes(root, url);
7526 this.resolveStyles(root, url);
7527 // handle template.content
7528 var templates = root.querySelectorAll('template');
7529 if (templates) {
7530 for (var i = 0, l = templates.length, t; (i < l) && (t = templates[i]); i+ +) {
7531 if (t.content) {
7532 this.resolveDom(t.content, url);
7533 }
7534 }
7535 }
7536 },
7537 resolveTemplate: function(template) {
7538 this.resolveDom(template.content, template.ownerDocument.baseURI);
7539 },
7540 resolveStyles: function(root, url) {
7541 var styles = root.querySelectorAll('style');
7542 if (styles) {
7543 for (var i = 0, l = styles.length, s; (i < l) && (s = styles[i]); i++) {
7544 this.resolveStyle(s, url);
7545 }
7546 }
7547 },
7548 resolveStyle: function(style, url) {
7549 url = url || style.ownerDocument.baseURI;
7550 style.textContent = this.resolveCssText(style.textContent, url);
7551 },
7552 resolveCssText: function(cssText, baseUrl, keepAbsolute) {
7553 cssText = replaceUrlsInCssText(cssText, baseUrl, keepAbsolute, CSS_URL_REGEX P);
7554 return replaceUrlsInCssText(cssText, baseUrl, keepAbsolute, CSS_IMPORT_REGEX P);
7555 },
7556 resolveAttributes: function(root, url) {
7557 if (root.hasAttributes && root.hasAttributes()) {
7558 this.resolveElementAttributes(root, url);
7559 }
7560 // search for attributes that host urls
7561 var nodes = root && root.querySelectorAll(URL_ATTRS_SELECTOR);
7562 if (nodes) {
7563 for (var i = 0, l = nodes.length, n; (i < l) && (n = nodes[i]); i++) {
7564 this.resolveElementAttributes(n, url);
7565 }
7566 }
7567 },
7568 resolveElementAttributes: function(node, url) {
7569 url = url || node.ownerDocument.baseURI;
7570 URL_ATTRS.forEach(function(v) {
7571 var attr = node.attributes[v];
7572 var value = attr && attr.value;
7573 var replacement;
7574 if (value && value.search(URL_TEMPLATE_SEARCH) < 0) {
7575 if (v === 'style') {
7576 replacement = replaceUrlsInCssText(value, url, false, CSS_URL_REGEXP);
7577 } else {
7578 replacement = resolveRelativeUrl(url, value);
7579 }
7580 attr.value = replacement;
7581 }
7582 });
7583 }
7584 };
7585
7586 var CSS_URL_REGEXP = /(url\()([^)]*)(\))/g;
7587 var CSS_IMPORT_REGEXP = /(@import[\s]+(?!url\())([^;]*)(;)/g;
7588 var URL_ATTRS = ['href', 'src', 'action', 'style', 'url'];
7589 var URL_ATTRS_SELECTOR = '[' + URL_ATTRS.join('],[') + ']';
7590 var URL_TEMPLATE_SEARCH = '{{.*}}';
7591
7592 function replaceUrlsInCssText(cssText, baseUrl, keepAbsolute, regexp) {
7593 return cssText.replace(regexp, function(m, pre, url, post) {
7594 var urlPath = url.replace(/["']/g, '');
7595 urlPath = resolveRelativeUrl(baseUrl, urlPath, keepAbsolute);
7596 return pre + '\'' + urlPath + '\'' + post;
7597 });
7598 }
7599
7600 function resolveRelativeUrl(baseUrl, url, keepAbsolute) {
7601 // do not resolve '/' absolute urls
7602 if (url && url[0] === '/') {
7603 return url;
7604 }
7605 var u = new URL(url, baseUrl);
7606 return keepAbsolute ? u.href : makeDocumentRelPath(u.href);
7607 }
7608
7609 function makeDocumentRelPath(url) {
7610 var root = new URL(document.baseURI);
7611 var u = new URL(url, root);
7612 if (u.host === root.host && u.port === root.port &&
7613 u.protocol === root.protocol) {
7614 return makeRelPath(root, u);
7615 } else {
7616 return url;
7617 }
7618 }
7619
7620 // make a relative path from source to target
7621 function makeRelPath(sourceUrl, targetUrl) {
7622 var source = sourceUrl.pathname;
7623 var target = targetUrl.pathname;
7624 var s = source.split('/');
7625 var t = target.split('/');
7626 while (s.length && s[0] === t[0]){
7627 s.shift();
7628 t.shift();
7629 }
7630 for (var i = 0, l = s.length - 1; i < l; i++) {
7631 t.unshift('..');
7632 }
7633 return t.join('/') + targetUrl.search + targetUrl.hash;
7634 }
7635
7636 // exports
7637 scope.urlResolver = urlResolver;
7638
7639 })(Polymer);
7640
7641 /*
7642 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
7643 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
7644 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
7645 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
7646 * Code distributed by Google as part of the polymer project is also
7647 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
7648 */
7649
7650 (function(scope) {
7651 var endOfMicrotask = Platform.endOfMicrotask;
7652
7653 // Generic url loader
7654 function Loader(regex) {
7655 this.cache = Object.create(null);
7656 this.map = Object.create(null);
7657 this.requests = 0;
7658 this.regex = regex;
7659 }
7660 Loader.prototype = {
7661
7662 // TODO(dfreedm): there may be a better factoring here
7663 // extract absolute urls from the text (full of relative urls)
7664 extractUrls: function(text, base) {
7665 var matches = [];
7666 var matched, u;
7667 while ((matched = this.regex.exec(text))) {
7668 u = new URL(matched[1], base);
7669 matches.push({matched: matched[0], url: u.href});
7670 }
7671 return matches;
7672 },
7673 // take a text blob, a root url, and a callback and load all the urls found within the text
7674 // returns a map of absolute url to text
7675 process: function(text, root, callback) {
7676 var matches = this.extractUrls(text, root);
7677
7678 // every call to process returns all the text this loader has ever receive d
7679 var done = callback.bind(null, this.map);
7680 this.fetch(matches, done);
7681 },
7682 // build a mapping of url -> text from matches
7683 fetch: function(matches, callback) {
7684 var inflight = matches.length;
7685
7686 // return early if there is no fetching to be done
7687 if (!inflight) {
7688 return callback();
7689 }
7690
7691 // wait for all subrequests to return
7692 var done = function() {
7693 if (--inflight === 0) {
7694 callback();
7695 }
7696 };
7697
7698 // start fetching all subrequests
7699 var m, req, url;
7700 for (var i = 0; i < inflight; i++) {
7701 m = matches[i];
7702 url = m.url;
7703 req = this.cache[url];
7704 // if this url has already been requested, skip requesting it again
7705 if (!req) {
7706 req = this.xhr(url);
7707 req.match = m;
7708 this.cache[url] = req;
7709 }
7710 // wait for the request to process its subrequests
7711 req.wait(done);
7712 }
7713 },
7714 handleXhr: function(request) {
7715 var match = request.match;
7716 var url = match.url;
7717
7718 // handle errors with an empty string
7719 var response = request.response || request.responseText || '';
7720 this.map[url] = response;
7721 this.fetch(this.extractUrls(response, url), request.resolve);
7722 },
7723 xhr: function(url) {
7724 this.requests++;
7725 var request = new XMLHttpRequest();
7726 request.open('GET', url, true);
7727 request.send();
7728 request.onerror = request.onload = this.handleXhr.bind(this, request);
7729
7730 // queue of tasks to run after XHR returns
7731 request.pending = [];
7732 request.resolve = function() {
7733 var pending = request.pending;
7734 for(var i = 0; i < pending.length; i++) {
7735 pending[i]();
7736 }
7737 request.pending = null;
7738 };
7739
7740 // if we have already resolved, pending is null, async call the callback
7741 request.wait = function(fn) {
7742 if (request.pending) {
7743 request.pending.push(fn);
7744 } else {
7745 endOfMicrotask(fn);
7746 }
7747 };
7748
7749 return request;
7750 }
7751 };
7752
7753 scope.Loader = Loader;
7754 })(Polymer);
7755
7756 /*
7757 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
7758 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
7759 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
7760 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
7761 * Code distributed by Google as part of the polymer project is also
7762 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
7763 */
7764
7765 (function(scope) {
7766
7767 var urlResolver = scope.urlResolver;
7768 var Loader = scope.Loader;
7769
7770 function StyleResolver() {
7771 this.loader = new Loader(this.regex);
7772 }
7773 StyleResolver.prototype = {
7774 regex: /@import\s+(?:url)?["'\(]*([^'"\)]*)['"\)]*;/g,
7775 // Recursively replace @imports with the text at that url
7776 resolve: function(text, url, callback) {
7777 var done = function(map) {
7778 callback(this.flatten(text, url, map));
7779 }.bind(this);
7780 this.loader.process(text, url, done);
7781 },
7782 // resolve the textContent of a style node
7783 resolveNode: function(style, url, callback) {
7784 var text = style.textContent;
7785 var done = function(text) {
7786 style.textContent = text;
7787 callback(style);
7788 };
7789 this.resolve(text, url, done);
7790 },
7791 // flatten all the @imports to text
7792 flatten: function(text, base, map) {
7793 var matches = this.loader.extractUrls(text, base);
7794 var match, url, intermediate;
7795 for (var i = 0; i < matches.length; i++) {
7796 match = matches[i];
7797 url = match.url;
7798 // resolve any css text to be relative to the importer, keep absolute url
7799 intermediate = urlResolver.resolveCssText(map[url], url, true);
7800 // flatten intermediate @imports
7801 intermediate = this.flatten(intermediate, base, map);
7802 text = text.replace(match.matched, intermediate);
7803 }
7804 return text;
7805 },
7806 loadStyles: function(styles, base, callback) {
7807 var loaded=0, l = styles.length;
7808 // called in the context of the style
7809 function loadedStyle(style) {
7810 loaded++;
7811 if (loaded === l && callback) {
7812 callback();
7813 }
7814 }
7815 for (var i=0, s; (i<l) && (s=styles[i]); i++) {
7816 this.resolveNode(s, base, loadedStyle);
7817 }
7818 }
7819 };
7820
7821 var styleResolver = new StyleResolver();
7822
7823 // exports
7824 scope.styleResolver = styleResolver;
7825
7826 })(Polymer);
7827
7828 /*
7829 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
7830 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
7831 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
7832 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
7833 * Code distributed by Google as part of the polymer project is also
7834 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
7835 */
7836
7837 (function(scope) {
7838
7839 // copy own properties from 'api' to 'prototype, with name hinting for 'super'
7840 function extend(prototype, api) {
7841 if (prototype && api) {
7842 // use only own properties of 'api'
7843 Object.getOwnPropertyNames(api).forEach(function(n) {
7844 // acquire property descriptor
7845 var pd = Object.getOwnPropertyDescriptor(api, n);
7846 if (pd) {
7847 // clone property via descriptor
7848 Object.defineProperty(prototype, n, pd);
7849 // cache name-of-method for 'super' engine
7850 if (typeof pd.value == 'function') {
7851 // hint the 'super' engine
7852 pd.value.nom = n;
7853 }
7854 }
7855 });
7856 }
7857 return prototype;
7858 }
7859
7860
7861 // mixin
7862
7863 // copy all properties from inProps (et al) to inObj
7864 function mixin(inObj/*, inProps, inMoreProps, ...*/) {
7865 var obj = inObj || {};
7866 for (var i = 1; i < arguments.length; i++) {
7867 var p = arguments[i];
7868 try {
7869 for (var n in p) {
7870 copyProperty(n, p, obj);
7871 }
7872 } catch(x) {
7873 }
7874 }
7875 return obj;
7876 }
7877
7878 // copy property inName from inSource object to inTarget object
7879 function copyProperty(inName, inSource, inTarget) {
7880 var pd = getPropertyDescriptor(inSource, inName);
7881 Object.defineProperty(inTarget, inName, pd);
7882 }
7883
7884 // get property descriptor for inName on inObject, even if
7885 // inName exists on some link in inObject's prototype chain
7886 function getPropertyDescriptor(inObject, inName) {
7887 if (inObject) {
7888 var pd = Object.getOwnPropertyDescriptor(inObject, inName);
7889 return pd || getPropertyDescriptor(Object.getPrototypeOf(inObject), inName );
7890 }
7891 }
7892
7893 // exports
7894
7895 scope.extend = extend;
7896 scope.mixin = mixin;
7897
7898 // for bc
7899 Platform.mixin = mixin;
7900
7901 })(Polymer);
7902
7903 /*
7904 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
7905 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
7906 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
7907 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
7908 * Code distributed by Google as part of the polymer project is also
7909 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
7910 */
7911
7912 (function(scope) {
7913
7914 // usage
7915
7916 // invoke cb.call(this) in 100ms, unless the job is re-registered,
7917 // which resets the timer
7918 //
7919 // this.myJob = this.job(this.myJob, cb, 100)
7920 //
7921 // returns a job handle which can be used to re-register a job
7922
7923 var Job = function(inContext) {
7924 this.context = inContext;
7925 this.boundComplete = this.complete.bind(this)
7926 };
7927 Job.prototype = {
7928 go: function(callback, wait) {
7929 this.callback = callback;
7930 var h;
7931 if (!wait) {
7932 h = requestAnimationFrame(this.boundComplete);
7933 this.handle = function() {
7934 cancelAnimationFrame(h);
7935 }
7936 } else {
7937 h = setTimeout(this.boundComplete, wait);
7938 this.handle = function() {
7939 clearTimeout(h);
7940 }
7941 }
7942 },
7943 stop: function() {
7944 if (this.handle) {
7945 this.handle();
7946 this.handle = null;
7947 }
7948 },
7949 complete: function() {
7950 if (this.handle) {
7951 this.stop();
7952 this.callback.call(this.context);
7953 }
7954 }
7955 };
7956
7957 function job(job, callback, wait) {
7958 if (job) {
7959 job.stop();
7960 } else {
7961 job = new Job(this);
7962 }
7963 job.go(callback, wait);
7964 return job;
7965 }
7966
7967 // exports
7968
7969 scope.job = job;
7970
7971 })(Polymer);
7972
7973 /*
7974 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
7975 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
7976 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
7977 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
7978 * Code distributed by Google as part of the polymer project is also
7979 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
7980 */
7981
7982 (function(scope) {
7983
7984 var registry = {};
7985
7986 HTMLElement.register = function(tag, prototype) {
7987 registry[tag] = prototype;
7988 }
7989
7990 // get prototype mapped to node <tag>
7991 HTMLElement.getPrototypeForTag = function(tag) {
7992 var prototype = !tag ? HTMLElement.prototype : registry[tag];
7993 // TODO(sjmiles): creating <tag> is likely to have wasteful side-effects
7994 return prototype || Object.getPrototypeOf(document.createElement(tag));
7995 };
7996
7997 // we have to flag propagation stoppage for the event dispatcher
7998 var originalStopPropagation = Event.prototype.stopPropagation;
7999 Event.prototype.stopPropagation = function() {
8000 this.cancelBubble = true;
8001 originalStopPropagation.apply(this, arguments);
8002 };
8003
8004
8005 // polyfill DOMTokenList
8006 // * add/remove: allow these methods to take multiple classNames
8007 // * toggle: add a 2nd argument which forces the given state rather
8008 // than toggling.
8009
8010 var add = DOMTokenList.prototype.add;
8011 var remove = DOMTokenList.prototype.remove;
8012 DOMTokenList.prototype.add = function() {
8013 for (var i = 0; i < arguments.length; i++) {
8014 add.call(this, arguments[i]);
8015 }
8016 };
8017 DOMTokenList.prototype.remove = function() {
8018 for (var i = 0; i < arguments.length; i++) {
8019 remove.call(this, arguments[i]);
8020 }
8021 };
8022 DOMTokenList.prototype.toggle = function(name, bool) {
8023 if (arguments.length == 1) {
8024 bool = !this.contains(name);
8025 }
8026 bool ? this.add(name) : this.remove(name);
8027 };
8028 DOMTokenList.prototype.switch = function(oldName, newName) {
8029 oldName && this.remove(oldName);
8030 newName && this.add(newName);
8031 };
8032
8033 // add array() to NodeList, NamedNodeMap, HTMLCollection
8034
8035 var ArraySlice = function() {
8036 return Array.prototype.slice.call(this);
8037 };
8038
8039 var namedNodeMap = (window.NamedNodeMap || window.MozNamedAttrMap || {});
8040
8041 NodeList.prototype.array = ArraySlice;
8042 namedNodeMap.prototype.array = ArraySlice;
8043 HTMLCollection.prototype.array = ArraySlice;
8044
8045 // utility
8046
8047 function createDOM(inTagOrNode, inHTML, inAttrs) {
8048 var dom = typeof inTagOrNode == 'string' ?
8049 document.createElement(inTagOrNode) : inTagOrNode.cloneNode(true);
8050 dom.innerHTML = inHTML;
8051 if (inAttrs) {
8052 for (var n in inAttrs) {
8053 dom.setAttribute(n, inAttrs[n]);
8054 }
8055 }
8056 return dom;
8057 }
8058
8059 // exports
8060
8061 scope.createDOM = createDOM;
8062
8063 })(Polymer);
8064
8065 /*
8066 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
8067 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
8068 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
8069 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
8070 * Code distributed by Google as part of the polymer project is also
8071 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
8072 */
8073
3847 (function(scope) { 8074 (function(scope) {
3848 // super 8075 // super
3849 8076
3850 // `arrayOfArgs` is an optional array of args like one might pass 8077 // `arrayOfArgs` is an optional array of args like one might pass
3851 // to `Function.apply` 8078 // to `Function.apply`
3852 8079
3853 // TODO(sjmiles): 8080 // TODO(sjmiles):
3854 // $super must be installed on an instance or prototype chain 8081 // $super must be installed on an instance or prototype chain
3855 // as `super`, and invoked via `this`, e.g. 8082 // as `super`, and invoked via `this`, e.g.
3856 // `this.super();` 8083 // `this.super();`
(...skipping 613 matching lines...) Expand 10 before | Expand all | Expand 10 after
4470 if (callbackName) { 8697 if (callbackName) {
4471 // if we are observing the previous value, stop 8698 // if we are observing the previous value, stop
4472 if (Array.isArray(old)) { 8699 if (Array.isArray(old)) {
4473 log.observe && console.log('[%s] observeArrayValue: unregister observe r [%s]', this.localName, name); 8700 log.observe && console.log('[%s] observeArrayValue: unregister observe r [%s]', this.localName, name);
4474 this.closeNamedObserver(name + '__array'); 8701 this.closeNamedObserver(name + '__array');
4475 } 8702 }
4476 // if the new value is an array, being observing it 8703 // if the new value is an array, being observing it
4477 if (Array.isArray(value)) { 8704 if (Array.isArray(value)) {
4478 log.observe && console.log('[%s] observeArrayValue: register observer [%s]', this.localName, name, value); 8705 log.observe && console.log('[%s] observeArrayValue: register observer [%s]', this.localName, name, value);
4479 var observer = new ArrayObserver(value); 8706 var observer = new ArrayObserver(value);
4480 observer.open(function(value, old) { 8707 observer.open(function(splices) {
4481 this.invokeMethod(callbackName, [old]); 8708 this.invokeMethod(callbackName, [splices]);
4482 }, this); 8709 }, this);
4483 this.registerNamedObserver(name + '__array', observer); 8710 this.registerNamedObserver(name + '__array', observer);
4484 } 8711 }
4485 } 8712 }
4486 }, 8713 },
4487 emitPropertyChangeRecord: function(name, value, oldValue) { 8714 emitPropertyChangeRecord: function(name, value, oldValue) {
4488 var object = this; 8715 var object = this;
4489 if (areSameValue(value, oldValue)) 8716 if (areSameValue(value, oldValue))
4490 return; 8717 return;
4491 8718
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
4637 8864
4638 (function(scope) { 8865 (function(scope) {
4639 8866
4640 // imports 8867 // imports
4641 8868
4642 var log = window.logFlags || 0; 8869 var log = window.logFlags || 0;
4643 8870
4644 // element api supporting mdv 8871 // element api supporting mdv
4645 var mdv = { 8872 var mdv = {
4646 instanceTemplate: function(template) { 8873 instanceTemplate: function(template) {
8874 // ensure template is decorated (lets' things like <tr template ...> work)
8875 HTMLTemplateElement.decorate(template);
4647 // ensure a default bindingDelegate 8876 // ensure a default bindingDelegate
4648 var syntax = this.syntax || (!template.bindingDelegate && 8877 var syntax = this.syntax || (!template.bindingDelegate &&
4649 this.element.syntax); 8878 this.element.syntax);
4650 var dom = template.createInstance(this, syntax); 8879 var dom = template.createInstance(this, syntax);
4651 var observers = dom.bindings_; 8880 var observers = dom.bindings_;
4652 for (var i = 0; i < observers.length; i++) { 8881 for (var i = 0; i < observers.length; i++) {
4653 this.registerObserver(observers[i]); 8882 this.registerObserver(observers[i]);
4654 } 8883 }
4655 return dom; 8884 return dom;
4656 }, 8885 },
(...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after
5109 9338
5110 // imports 9339 // imports
5111 9340
5112 var extend = scope.extend; 9341 var extend = scope.extend;
5113 var api = scope.api; 9342 var api = scope.api;
5114 9343
5115 // imperative implementation: Polymer() 9344 // imperative implementation: Polymer()
5116 9345
5117 // specify an 'own' prototype for tag `name` 9346 // specify an 'own' prototype for tag `name`
5118 function element(name, prototype) { 9347 function element(name, prototype) {
5119 if (arguments.length === 1 && typeof arguments[0] !== 'string') { 9348 if (typeof name !== 'string') {
9349 var script = prototype || document._currentScript;
5120 prototype = name; 9350 prototype = name;
5121 var script = document._currentScript;
5122 name = script && script.parentNode && script.parentNode.getAttribute ? 9351 name = script && script.parentNode && script.parentNode.getAttribute ?
5123 script.parentNode.getAttribute('name') : ''; 9352 script.parentNode.getAttribute('name') : '';
5124 if (!name) { 9353 if (!name) {
5125 throw 'Element name could not be inferred.'; 9354 throw 'Element name could not be inferred.';
5126 } 9355 }
5127 } 9356 }
5128 if (getRegisteredPrototype[name]) { 9357 if (getRegisteredPrototype[name]) {
5129 throw 'Already registered (Polymer) prototype for element ' + name; 9358 throw 'Already registered (Polymer) prototype for element ' + name;
5130 } 9359 }
5131 // cache the prototype 9360 // cache the prototype
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
5184 // TODO(sjmiles): find a way to do this that is less terrible 9413 // TODO(sjmiles): find a way to do this that is less terrible
5185 // copy window.Polymer properties onto `element()` 9414 // copy window.Polymer properties onto `element()`
5186 9415
5187 extend(Polymer, scope); 9416 extend(Polymer, scope);
5188 9417
5189 // Under the HTMLImports polyfill, scripts in the main document 9418 // Under the HTMLImports polyfill, scripts in the main document
5190 // do not block on imports; we want to allow calls to Polymer in the main 9419 // do not block on imports; we want to allow calls to Polymer in the main
5191 // document. Platform collects those calls until we can process them, which 9420 // document. Platform collects those calls until we can process them, which
5192 // we do here. 9421 // we do here.
5193 9422
5194 var declarations = Platform.deliverDeclarations(); 9423 if (Platform.consumeDeclarations) {
5195 if (declarations) { 9424 Platform.consumeDeclarations(function(declarations) {;
5196 for (var i=0, l=declarations.length, d; (i<l) && (d=declarations[i]); i++) { 9425 if (declarations) {
5197 element.apply(null, d); 9426 for (var i=0, l=declarations.length, d; (i<l) && (d=declarations[i]); i+ +) {
5198 } 9427 element.apply(null, d);
9428 }
9429 }
9430 });
5199 } 9431 }
5200 9432
5201 })(Polymer); 9433 })(Polymer);
5202 9434
5203 /* 9435 /*
5204 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. 9436 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
5205 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt 9437 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
5206 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt 9438 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
5207 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt 9439 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
5208 * Code distributed by Google as part of the polymer project is also 9440 * Code distributed by Google as part of the polymer project is also
5209 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt 9441 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
5210 */ 9442 */
5211 9443
5212 (function(scope) { 9444 (function(scope) {
5213 9445
5214 var path = { 9446 var path = {
5215 resolveElementPaths: function(node) { 9447 resolveElementPaths: function(node) {
5216 Platform.urlResolver.resolveDom(node); 9448 Polymer.urlResolver.resolveDom(node);
5217 }, 9449 },
5218 addResolvePathApi: function() { 9450 addResolvePathApi: function() {
5219 // let assetpath attribute modify the resolve path 9451 // let assetpath attribute modify the resolve path
5220 var assetPath = this.getAttribute('assetpath') || ''; 9452 var assetPath = this.getAttribute('assetpath') || '';
5221 var root = new URL(assetPath, this.ownerDocument.baseURI); 9453 var root = new URL(assetPath, this.ownerDocument.baseURI);
5222 this.prototype.resolvePath = function(urlPath, base) { 9454 this.prototype.resolvePath = function(urlPath, base) {
5223 var u = new URL(urlPath, base || root); 9455 var u = new URL(urlPath, base || root);
5224 return u.href; 9456 return u.href;
5225 }; 9457 };
5226 } 9458 }
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
5261 var styles = { 9493 var styles = {
5262 // returns true if resources are loading 9494 // returns true if resources are loading
5263 loadStyles: function(callback) { 9495 loadStyles: function(callback) {
5264 var template = this.fetchTemplate(); 9496 var template = this.fetchTemplate();
5265 var content = template && this.templateContent(); 9497 var content = template && this.templateContent();
5266 if (content) { 9498 if (content) {
5267 this.convertSheetsToStyles(content); 9499 this.convertSheetsToStyles(content);
5268 var styles = this.findLoadableStyles(content); 9500 var styles = this.findLoadableStyles(content);
5269 if (styles.length) { 9501 if (styles.length) {
5270 var templateUrl = template.ownerDocument.baseURI; 9502 var templateUrl = template.ownerDocument.baseURI;
5271 return Platform.styleResolver.loadStyles(styles, templateUrl, callback ); 9503 return Polymer.styleResolver.loadStyles(styles, templateUrl, callback) ;
5272 } 9504 }
5273 } 9505 }
5274 if (callback) { 9506 if (callback) {
5275 callback(); 9507 callback();
5276 } 9508 }
5277 }, 9509 },
5278 convertSheetsToStyles: function(root) { 9510 convertSheetsToStyles: function(root) {
5279 var s$ = root.querySelectorAll(SHEET_SELECTOR); 9511 var s$ = root.querySelectorAll(SHEET_SELECTOR);
5280 for (var i=0, l=s$.length, s, c; (i<l) && (s=s$[i]); i++) { 9512 for (var i=0, l=s$.length, s, c; (i<l) && (s=s$[i]); i++) {
5281 c = createStyleElement(importRuleForSheet(s, this.ownerDocument.baseURI) , 9513 c = createStyleElement(importRuleForSheet(s, this.ownerDocument.baseURI) ,
(...skipping 612 matching lines...) Expand 10 before | Expand all | Expand 10 after
5894 }; 10126 };
5895 10127
5896 // declaration api supporting mdv 10128 // declaration api supporting mdv
5897 var mdv = { 10129 var mdv = {
5898 syntax: syntax, 10130 syntax: syntax,
5899 fetchTemplate: function() { 10131 fetchTemplate: function() {
5900 return this.querySelector('template'); 10132 return this.querySelector('template');
5901 }, 10133 },
5902 templateContent: function() { 10134 templateContent: function() {
5903 var template = this.fetchTemplate(); 10135 var template = this.fetchTemplate();
5904 return template && Platform.templateContent(template); 10136 return template && template.content;
5905 }, 10137 },
5906 installBindingDelegate: function(template) { 10138 installBindingDelegate: function(template) {
5907 if (template) { 10139 if (template) {
5908 template.bindingDelegate = this.syntax; 10140 template.bindingDelegate = this.syntax;
5909 } 10141 }
5910 } 10142 }
5911 }; 10143 };
5912 10144
5913 // exports 10145 // exports
5914 scope.api.declaration.mdv = mdv; 10146 scope.api.declaration.mdv = mdv;
(...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after
6294 var element; 10526 var element;
6295 while (flushQueue.length) { 10527 while (flushQueue.length) {
6296 element = flushQueue.shift(); 10528 element = flushQueue.shift();
6297 element.__queue.go.call(element); 10529 element.__queue.go.call(element);
6298 element.__queue = null; 10530 element.__queue = null;
6299 } 10531 }
6300 this.flushing = false; 10532 this.flushing = false;
6301 }, 10533 },
6302 10534
6303 ready: function() { 10535 ready: function() {
6304 this.flush();
6305 // TODO(sorvell): As an optimization, turn off CE polyfill upgrading 10536 // TODO(sorvell): As an optimization, turn off CE polyfill upgrading
6306 // while registering. This way we avoid having to upgrade each document 10537 // while registering. This way we avoid having to upgrade each document
6307 // piecemeal per registration and can instead register all elements 10538 // piecemeal per registration and can instead register all elements
6308 // and upgrade once in a batch. Without this optimization, upgrade time 10539 // and upgrade once in a batch. Without this optimization, upgrade time
6309 // degrades significantly when SD polyfill is used. This is mainly because 10540 // degrades significantly when SD polyfill is used. This is mainly because
6310 // querying the document tree for elements is slow under the SD polyfill. 10541 // querying the document tree for elements is slow under the SD polyfill.
6311 if (CustomElements.ready === false) { 10542 var polyfillWasReady = CustomElements.ready;
10543 CustomElements.ready = false;
10544 this.flush();
10545 if (!CustomElements.useNative) {
6312 CustomElements.upgradeDocumentTree(document); 10546 CustomElements.upgradeDocumentTree(document);
6313 CustomElements.ready = true;
6314 } 10547 }
10548 CustomElements.ready = polyfillWasReady;
6315 Platform.flush(); 10549 Platform.flush();
6316 requestAnimationFrame(this.flushReadyCallbacks); 10550 requestAnimationFrame(this.flushReadyCallbacks);
6317 }, 10551 },
6318 10552
6319 addReadyCallback: function(callback) { 10553 addReadyCallback: function(callback) {
6320 if (callback) { 10554 if (callback) {
6321 readyCallbacks.push(callback); 10555 readyCallbacks.push(callback);
6322 } 10556 }
6323 }, 10557 },
6324 10558
(...skipping 18 matching lines...) Expand all
6343 var readyCallbacks = []; 10577 var readyCallbacks = [];
6344 10578
6345 function queueForElement(element) { 10579 function queueForElement(element) {
6346 return document.contains(element) ? mainQueue : importQueue; 10580 return document.contains(element) ? mainQueue : importQueue;
6347 } 10581 }
6348 10582
6349 function nextQueued() { 10583 function nextQueued() {
6350 return importQueue.length ? importQueue[0] : mainQueue[0]; 10584 return importQueue.length ? importQueue[0] : mainQueue[0];
6351 } 10585 }
6352 10586
6353 var polymerReadied = false; 10587 function whenReady(callback) {
6354
6355 document.addEventListener('WebComponentsReady', function() {
6356 CustomElements.ready = false;
6357 });
6358
6359 function whenPolymerReady(callback) {
6360 queue.waitToReady = true; 10588 queue.waitToReady = true;
6361 CustomElements.ready = false;
6362 HTMLImports.whenImportsReady(function() { 10589 HTMLImports.whenImportsReady(function() {
6363 queue.addReadyCallback(callback); 10590 queue.addReadyCallback(callback);
6364 queue.waitToReady = false; 10591 queue.waitToReady = false;
6365 queue.check(); 10592 queue.check();
6366 }); 10593 });
6367 } 10594 }
6368 10595
6369 // exports 10596 // exports
6370 scope.elements = elements; 10597 scope.elements = elements;
6371 scope.queue = queue; 10598 scope.queue = queue;
6372 scope.whenReady = scope.whenPolymerReady = whenPolymerReady; 10599 scope.whenReady = scope.whenPolymerReady = whenReady;
6373 })(Polymer); 10600 })(Polymer);
6374 10601
6375 /* 10602 /*
6376 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
6377 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
6378 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
6379 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
6380 * Code distributed by Google as part of the polymer project is also
6381 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
6382 */
6383
6384 (function(scope) {
6385
6386 var whenPolymerReady = scope.whenPolymerReady;
6387
6388 function importElements(elementOrFragment, callback) {
6389 if (elementOrFragment) {
6390 document.head.appendChild(elementOrFragment);
6391 whenPolymerReady(callback);
6392 } else if (callback) {
6393 callback();
6394 }
6395 }
6396
6397 function importUrls(urls, callback) {
6398 if (urls && urls.length) {
6399 var frag = document.createDocumentFragment();
6400 for (var i=0, l=urls.length, url, link; (i<l) && (url=urls[i]); i++) {
6401 link = document.createElement('link');
6402 link.rel = 'import';
6403 link.href = url;
6404 frag.appendChild(link);
6405 }
6406 importElements(frag, callback);
6407 } else if (callback) {
6408 callback();
6409 }
6410 }
6411
6412 // exports
6413 scope.import = importUrls;
6414 scope.importElements = importElements;
6415
6416 })(Polymer);
6417
6418 /*
6419 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. 10603 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
6420 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt 10604 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
6421 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt 10605 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
6422 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt 10606 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
6423 * Code distributed by Google as part of the polymer project is also 10607 * Code distributed by Google as part of the polymer project is also
6424 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt 10608 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
6425 */ 10609 */
6426 10610
6427 (function(scope) { 10611 (function(scope) {
6428 10612
6429 // imports 10613 // imports
6430 10614
6431 var extend = scope.extend; 10615 var extend = scope.extend;
6432 var api = scope.api; 10616 var api = scope.api;
6433 var queue = scope.queue; 10617 var queue = scope.queue;
6434 var whenPolymerReady = scope.whenPolymerReady; 10618 var whenReady = scope.whenReady;
6435 var getRegisteredPrototype = scope.getRegisteredPrototype; 10619 var getRegisteredPrototype = scope.getRegisteredPrototype;
6436 var waitingForPrototype = scope.waitingForPrototype; 10620 var waitingForPrototype = scope.waitingForPrototype;
6437 10621
6438 // declarative implementation: <polymer-element> 10622 // declarative implementation: <polymer-element>
6439 10623
6440 var prototype = extend(Object.create(HTMLElement.prototype), { 10624 var prototype = extend(Object.create(HTMLElement.prototype), {
6441 10625
6442 createdCallback: function() { 10626 createdCallback: function() {
6443 if (this.getAttribute('name')) { 10627 if (this.getAttribute('name')) {
6444 this.init(); 10628 this.init();
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
6534 function isRegistered(name) { 10718 function isRegistered(name) {
6535 return Boolean(HTMLElement.getPrototypeForTag(name)); 10719 return Boolean(HTMLElement.getPrototypeForTag(name));
6536 } 10720 }
6537 10721
6538 function isCustomTag(name) { 10722 function isCustomTag(name) {
6539 return (name && name.indexOf('-') >= 0); 10723 return (name && name.indexOf('-') >= 0);
6540 } 10724 }
6541 10725
6542 // boot tasks 10726 // boot tasks
6543 10727
6544 whenPolymerReady(function() { 10728 whenReady(function() {
6545 document.body.removeAttribute('unresolved'); 10729 document.body.removeAttribute('unresolved');
6546 document.dispatchEvent( 10730 document.dispatchEvent(
6547 new CustomEvent('polymer-ready', {bubbles: true}) 10731 new CustomEvent('polymer-ready', {bubbles: true})
6548 ); 10732 );
6549 }); 10733 });
6550 10734
6551 // register polymer-element with document 10735 // register polymer-element with document
6552 10736
6553 document.registerElement('polymer-element', {prototype: prototype}); 10737 document.registerElement('polymer-element', {prototype: prototype});
6554 10738
6555 })(Polymer); 10739 })(Polymer);
6556 10740
6557 /* 10741 /*
6558 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. 10742 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
6559 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt 10743 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
6560 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt 10744 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
6561 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt 10745 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
6562 * Code distributed by Google as part of the polymer project is also 10746 * Code distributed by Google as part of the polymer project is also
6563 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt 10747 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
6564 */ 10748 */
6565 10749
10750 (function(scope) {
10751
10752 var whenPolymerReady = scope.whenPolymerReady;
10753
10754 function importElements(elementOrFragment, callback) {
10755 if (elementOrFragment) {
10756 document.head.appendChild(elementOrFragment);
10757 whenPolymerReady(callback);
10758 } else if (callback) {
10759 callback();
10760 }
10761 }
10762
10763 function importUrls(urls, callback) {
10764 if (urls && urls.length) {
10765 var frag = document.createDocumentFragment();
10766 for (var i=0, l=urls.length, url, link; (i<l) && (url=urls[i]); i++) {
10767 link = document.createElement('link');
10768 link.rel = 'import';
10769 link.href = url;
10770 frag.appendChild(link);
10771 }
10772 importElements(frag, callback);
10773 } else if (callback) {
10774 callback();
10775 }
10776 }
10777
10778 // exports
10779 scope.import = importUrls;
10780 scope.importElements = importElements;
10781
10782 })(Polymer);
10783
10784 /*
10785 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
10786 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
10787 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
10788 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
10789 * Code distributed by Google as part of the polymer project is also
10790 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
10791 */
10792
6566 /** 10793 /**
6567 * The `auto-binding` element extends the template element. It provides a quick 10794 * The `auto-binding` element extends the template element. It provides a quick
6568 * and easy way to do data binding without the need to setup a model. 10795 * and easy way to do data binding without the need to setup a model.
6569 * The `auto-binding` element itself serves as the model and controller for the 10796 * The `auto-binding` element itself serves as the model and controller for the
6570 * elements it contains. Both data and event handlers can be bound. 10797 * elements it contains. Both data and event handlers can be bound.
6571 * 10798 *
6572 * The `auto-binding` element acts just like a template that is bound to 10799 * The `auto-binding` element acts just like a template that is bound to
6573 * a model. It stamps its content in the dom adjacent to itself. When the 10800 * a model. It stamps its content in the dom adjacent to itself. When the
6574 * content is stamped, the `template-bound` event is fired. 10801 * content is stamped, the `template-bound` event is fired.
6575 * 10802 *
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
6634 prepareBinding.call(syntax, pathString, name, node); 10861 prepareBinding.call(syntax, pathString, name, node);
6635 }; 10862 };
6636 return syntax; 10863 return syntax;
6637 } 10864 }
6638 10865
6639 }); 10866 });
6640 10867
6641 })(); 10868 })();
6642 10869
6643 //# sourceMappingURL=polymer.concat.js.map 10870 //# sourceMappingURL=polymer.concat.js.map
OLDNEW
« no previous file with comments | « pkg/polymer/lib/src/js/polymer/polymer.js ('k') | pkg/polymer/lib/src/js/polymer/polymer.concat.js.map » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698