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

Side by Side Diff: chrome/browser/resources/md_history/app.crisper.js

Issue 2264983002: MD History: Lazily load element files which are not needed for first paint (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Remove flattenhtml, rebase Created 4 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
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 function PromiseResolver() { 4 function PromiseResolver() {
5 this.resolve_; 5 this.resolve_;
6 this.reject_; 6 this.reject_;
7 this.promise_ = new Promise(function(resolve, reject) { 7 this.promise_ = new Promise(function(resolve, reject) {
8 this.resolve_ = resolve; 8 this.resolve_ = resolve;
9 this.reject_ = reject; 9 this.reject_ = reject;
10 }.bind(this)); 10 }.bind(this));
(...skipping 489 matching lines...) Expand 10 before | Expand all | Expand 10 after
500 this.stopPropagation(); 500 this.stopPropagation();
501 this.preventDefault(); 501 this.preventDefault();
502 } 502 }
503 }; 503 };
504 return { 504 return {
505 Command: Command, 505 Command: Command,
506 CanExecuteEvent: CanExecuteEvent 506 CanExecuteEvent: CanExecuteEvent
507 }; 507 };
508 }); 508 });
509 509
510 Polymer({
511 is: 'app-drawer',
512 properties: {
513 opened: {
514 type: Boolean,
515 value: false,
516 notify: true,
517 reflectToAttribute: true
518 },
519 persistent: {
520 type: Boolean,
521 value: false,
522 reflectToAttribute: true
523 },
524 align: {
525 type: String,
526 value: 'left'
527 },
528 position: {
529 type: String,
530 readOnly: true,
531 value: 'left',
532 reflectToAttribute: true
533 },
534 swipeOpen: {
535 type: Boolean,
536 value: false,
537 reflectToAttribute: true
538 },
539 noFocusTrap: {
540 type: Boolean,
541 value: false
542 }
543 },
544 observers: [ 'resetLayout(position)', '_resetPosition(align, isAttached)' ],
545 _translateOffset: 0,
546 _trackDetails: null,
547 _drawerState: 0,
548 _boundEscKeydownHandler: null,
549 _firstTabStop: null,
550 _lastTabStop: null,
551 ready: function() {
552 this.setScrollDirection('y');
553 this._setTransitionDuration('0s');
554 },
555 attached: function() {
556 Polymer.RenderStatus.afterNextRender(this, function() {
557 this._setTransitionDuration('');
558 this._boundEscKeydownHandler = this._escKeydownHandler.bind(this);
559 this._resetDrawerState();
560 this.listen(this, 'track', '_track');
561 this.addEventListener('transitionend', this._transitionend.bind(this));
562 this.addEventListener('keydown', this._tabKeydownHandler.bind(this));
563 });
564 },
565 detached: function() {
566 document.removeEventListener('keydown', this._boundEscKeydownHandler);
567 },
568 open: function() {
569 this.opened = true;
570 },
571 close: function() {
572 this.opened = false;
573 },
574 toggle: function() {
575 this.opened = !this.opened;
576 },
577 getWidth: function() {
578 return this.$.contentContainer.offsetWidth;
579 },
580 resetLayout: function() {
581 this.debounce('_resetLayout', function() {
582 this.fire('app-drawer-reset-layout');
583 }, 1);
584 },
585 _isRTL: function() {
586 return window.getComputedStyle(this).direction === 'rtl';
587 },
588 _resetPosition: function() {
589 switch (this.align) {
590 case 'start':
591 this._setPosition(this._isRTL() ? 'right' : 'left');
592 return;
593
594 case 'end':
595 this._setPosition(this._isRTL() ? 'left' : 'right');
596 return;
597 }
598 this._setPosition(this.align);
599 },
600 _escKeydownHandler: function(event) {
601 var ESC_KEYCODE = 27;
602 if (event.keyCode === ESC_KEYCODE) {
603 event.preventDefault();
604 this.close();
605 }
606 },
607 _track: function(event) {
608 if (this.persistent) {
609 return;
610 }
611 event.preventDefault();
612 switch (event.detail.state) {
613 case 'start':
614 this._trackStart(event);
615 break;
616
617 case 'track':
618 this._trackMove(event);
619 break;
620
621 case 'end':
622 this._trackEnd(event);
623 break;
624 }
625 },
626 _trackStart: function(event) {
627 this._drawerState = this._DRAWER_STATE.TRACKING;
628 this._setTransitionDuration('0s');
629 this.style.visibility = 'visible';
630 var rect = this.$.contentContainer.getBoundingClientRect();
631 if (this.position === 'left') {
632 this._translateOffset = rect.left;
633 } else {
634 this._translateOffset = rect.right - window.innerWidth;
635 }
636 this._trackDetails = [];
637 },
638 _trackMove: function(event) {
639 this._translateDrawer(event.detail.dx + this._translateOffset);
640 this._trackDetails.push({
641 dx: event.detail.dx,
642 timeStamp: Date.now()
643 });
644 },
645 _trackEnd: function(event) {
646 var x = event.detail.dx + this._translateOffset;
647 var drawerWidth = this.getWidth();
648 var isPositionLeft = this.position === 'left';
649 var isInEndState = isPositionLeft ? x >= 0 || x <= -drawerWidth : x <= 0 || x >= drawerWidth;
650 if (!isInEndState) {
651 var trackDetails = this._trackDetails;
652 this._trackDetails = null;
653 this._flingDrawer(event, trackDetails);
654 if (this._drawerState === this._DRAWER_STATE.FLINGING) {
655 return;
656 }
657 }
658 var halfWidth = drawerWidth / 2;
659 if (event.detail.dx < -halfWidth) {
660 this.opened = this.position === 'right';
661 } else if (event.detail.dx > halfWidth) {
662 this.opened = this.position === 'left';
663 }
664 if (isInEndState) {
665 this._resetDrawerState();
666 }
667 this._setTransitionDuration('');
668 this._resetDrawerTranslate();
669 this.style.visibility = '';
670 },
671 _calculateVelocity: function(event, trackDetails) {
672 var now = Date.now();
673 var timeLowerBound = now - 100;
674 var trackDetail;
675 var min = 0;
676 var max = trackDetails.length - 1;
677 while (min <= max) {
678 var mid = min + max >> 1;
679 var d = trackDetails[mid];
680 if (d.timeStamp >= timeLowerBound) {
681 trackDetail = d;
682 max = mid - 1;
683 } else {
684 min = mid + 1;
685 }
686 }
687 if (trackDetail) {
688 var dx = event.detail.dx - trackDetail.dx;
689 var dt = now - trackDetail.timeStamp || 1;
690 return dx / dt;
691 }
692 return 0;
693 },
694 _flingDrawer: function(event, trackDetails) {
695 var velocity = this._calculateVelocity(event, trackDetails);
696 if (Math.abs(velocity) < this._MIN_FLING_THRESHOLD) {
697 return;
698 }
699 this._drawerState = this._DRAWER_STATE.FLINGING;
700 var x = event.detail.dx + this._translateOffset;
701 var drawerWidth = this.getWidth();
702 var isPositionLeft = this.position === 'left';
703 var isVelocityPositive = velocity > 0;
704 var isClosingLeft = !isVelocityPositive && isPositionLeft;
705 var isClosingRight = isVelocityPositive && !isPositionLeft;
706 var dx;
707 if (isClosingLeft) {
708 dx = -(x + drawerWidth);
709 } else if (isClosingRight) {
710 dx = drawerWidth - x;
711 } else {
712 dx = -x;
713 }
714 if (isVelocityPositive) {
715 velocity = Math.max(velocity, this._MIN_TRANSITION_VELOCITY);
716 this.opened = this.position === 'left';
717 } else {
718 velocity = Math.min(velocity, -this._MIN_TRANSITION_VELOCITY);
719 this.opened = this.position === 'right';
720 }
721 this._setTransitionDuration(this._FLING_INITIAL_SLOPE * dx / velocity + 'ms' );
722 this._setTransitionTimingFunction(this._FLING_TIMING_FUNCTION);
723 this._resetDrawerTranslate();
724 },
725 _transitionend: function(event) {
726 var target = Polymer.dom(event).rootTarget;
727 if (target === this.$.contentContainer || target === this.$.scrim) {
728 if (this._drawerState === this._DRAWER_STATE.FLINGING) {
729 this._setTransitionDuration('');
730 this._setTransitionTimingFunction('');
731 this.style.visibility = '';
732 }
733 this._resetDrawerState();
734 }
735 },
736 _setTransitionDuration: function(duration) {
737 this.$.contentContainer.style.transitionDuration = duration;
738 this.$.scrim.style.transitionDuration = duration;
739 },
740 _setTransitionTimingFunction: function(timingFunction) {
741 this.$.contentContainer.style.transitionTimingFunction = timingFunction;
742 this.$.scrim.style.transitionTimingFunction = timingFunction;
743 },
744 _translateDrawer: function(x) {
745 var drawerWidth = this.getWidth();
746 if (this.position === 'left') {
747 x = Math.max(-drawerWidth, Math.min(x, 0));
748 this.$.scrim.style.opacity = 1 + x / drawerWidth;
749 } else {
750 x = Math.max(0, Math.min(x, drawerWidth));
751 this.$.scrim.style.opacity = 1 - x / drawerWidth;
752 }
753 this.translate3d(x + 'px', '0', '0', this.$.contentContainer);
754 },
755 _resetDrawerTranslate: function() {
756 this.$.scrim.style.opacity = '';
757 this.transform('', this.$.contentContainer);
758 },
759 _resetDrawerState: function() {
760 var oldState = this._drawerState;
761 if (this.opened) {
762 this._drawerState = this.persistent ? this._DRAWER_STATE.OPENED_PERSISTENT : this._DRAWER_STATE.OPENED;
763 } else {
764 this._drawerState = this._DRAWER_STATE.CLOSED;
765 }
766 if (oldState !== this._drawerState) {
767 if (this._drawerState === this._DRAWER_STATE.OPENED) {
768 this._setKeyboardFocusTrap();
769 document.addEventListener('keydown', this._boundEscKeydownHandler);
770 document.body.style.overflow = 'hidden';
771 } else {
772 document.removeEventListener('keydown', this._boundEscKeydownHandler);
773 document.body.style.overflow = '';
774 }
775 if (oldState !== this._DRAWER_STATE.INIT) {
776 this.fire('app-drawer-transitioned');
777 }
778 }
779 },
780 _setKeyboardFocusTrap: function() {
781 if (this.noFocusTrap) {
782 return;
783 }
784 var focusableElementsSelector = [ 'a[href]:not([tabindex="-1"])', 'area[href ]:not([tabindex="-1"])', 'input:not([disabled]):not([tabindex="-1"])', 'select:n ot([disabled]):not([tabindex="-1"])', 'textarea:not([disabled]):not([tabindex="- 1"])', 'button:not([disabled]):not([tabindex="-1"])', 'iframe:not([tabindex="-1" ])', '[tabindex]:not([tabindex="-1"])', '[contentEditable=true]:not([tabindex="- 1"])' ].join(',');
785 var focusableElements = Polymer.dom(this).querySelectorAll(focusableElements Selector);
786 if (focusableElements.length > 0) {
787 this._firstTabStop = focusableElements[0];
788 this._lastTabStop = focusableElements[focusableElements.length - 1];
789 } else {
790 this._firstTabStop = null;
791 this._lastTabStop = null;
792 }
793 var tabindex = this.getAttribute('tabindex');
794 if (tabindex && parseInt(tabindex, 10) > -1) {
795 this.focus();
796 } else if (this._firstTabStop) {
797 this._firstTabStop.focus();
798 }
799 },
800 _tabKeydownHandler: function(event) {
801 if (this.noFocusTrap) {
802 return;
803 }
804 var TAB_KEYCODE = 9;
805 if (this._drawerState === this._DRAWER_STATE.OPENED && event.keyCode === TAB _KEYCODE) {
806 if (event.shiftKey) {
807 if (this._firstTabStop && Polymer.dom(event).localTarget === this._first TabStop) {
808 event.preventDefault();
809 this._lastTabStop.focus();
810 }
811 } else {
812 if (this._lastTabStop && Polymer.dom(event).localTarget === this._lastTa bStop) {
813 event.preventDefault();
814 this._firstTabStop.focus();
815 }
816 }
817 }
818 },
819 _MIN_FLING_THRESHOLD: .2,
820 _MIN_TRANSITION_VELOCITY: 1.2,
821 _FLING_TIMING_FUNCTION: 'cubic-bezier(0.667, 1, 0.667, 1)',
822 _FLING_INITIAL_SLOPE: 1.5,
823 _DRAWER_STATE: {
824 INIT: 0,
825 OPENED: 1,
826 OPENED_PERSISTENT: 2,
827 CLOSED: 3,
828 TRACKING: 4,
829 FLINGING: 5
830 }
831 });
832
833 (function() { 510 (function() {
834 'use strict'; 511 'use strict';
835 Polymer({ 512 Polymer({
836 is: 'iron-location', 513 is: 'iron-location',
837 properties: { 514 properties: {
838 path: { 515 path: {
839 type: String, 516 type: String,
840 notify: true, 517 notify: true,
841 value: function() { 518 value: function() {
842 return window.decodeURIComponent(window.location.pathname); 519 return window.decodeURIComponent(window.location.pathname);
(...skipping 1073 matching lines...) Expand 10 before | Expand all | Expand 10 after
1916 return this.scrollTarget === this._doc ? window.innerHeight : this.scrollT arget.offsetHeight; 1593 return this.scrollTarget === this._doc ? window.innerHeight : this.scrollT arget.offsetHeight;
1917 } 1594 }
1918 return 0; 1595 return 0;
1919 }, 1596 },
1920 _isValidScrollTarget: function() { 1597 _isValidScrollTarget: function() {
1921 return this.scrollTarget instanceof HTMLElement; 1598 return this.scrollTarget instanceof HTMLElement;
1922 } 1599 }
1923 }; 1600 };
1924 1601
1925 (function() { 1602 (function() {
1603 var metaDatas = {};
1604 var metaArrays = {};
1605 var singleton = null;
1606 Polymer.IronMeta = Polymer({
1607 is: 'iron-meta',
1608 properties: {
1609 type: {
1610 type: String,
1611 value: 'default',
1612 observer: '_typeChanged'
1613 },
1614 key: {
1615 type: String,
1616 observer: '_keyChanged'
1617 },
1618 value: {
1619 type: Object,
1620 notify: true,
1621 observer: '_valueChanged'
1622 },
1623 self: {
1624 type: Boolean,
1625 observer: '_selfChanged'
1626 },
1627 list: {
1628 type: Array,
1629 notify: true
1630 }
1631 },
1632 hostAttributes: {
1633 hidden: true
1634 },
1635 factoryImpl: function(config) {
1636 if (config) {
1637 for (var n in config) {
1638 switch (n) {
1639 case 'type':
1640 case 'key':
1641 case 'value':
1642 this[n] = config[n];
1643 break;
1644 }
1645 }
1646 }
1647 },
1648 created: function() {
1649 this._metaDatas = metaDatas;
1650 this._metaArrays = metaArrays;
1651 },
1652 _keyChanged: function(key, old) {
1653 this._resetRegistration(old);
1654 },
1655 _valueChanged: function(value) {
1656 this._resetRegistration(this.key);
1657 },
1658 _selfChanged: function(self) {
1659 if (self) {
1660 this.value = this;
1661 }
1662 },
1663 _typeChanged: function(type) {
1664 this._unregisterKey(this.key);
1665 if (!metaDatas[type]) {
1666 metaDatas[type] = {};
1667 }
1668 this._metaData = metaDatas[type];
1669 if (!metaArrays[type]) {
1670 metaArrays[type] = [];
1671 }
1672 this.list = metaArrays[type];
1673 this._registerKeyValue(this.key, this.value);
1674 },
1675 byKey: function(key) {
1676 return this._metaData && this._metaData[key];
1677 },
1678 _resetRegistration: function(oldKey) {
1679 this._unregisterKey(oldKey);
1680 this._registerKeyValue(this.key, this.value);
1681 },
1682 _unregisterKey: function(key) {
1683 this._unregister(key, this._metaData, this.list);
1684 },
1685 _registerKeyValue: function(key, value) {
1686 this._register(key, value, this._metaData, this.list);
1687 },
1688 _register: function(key, value, data, list) {
1689 if (key && data && value !== undefined) {
1690 data[key] = value;
1691 list.push(value);
1692 }
1693 },
1694 _unregister: function(key, data, list) {
1695 if (key && data) {
1696 if (key in data) {
1697 var value = data[key];
1698 delete data[key];
1699 this.arrayDelete(list, value);
1700 }
1701 }
1702 }
1703 });
1704 Polymer.IronMeta.getIronMeta = function getIronMeta() {
1705 if (singleton === null) {
1706 singleton = new Polymer.IronMeta();
1707 }
1708 return singleton;
1709 };
1710 Polymer.IronMetaQuery = Polymer({
1711 is: 'iron-meta-query',
1712 properties: {
1713 type: {
1714 type: String,
1715 value: 'default',
1716 observer: '_typeChanged'
1717 },
1718 key: {
1719 type: String,
1720 observer: '_keyChanged'
1721 },
1722 value: {
1723 type: Object,
1724 notify: true,
1725 readOnly: true
1726 },
1727 list: {
1728 type: Array,
1729 notify: true
1730 }
1731 },
1732 factoryImpl: function(config) {
1733 if (config) {
1734 for (var n in config) {
1735 switch (n) {
1736 case 'type':
1737 case 'key':
1738 this[n] = config[n];
1739 break;
1740 }
1741 }
1742 }
1743 },
1744 created: function() {
1745 this._metaDatas = metaDatas;
1746 this._metaArrays = metaArrays;
1747 },
1748 _keyChanged: function(key) {
1749 this._setValue(this._metaData && this._metaData[key]);
1750 },
1751 _typeChanged: function(type) {
1752 this._metaData = metaDatas[type];
1753 this.list = metaArrays[type];
1754 if (this.key) {
1755 this._keyChanged(this.key);
1756 }
1757 },
1758 byKey: function(key) {
1759 return this._metaData && this._metaData[key];
1760 }
1761 });
1762 })();
1763
1764 Polymer({
1765 is: 'iron-icon',
1766 properties: {
1767 icon: {
1768 type: String,
1769 observer: '_iconChanged'
1770 },
1771 theme: {
1772 type: String,
1773 observer: '_updateIcon'
1774 },
1775 src: {
1776 type: String,
1777 observer: '_srcChanged'
1778 },
1779 _meta: {
1780 value: Polymer.Base.create('iron-meta', {
1781 type: 'iconset'
1782 }),
1783 observer: '_updateIcon'
1784 }
1785 },
1786 _DEFAULT_ICONSET: 'icons',
1787 _iconChanged: function(icon) {
1788 var parts = (icon || '').split(':');
1789 this._iconName = parts.pop();
1790 this._iconsetName = parts.pop() || this._DEFAULT_ICONSET;
1791 this._updateIcon();
1792 },
1793 _srcChanged: function(src) {
1794 this._updateIcon();
1795 },
1796 _usesIconset: function() {
1797 return this.icon || !this.src;
1798 },
1799 _updateIcon: function() {
1800 if (this._usesIconset()) {
1801 if (this._img && this._img.parentNode) {
1802 Polymer.dom(this.root).removeChild(this._img);
1803 }
1804 if (this._iconName === "") {
1805 if (this._iconset) {
1806 this._iconset.removeIcon(this);
1807 }
1808 } else if (this._iconsetName && this._meta) {
1809 this._iconset = this._meta.byKey(this._iconsetName);
1810 if (this._iconset) {
1811 this._iconset.applyIcon(this, this._iconName, this.theme);
1812 this.unlisten(window, 'iron-iconset-added', '_updateIcon');
1813 } else {
1814 this.listen(window, 'iron-iconset-added', '_updateIcon');
1815 }
1816 }
1817 } else {
1818 if (this._iconset) {
1819 this._iconset.removeIcon(this);
1820 }
1821 if (!this._img) {
1822 this._img = document.createElement('img');
1823 this._img.style.width = '100%';
1824 this._img.style.height = '100%';
1825 this._img.draggable = false;
1826 }
1827 this._img.src = this.src;
1828 Polymer.dom(this.root).appendChild(this._img);
1829 }
1830 }
1831 });
1832
1833 (function() {
1926 'use strict'; 1834 'use strict';
1927 var KEY_IDENTIFIER = { 1835 var KEY_IDENTIFIER = {
1928 'U+0008': 'backspace', 1836 'U+0008': 'backspace',
1929 'U+0009': 'tab', 1837 'U+0009': 'tab',
1930 'U+001B': 'esc', 1838 'U+001B': 'esc',
1931 'U+0020': 'space', 1839 'U+0020': 'space',
1932 'U+007F': 'del' 1840 'U+007F': 'del'
1933 }; 1841 };
1934 var KEY_CODE = { 1842 var KEY_CODE = {
1935 8: 'backspace', 1843 8: 'backspace',
(...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after
2264 this.tabIndex = this._oldTabIndex; 2172 this.tabIndex = this._oldTabIndex;
2265 } 2173 }
2266 }, 2174 },
2267 _changedControlState: function() { 2175 _changedControlState: function() {
2268 if (this._controlStateChanged) { 2176 if (this._controlStateChanged) {
2269 this._controlStateChanged(); 2177 this._controlStateChanged();
2270 } 2178 }
2271 } 2179 }
2272 }; 2180 };
2273 2181
2274 Polymer.IronFitBehavior = {
2275 properties: {
2276 sizingTarget: {
2277 type: Object,
2278 value: function() {
2279 return this;
2280 }
2281 },
2282 fitInto: {
2283 type: Object,
2284 value: window
2285 },
2286 noOverlap: {
2287 type: Boolean
2288 },
2289 positionTarget: {
2290 type: Element
2291 },
2292 horizontalAlign: {
2293 type: String
2294 },
2295 verticalAlign: {
2296 type: String
2297 },
2298 dynamicAlign: {
2299 type: Boolean
2300 },
2301 horizontalOffset: {
2302 type: Number,
2303 value: 0,
2304 notify: true
2305 },
2306 verticalOffset: {
2307 type: Number,
2308 value: 0,
2309 notify: true
2310 },
2311 autoFitOnAttach: {
2312 type: Boolean,
2313 value: false
2314 },
2315 _fitInfo: {
2316 type: Object
2317 }
2318 },
2319 get _fitWidth() {
2320 var fitWidth;
2321 if (this.fitInto === window) {
2322 fitWidth = this.fitInto.innerWidth;
2323 } else {
2324 fitWidth = this.fitInto.getBoundingClientRect().width;
2325 }
2326 return fitWidth;
2327 },
2328 get _fitHeight() {
2329 var fitHeight;
2330 if (this.fitInto === window) {
2331 fitHeight = this.fitInto.innerHeight;
2332 } else {
2333 fitHeight = this.fitInto.getBoundingClientRect().height;
2334 }
2335 return fitHeight;
2336 },
2337 get _fitLeft() {
2338 var fitLeft;
2339 if (this.fitInto === window) {
2340 fitLeft = 0;
2341 } else {
2342 fitLeft = this.fitInto.getBoundingClientRect().left;
2343 }
2344 return fitLeft;
2345 },
2346 get _fitTop() {
2347 var fitTop;
2348 if (this.fitInto === window) {
2349 fitTop = 0;
2350 } else {
2351 fitTop = this.fitInto.getBoundingClientRect().top;
2352 }
2353 return fitTop;
2354 },
2355 get _defaultPositionTarget() {
2356 var parent = Polymer.dom(this).parentNode;
2357 if (parent && parent.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
2358 parent = parent.host;
2359 }
2360 return parent;
2361 },
2362 get _localeHorizontalAlign() {
2363 if (this._isRTL) {
2364 if (this.horizontalAlign === 'right') {
2365 return 'left';
2366 }
2367 if (this.horizontalAlign === 'left') {
2368 return 'right';
2369 }
2370 }
2371 return this.horizontalAlign;
2372 },
2373 attached: function() {
2374 this._isRTL = window.getComputedStyle(this).direction == 'rtl';
2375 this.positionTarget = this.positionTarget || this._defaultPositionTarget;
2376 if (this.autoFitOnAttach) {
2377 if (window.getComputedStyle(this).display === 'none') {
2378 setTimeout(function() {
2379 this.fit();
2380 }.bind(this));
2381 } else {
2382 this.fit();
2383 }
2384 }
2385 },
2386 fit: function() {
2387 this.position();
2388 this.constrain();
2389 this.center();
2390 },
2391 _discoverInfo: function() {
2392 if (this._fitInfo) {
2393 return;
2394 }
2395 var target = window.getComputedStyle(this);
2396 var sizer = window.getComputedStyle(this.sizingTarget);
2397 this._fitInfo = {
2398 inlineStyle: {
2399 top: this.style.top || '',
2400 left: this.style.left || '',
2401 position: this.style.position || ''
2402 },
2403 sizerInlineStyle: {
2404 maxWidth: this.sizingTarget.style.maxWidth || '',
2405 maxHeight: this.sizingTarget.style.maxHeight || '',
2406 boxSizing: this.sizingTarget.style.boxSizing || ''
2407 },
2408 positionedBy: {
2409 vertically: target.top !== 'auto' ? 'top' : target.bottom !== 'auto' ? ' bottom' : null,
2410 horizontally: target.left !== 'auto' ? 'left' : target.right !== 'auto' ? 'right' : null
2411 },
2412 sizedBy: {
2413 height: sizer.maxHeight !== 'none',
2414 width: sizer.maxWidth !== 'none',
2415 minWidth: parseInt(sizer.minWidth, 10) || 0,
2416 minHeight: parseInt(sizer.minHeight, 10) || 0
2417 },
2418 margin: {
2419 top: parseInt(target.marginTop, 10) || 0,
2420 right: parseInt(target.marginRight, 10) || 0,
2421 bottom: parseInt(target.marginBottom, 10) || 0,
2422 left: parseInt(target.marginLeft, 10) || 0
2423 }
2424 };
2425 if (this.verticalOffset) {
2426 this._fitInfo.margin.top = this._fitInfo.margin.bottom = this.verticalOffs et;
2427 this._fitInfo.inlineStyle.marginTop = this.style.marginTop || '';
2428 this._fitInfo.inlineStyle.marginBottom = this.style.marginBottom || '';
2429 this.style.marginTop = this.style.marginBottom = this.verticalOffset + 'px ';
2430 }
2431 if (this.horizontalOffset) {
2432 this._fitInfo.margin.left = this._fitInfo.margin.right = this.horizontalOf fset;
2433 this._fitInfo.inlineStyle.marginLeft = this.style.marginLeft || '';
2434 this._fitInfo.inlineStyle.marginRight = this.style.marginRight || '';
2435 this.style.marginLeft = this.style.marginRight = this.horizontalOffset + ' px';
2436 }
2437 },
2438 resetFit: function() {
2439 var info = this._fitInfo || {};
2440 for (var property in info.sizerInlineStyle) {
2441 this.sizingTarget.style[property] = info.sizerInlineStyle[property];
2442 }
2443 for (var property in info.inlineStyle) {
2444 this.style[property] = info.inlineStyle[property];
2445 }
2446 this._fitInfo = null;
2447 },
2448 refit: function() {
2449 var scrollLeft = this.sizingTarget.scrollLeft;
2450 var scrollTop = this.sizingTarget.scrollTop;
2451 this.resetFit();
2452 this.fit();
2453 this.sizingTarget.scrollLeft = scrollLeft;
2454 this.sizingTarget.scrollTop = scrollTop;
2455 },
2456 position: function() {
2457 if (!this.horizontalAlign && !this.verticalAlign) {
2458 return;
2459 }
2460 this._discoverInfo();
2461 this.style.position = 'fixed';
2462 this.sizingTarget.style.boxSizing = 'border-box';
2463 this.style.left = '0px';
2464 this.style.top = '0px';
2465 var rect = this.getBoundingClientRect();
2466 var positionRect = this.__getNormalizedRect(this.positionTarget);
2467 var fitRect = this.__getNormalizedRect(this.fitInto);
2468 var margin = this._fitInfo.margin;
2469 var size = {
2470 width: rect.width + margin.left + margin.right,
2471 height: rect.height + margin.top + margin.bottom
2472 };
2473 var position = this.__getPosition(this._localeHorizontalAlign, this.vertical Align, size, positionRect, fitRect);
2474 var left = position.left + margin.left;
2475 var top = position.top + margin.top;
2476 var right = Math.min(fitRect.right - margin.right, left + rect.width);
2477 var bottom = Math.min(fitRect.bottom - margin.bottom, top + rect.height);
2478 var minWidth = this._fitInfo.sizedBy.minWidth;
2479 var minHeight = this._fitInfo.sizedBy.minHeight;
2480 if (left < margin.left) {
2481 left = margin.left;
2482 if (right - left < minWidth) {
2483 left = right - minWidth;
2484 }
2485 }
2486 if (top < margin.top) {
2487 top = margin.top;
2488 if (bottom - top < minHeight) {
2489 top = bottom - minHeight;
2490 }
2491 }
2492 this.sizingTarget.style.maxWidth = right - left + 'px';
2493 this.sizingTarget.style.maxHeight = bottom - top + 'px';
2494 this.style.left = left - rect.left + 'px';
2495 this.style.top = top - rect.top + 'px';
2496 },
2497 constrain: function() {
2498 if (this.horizontalAlign || this.verticalAlign) {
2499 return;
2500 }
2501 this._discoverInfo();
2502 var info = this._fitInfo;
2503 if (!info.positionedBy.vertically) {
2504 this.style.position = 'fixed';
2505 this.style.top = '0px';
2506 }
2507 if (!info.positionedBy.horizontally) {
2508 this.style.position = 'fixed';
2509 this.style.left = '0px';
2510 }
2511 this.sizingTarget.style.boxSizing = 'border-box';
2512 var rect = this.getBoundingClientRect();
2513 if (!info.sizedBy.height) {
2514 this.__sizeDimension(rect, info.positionedBy.vertically, 'top', 'bottom', 'Height');
2515 }
2516 if (!info.sizedBy.width) {
2517 this.__sizeDimension(rect, info.positionedBy.horizontally, 'left', 'right' , 'Width');
2518 }
2519 },
2520 _sizeDimension: function(rect, positionedBy, start, end, extent) {
2521 this.__sizeDimension(rect, positionedBy, start, end, extent);
2522 },
2523 __sizeDimension: function(rect, positionedBy, start, end, extent) {
2524 var info = this._fitInfo;
2525 var fitRect = this.__getNormalizedRect(this.fitInto);
2526 var max = extent === 'Width' ? fitRect.width : fitRect.height;
2527 var flip = positionedBy === end;
2528 var offset = flip ? max - rect[end] : rect[start];
2529 var margin = info.margin[flip ? start : end];
2530 var offsetExtent = 'offset' + extent;
2531 var sizingOffset = this[offsetExtent] - this.sizingTarget[offsetExtent];
2532 this.sizingTarget.style['max' + extent] = max - margin - offset - sizingOffs et + 'px';
2533 },
2534 center: function() {
2535 if (this.horizontalAlign || this.verticalAlign) {
2536 return;
2537 }
2538 this._discoverInfo();
2539 var positionedBy = this._fitInfo.positionedBy;
2540 if (positionedBy.vertically && positionedBy.horizontally) {
2541 return;
2542 }
2543 this.style.position = 'fixed';
2544 if (!positionedBy.vertically) {
2545 this.style.top = '0px';
2546 }
2547 if (!positionedBy.horizontally) {
2548 this.style.left = '0px';
2549 }
2550 var rect = this.getBoundingClientRect();
2551 var fitRect = this.__getNormalizedRect(this.fitInto);
2552 if (!positionedBy.vertically) {
2553 var top = fitRect.top - rect.top + (fitRect.height - rect.height) / 2;
2554 this.style.top = top + 'px';
2555 }
2556 if (!positionedBy.horizontally) {
2557 var left = fitRect.left - rect.left + (fitRect.width - rect.width) / 2;
2558 this.style.left = left + 'px';
2559 }
2560 },
2561 __getNormalizedRect: function(target) {
2562 if (target === document.documentElement || target === window) {
2563 return {
2564 top: 0,
2565 left: 0,
2566 width: window.innerWidth,
2567 height: window.innerHeight,
2568 right: window.innerWidth,
2569 bottom: window.innerHeight
2570 };
2571 }
2572 return target.getBoundingClientRect();
2573 },
2574 __getCroppedArea: function(position, size, fitRect) {
2575 var verticalCrop = Math.min(0, position.top) + Math.min(0, fitRect.bottom - (position.top + size.height));
2576 var horizontalCrop = Math.min(0, position.left) + Math.min(0, fitRect.right - (position.left + size.width));
2577 return Math.abs(verticalCrop) * size.width + Math.abs(horizontalCrop) * size .height;
2578 },
2579 __getPosition: function(hAlign, vAlign, size, positionRect, fitRect) {
2580 var positions = [ {
2581 verticalAlign: 'top',
2582 horizontalAlign: 'left',
2583 top: positionRect.top,
2584 left: positionRect.left
2585 }, {
2586 verticalAlign: 'top',
2587 horizontalAlign: 'right',
2588 top: positionRect.top,
2589 left: positionRect.right - size.width
2590 }, {
2591 verticalAlign: 'bottom',
2592 horizontalAlign: 'left',
2593 top: positionRect.bottom - size.height,
2594 left: positionRect.left
2595 }, {
2596 verticalAlign: 'bottom',
2597 horizontalAlign: 'right',
2598 top: positionRect.bottom - size.height,
2599 left: positionRect.right - size.width
2600 } ];
2601 if (this.noOverlap) {
2602 for (var i = 0, l = positions.length; i < l; i++) {
2603 var copy = {};
2604 for (var key in positions[i]) {
2605 copy[key] = positions[i][key];
2606 }
2607 positions.push(copy);
2608 }
2609 positions[0].top = positions[1].top += positionRect.height;
2610 positions[2].top = positions[3].top -= positionRect.height;
2611 positions[4].left = positions[6].left += positionRect.width;
2612 positions[5].left = positions[7].left -= positionRect.width;
2613 }
2614 vAlign = vAlign === 'auto' ? null : vAlign;
2615 hAlign = hAlign === 'auto' ? null : hAlign;
2616 var position;
2617 for (var i = 0; i < positions.length; i++) {
2618 var pos = positions[i];
2619 if (!this.dynamicAlign && !this.noOverlap && pos.verticalAlign === vAlign && pos.horizontalAlign === hAlign) {
2620 position = pos;
2621 break;
2622 }
2623 var alignOk = (!vAlign || pos.verticalAlign === vAlign) && (!hAlign || pos .horizontalAlign === hAlign);
2624 if (!this.dynamicAlign && !alignOk) {
2625 continue;
2626 }
2627 position = position || pos;
2628 pos.croppedArea = this.__getCroppedArea(pos, size, fitRect);
2629 var diff = pos.croppedArea - position.croppedArea;
2630 if (diff < 0 || diff === 0 && alignOk) {
2631 position = pos;
2632 }
2633 if (position.croppedArea === 0 && alignOk) {
2634 break;
2635 }
2636 }
2637 return position;
2638 }
2639 };
2640
2641 (function() {
2642 'use strict';
2643 Polymer({
2644 is: 'iron-overlay-backdrop',
2645 properties: {
2646 opened: {
2647 reflectToAttribute: true,
2648 type: Boolean,
2649 value: false,
2650 observer: '_openedChanged'
2651 }
2652 },
2653 listeners: {
2654 transitionend: '_onTransitionend'
2655 },
2656 created: function() {
2657 this.__openedRaf = null;
2658 },
2659 attached: function() {
2660 this.opened && this._openedChanged(this.opened);
2661 },
2662 prepare: function() {
2663 if (this.opened && !this.parentNode) {
2664 Polymer.dom(document.body).appendChild(this);
2665 }
2666 },
2667 open: function() {
2668 this.opened = true;
2669 },
2670 close: function() {
2671 this.opened = false;
2672 },
2673 complete: function() {
2674 if (!this.opened && this.parentNode === document.body) {
2675 Polymer.dom(this.parentNode).removeChild(this);
2676 }
2677 },
2678 _onTransitionend: function(event) {
2679 if (event && event.target === this) {
2680 this.complete();
2681 }
2682 },
2683 _openedChanged: function(opened) {
2684 if (opened) {
2685 this.prepare();
2686 } else {
2687 var cs = window.getComputedStyle(this);
2688 if (cs.transitionDuration === '0s' || cs.opacity == 0) {
2689 this.complete();
2690 }
2691 }
2692 if (!this.isAttached) {
2693 return;
2694 }
2695 if (this.__openedRaf) {
2696 window.cancelAnimationFrame(this.__openedRaf);
2697 this.__openedRaf = null;
2698 }
2699 this.scrollTop = this.scrollTop;
2700 this.__openedRaf = window.requestAnimationFrame(function() {
2701 this.__openedRaf = null;
2702 this.toggleClass('opened', this.opened);
2703 }.bind(this));
2704 }
2705 });
2706 })();
2707
2708 Polymer.IronOverlayManagerClass = function() {
2709 this._overlays = [];
2710 this._minimumZ = 101;
2711 this._backdropElement = null;
2712 Polymer.Gestures.add(document, 'tap', this._onCaptureClick.bind(this));
2713 document.addEventListener('focus', this._onCaptureFocus.bind(this), true);
2714 document.addEventListener('keydown', this._onCaptureKeyDown.bind(this), true);
2715 };
2716
2717 Polymer.IronOverlayManagerClass.prototype = {
2718 constructor: Polymer.IronOverlayManagerClass,
2719 get backdropElement() {
2720 if (!this._backdropElement) {
2721 this._backdropElement = document.createElement('iron-overlay-backdrop');
2722 }
2723 return this._backdropElement;
2724 },
2725 get deepActiveElement() {
2726 var active = document.activeElement || document.body;
2727 while (active.root && Polymer.dom(active.root).activeElement) {
2728 active = Polymer.dom(active.root).activeElement;
2729 }
2730 return active;
2731 },
2732 _bringOverlayAtIndexToFront: function(i) {
2733 var overlay = this._overlays[i];
2734 if (!overlay) {
2735 return;
2736 }
2737 var lastI = this._overlays.length - 1;
2738 var currentOverlay = this._overlays[lastI];
2739 if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)) {
2740 lastI--;
2741 }
2742 if (i >= lastI) {
2743 return;
2744 }
2745 var minimumZ = Math.max(this.currentOverlayZ(), this._minimumZ);
2746 if (this._getZ(overlay) <= minimumZ) {
2747 this._applyOverlayZ(overlay, minimumZ);
2748 }
2749 while (i < lastI) {
2750 this._overlays[i] = this._overlays[i + 1];
2751 i++;
2752 }
2753 this._overlays[lastI] = overlay;
2754 },
2755 addOrRemoveOverlay: function(overlay) {
2756 if (overlay.opened) {
2757 this.addOverlay(overlay);
2758 } else {
2759 this.removeOverlay(overlay);
2760 }
2761 },
2762 addOverlay: function(overlay) {
2763 var i = this._overlays.indexOf(overlay);
2764 if (i >= 0) {
2765 this._bringOverlayAtIndexToFront(i);
2766 this.trackBackdrop();
2767 return;
2768 }
2769 var insertionIndex = this._overlays.length;
2770 var currentOverlay = this._overlays[insertionIndex - 1];
2771 var minimumZ = Math.max(this._getZ(currentOverlay), this._minimumZ);
2772 var newZ = this._getZ(overlay);
2773 if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)) {
2774 this._applyOverlayZ(currentOverlay, minimumZ);
2775 insertionIndex--;
2776 var previousOverlay = this._overlays[insertionIndex - 1];
2777 minimumZ = Math.max(this._getZ(previousOverlay), this._minimumZ);
2778 }
2779 if (newZ <= minimumZ) {
2780 this._applyOverlayZ(overlay, minimumZ);
2781 }
2782 this._overlays.splice(insertionIndex, 0, overlay);
2783 this.trackBackdrop();
2784 },
2785 removeOverlay: function(overlay) {
2786 var i = this._overlays.indexOf(overlay);
2787 if (i === -1) {
2788 return;
2789 }
2790 this._overlays.splice(i, 1);
2791 this.trackBackdrop();
2792 },
2793 currentOverlay: function() {
2794 var i = this._overlays.length - 1;
2795 return this._overlays[i];
2796 },
2797 currentOverlayZ: function() {
2798 return this._getZ(this.currentOverlay());
2799 },
2800 ensureMinimumZ: function(minimumZ) {
2801 this._minimumZ = Math.max(this._minimumZ, minimumZ);
2802 },
2803 focusOverlay: function() {
2804 var current = this.currentOverlay();
2805 if (current) {
2806 current._applyFocus();
2807 }
2808 },
2809 trackBackdrop: function() {
2810 var overlay = this._overlayWithBackdrop();
2811 if (!overlay && !this._backdropElement) {
2812 return;
2813 }
2814 this.backdropElement.style.zIndex = this._getZ(overlay) - 1;
2815 this.backdropElement.opened = !!overlay;
2816 },
2817 getBackdrops: function() {
2818 var backdrops = [];
2819 for (var i = 0; i < this._overlays.length; i++) {
2820 if (this._overlays[i].withBackdrop) {
2821 backdrops.push(this._overlays[i]);
2822 }
2823 }
2824 return backdrops;
2825 },
2826 backdropZ: function() {
2827 return this._getZ(this._overlayWithBackdrop()) - 1;
2828 },
2829 _overlayWithBackdrop: function() {
2830 for (var i = 0; i < this._overlays.length; i++) {
2831 if (this._overlays[i].withBackdrop) {
2832 return this._overlays[i];
2833 }
2834 }
2835 },
2836 _getZ: function(overlay) {
2837 var z = this._minimumZ;
2838 if (overlay) {
2839 var z1 = Number(overlay.style.zIndex || window.getComputedStyle(overlay).z Index);
2840 if (z1 === z1) {
2841 z = z1;
2842 }
2843 }
2844 return z;
2845 },
2846 _setZ: function(element, z) {
2847 element.style.zIndex = z;
2848 },
2849 _applyOverlayZ: function(overlay, aboveZ) {
2850 this._setZ(overlay, aboveZ + 2);
2851 },
2852 _overlayInPath: function(path) {
2853 path = path || [];
2854 for (var i = 0; i < path.length; i++) {
2855 if (path[i]._manager === this) {
2856 return path[i];
2857 }
2858 }
2859 },
2860 _onCaptureClick: function(event) {
2861 var overlay = this.currentOverlay();
2862 if (overlay && this._overlayInPath(Polymer.dom(event).path) !== overlay) {
2863 overlay._onCaptureClick(event);
2864 }
2865 },
2866 _onCaptureFocus: function(event) {
2867 var overlay = this.currentOverlay();
2868 if (overlay) {
2869 overlay._onCaptureFocus(event);
2870 }
2871 },
2872 _onCaptureKeyDown: function(event) {
2873 var overlay = this.currentOverlay();
2874 if (overlay) {
2875 if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'esc')) {
2876 overlay._onCaptureEsc(event);
2877 } else if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 't ab')) {
2878 overlay._onCaptureTab(event);
2879 }
2880 }
2881 },
2882 _shouldBeBehindOverlay: function(overlay1, overlay2) {
2883 return !overlay1.alwaysOnTop && overlay2.alwaysOnTop;
2884 }
2885 };
2886
2887 Polymer.IronOverlayManager = new Polymer.IronOverlayManagerClass();
2888
2889 (function() {
2890 'use strict';
2891 Polymer.IronOverlayBehaviorImpl = {
2892 properties: {
2893 opened: {
2894 observer: '_openedChanged',
2895 type: Boolean,
2896 value: false,
2897 notify: true
2898 },
2899 canceled: {
2900 observer: '_canceledChanged',
2901 readOnly: true,
2902 type: Boolean,
2903 value: false
2904 },
2905 withBackdrop: {
2906 observer: '_withBackdropChanged',
2907 type: Boolean
2908 },
2909 noAutoFocus: {
2910 type: Boolean,
2911 value: false
2912 },
2913 noCancelOnEscKey: {
2914 type: Boolean,
2915 value: false
2916 },
2917 noCancelOnOutsideClick: {
2918 type: Boolean,
2919 value: false
2920 },
2921 closingReason: {
2922 type: Object
2923 },
2924 restoreFocusOnClose: {
2925 type: Boolean,
2926 value: false
2927 },
2928 alwaysOnTop: {
2929 type: Boolean
2930 },
2931 _manager: {
2932 type: Object,
2933 value: Polymer.IronOverlayManager
2934 },
2935 _focusedChild: {
2936 type: Object
2937 }
2938 },
2939 listeners: {
2940 'iron-resize': '_onIronResize'
2941 },
2942 get backdropElement() {
2943 return this._manager.backdropElement;
2944 },
2945 get _focusNode() {
2946 return this._focusedChild || Polymer.dom(this).querySelector('[autofocus]' ) || this;
2947 },
2948 get _focusableNodes() {
2949 var FOCUSABLE_WITH_DISABLED = [ 'a[href]', 'area[href]', 'iframe', '[tabin dex]', '[contentEditable=true]' ];
2950 var FOCUSABLE_WITHOUT_DISABLED = [ 'input', 'select', 'textarea', 'button' ];
2951 var selector = FOCUSABLE_WITH_DISABLED.join(':not([tabindex="-1"]),') + ': not([tabindex="-1"]),' + FOCUSABLE_WITHOUT_DISABLED.join(':not([disabled]):not([ tabindex="-1"]),') + ':not([disabled]):not([tabindex="-1"])';
2952 var focusables = Polymer.dom(this).querySelectorAll(selector);
2953 if (this.tabIndex >= 0) {
2954 focusables.splice(0, 0, this);
2955 }
2956 return focusables.sort(function(a, b) {
2957 if (a.tabIndex === b.tabIndex) {
2958 return 0;
2959 }
2960 if (a.tabIndex === 0 || a.tabIndex > b.tabIndex) {
2961 return 1;
2962 }
2963 return -1;
2964 });
2965 },
2966 ready: function() {
2967 this.__isAnimating = false;
2968 this.__shouldRemoveTabIndex = false;
2969 this.__firstFocusableNode = this.__lastFocusableNode = null;
2970 this.__raf = null;
2971 this.__restoreFocusNode = null;
2972 this._ensureSetup();
2973 },
2974 attached: function() {
2975 if (this.opened) {
2976 this._openedChanged(this.opened);
2977 }
2978 this._observer = Polymer.dom(this).observeNodes(this._onNodesChange);
2979 },
2980 detached: function() {
2981 Polymer.dom(this).unobserveNodes(this._observer);
2982 this._observer = null;
2983 if (this.__raf) {
2984 window.cancelAnimationFrame(this.__raf);
2985 this.__raf = null;
2986 }
2987 this._manager.removeOverlay(this);
2988 },
2989 toggle: function() {
2990 this._setCanceled(false);
2991 this.opened = !this.opened;
2992 },
2993 open: function() {
2994 this._setCanceled(false);
2995 this.opened = true;
2996 },
2997 close: function() {
2998 this._setCanceled(false);
2999 this.opened = false;
3000 },
3001 cancel: function(event) {
3002 var cancelEvent = this.fire('iron-overlay-canceled', event, {
3003 cancelable: true
3004 });
3005 if (cancelEvent.defaultPrevented) {
3006 return;
3007 }
3008 this._setCanceled(true);
3009 this.opened = false;
3010 },
3011 _ensureSetup: function() {
3012 if (this._overlaySetup) {
3013 return;
3014 }
3015 this._overlaySetup = true;
3016 this.style.outline = 'none';
3017 this.style.display = 'none';
3018 },
3019 _openedChanged: function(opened) {
3020 if (opened) {
3021 this.removeAttribute('aria-hidden');
3022 } else {
3023 this.setAttribute('aria-hidden', 'true');
3024 }
3025 if (!this.isAttached) {
3026 return;
3027 }
3028 this.__isAnimating = true;
3029 this.__onNextAnimationFrame(this.__openedChanged);
3030 },
3031 _canceledChanged: function() {
3032 this.closingReason = this.closingReason || {};
3033 this.closingReason.canceled = this.canceled;
3034 },
3035 _withBackdropChanged: function() {
3036 if (this.withBackdrop && !this.hasAttribute('tabindex')) {
3037 this.setAttribute('tabindex', '-1');
3038 this.__shouldRemoveTabIndex = true;
3039 } else if (this.__shouldRemoveTabIndex) {
3040 this.removeAttribute('tabindex');
3041 this.__shouldRemoveTabIndex = false;
3042 }
3043 if (this.opened && this.isAttached) {
3044 this._manager.trackBackdrop();
3045 }
3046 },
3047 _prepareRenderOpened: function() {
3048 this.__restoreFocusNode = this._manager.deepActiveElement;
3049 this._preparePositioning();
3050 this.refit();
3051 this._finishPositioning();
3052 if (this.noAutoFocus && document.activeElement === this._focusNode) {
3053 this._focusNode.blur();
3054 this.__restoreFocusNode.focus();
3055 }
3056 },
3057 _renderOpened: function() {
3058 this._finishRenderOpened();
3059 },
3060 _renderClosed: function() {
3061 this._finishRenderClosed();
3062 },
3063 _finishRenderOpened: function() {
3064 this.notifyResize();
3065 this.__isAnimating = false;
3066 var focusableNodes = this._focusableNodes;
3067 this.__firstFocusableNode = focusableNodes[0];
3068 this.__lastFocusableNode = focusableNodes[focusableNodes.length - 1];
3069 this.fire('iron-overlay-opened');
3070 },
3071 _finishRenderClosed: function() {
3072 this.style.display = 'none';
3073 this.style.zIndex = '';
3074 this.notifyResize();
3075 this.__isAnimating = false;
3076 this.fire('iron-overlay-closed', this.closingReason);
3077 },
3078 _preparePositioning: function() {
3079 this.style.transition = this.style.webkitTransition = 'none';
3080 this.style.transform = this.style.webkitTransform = 'none';
3081 this.style.display = '';
3082 },
3083 _finishPositioning: function() {
3084 this.style.display = 'none';
3085 this.scrollTop = this.scrollTop;
3086 this.style.transition = this.style.webkitTransition = '';
3087 this.style.transform = this.style.webkitTransform = '';
3088 this.style.display = '';
3089 this.scrollTop = this.scrollTop;
3090 },
3091 _applyFocus: function() {
3092 if (this.opened) {
3093 if (!this.noAutoFocus) {
3094 this._focusNode.focus();
3095 }
3096 } else {
3097 this._focusNode.blur();
3098 this._focusedChild = null;
3099 if (this.restoreFocusOnClose && this.__restoreFocusNode) {
3100 this.__restoreFocusNode.focus();
3101 }
3102 this.__restoreFocusNode = null;
3103 var currentOverlay = this._manager.currentOverlay();
3104 if (currentOverlay && this !== currentOverlay) {
3105 currentOverlay._applyFocus();
3106 }
3107 }
3108 },
3109 _onCaptureClick: function(event) {
3110 if (!this.noCancelOnOutsideClick) {
3111 this.cancel(event);
3112 }
3113 },
3114 _onCaptureFocus: function(event) {
3115 if (!this.withBackdrop) {
3116 return;
3117 }
3118 var path = Polymer.dom(event).path;
3119 if (path.indexOf(this) === -1) {
3120 event.stopPropagation();
3121 this._applyFocus();
3122 } else {
3123 this._focusedChild = path[0];
3124 }
3125 },
3126 _onCaptureEsc: function(event) {
3127 if (!this.noCancelOnEscKey) {
3128 this.cancel(event);
3129 }
3130 },
3131 _onCaptureTab: function(event) {
3132 if (!this.withBackdrop) {
3133 return;
3134 }
3135 var shift = event.shiftKey;
3136 var nodeToCheck = shift ? this.__firstFocusableNode : this.__lastFocusable Node;
3137 var nodeToSet = shift ? this.__lastFocusableNode : this.__firstFocusableNo de;
3138 var shouldWrap = false;
3139 if (nodeToCheck === nodeToSet) {
3140 shouldWrap = true;
3141 } else {
3142 var focusedNode = this._manager.deepActiveElement;
3143 shouldWrap = focusedNode === nodeToCheck || focusedNode === this;
3144 }
3145 if (shouldWrap) {
3146 event.preventDefault();
3147 this._focusedChild = nodeToSet;
3148 this._applyFocus();
3149 }
3150 },
3151 _onIronResize: function() {
3152 if (this.opened && !this.__isAnimating) {
3153 this.__onNextAnimationFrame(this.refit);
3154 }
3155 },
3156 _onNodesChange: function() {
3157 if (this.opened && !this.__isAnimating) {
3158 this.notifyResize();
3159 }
3160 },
3161 __openedChanged: function() {
3162 if (this.opened) {
3163 this._prepareRenderOpened();
3164 this._manager.addOverlay(this);
3165 this._applyFocus();
3166 this._renderOpened();
3167 } else {
3168 this._manager.removeOverlay(this);
3169 this._applyFocus();
3170 this._renderClosed();
3171 }
3172 },
3173 __onNextAnimationFrame: function(callback) {
3174 if (this.__raf) {
3175 window.cancelAnimationFrame(this.__raf);
3176 }
3177 var self = this;
3178 this.__raf = window.requestAnimationFrame(function nextAnimationFrame() {
3179 self.__raf = null;
3180 callback.call(self);
3181 });
3182 }
3183 };
3184 Polymer.IronOverlayBehavior = [ Polymer.IronFitBehavior, Polymer.IronResizable Behavior, Polymer.IronOverlayBehaviorImpl ];
3185 })();
3186
3187 (function() {
3188 var metaDatas = {};
3189 var metaArrays = {};
3190 var singleton = null;
3191 Polymer.IronMeta = Polymer({
3192 is: 'iron-meta',
3193 properties: {
3194 type: {
3195 type: String,
3196 value: 'default',
3197 observer: '_typeChanged'
3198 },
3199 key: {
3200 type: String,
3201 observer: '_keyChanged'
3202 },
3203 value: {
3204 type: Object,
3205 notify: true,
3206 observer: '_valueChanged'
3207 },
3208 self: {
3209 type: Boolean,
3210 observer: '_selfChanged'
3211 },
3212 list: {
3213 type: Array,
3214 notify: true
3215 }
3216 },
3217 hostAttributes: {
3218 hidden: true
3219 },
3220 factoryImpl: function(config) {
3221 if (config) {
3222 for (var n in config) {
3223 switch (n) {
3224 case 'type':
3225 case 'key':
3226 case 'value':
3227 this[n] = config[n];
3228 break;
3229 }
3230 }
3231 }
3232 },
3233 created: function() {
3234 this._metaDatas = metaDatas;
3235 this._metaArrays = metaArrays;
3236 },
3237 _keyChanged: function(key, old) {
3238 this._resetRegistration(old);
3239 },
3240 _valueChanged: function(value) {
3241 this._resetRegistration(this.key);
3242 },
3243 _selfChanged: function(self) {
3244 if (self) {
3245 this.value = this;
3246 }
3247 },
3248 _typeChanged: function(type) {
3249 this._unregisterKey(this.key);
3250 if (!metaDatas[type]) {
3251 metaDatas[type] = {};
3252 }
3253 this._metaData = metaDatas[type];
3254 if (!metaArrays[type]) {
3255 metaArrays[type] = [];
3256 }
3257 this.list = metaArrays[type];
3258 this._registerKeyValue(this.key, this.value);
3259 },
3260 byKey: function(key) {
3261 return this._metaData && this._metaData[key];
3262 },
3263 _resetRegistration: function(oldKey) {
3264 this._unregisterKey(oldKey);
3265 this._registerKeyValue(this.key, this.value);
3266 },
3267 _unregisterKey: function(key) {
3268 this._unregister(key, this._metaData, this.list);
3269 },
3270 _registerKeyValue: function(key, value) {
3271 this._register(key, value, this._metaData, this.list);
3272 },
3273 _register: function(key, value, data, list) {
3274 if (key && data && value !== undefined) {
3275 data[key] = value;
3276 list.push(value);
3277 }
3278 },
3279 _unregister: function(key, data, list) {
3280 if (key && data) {
3281 if (key in data) {
3282 var value = data[key];
3283 delete data[key];
3284 this.arrayDelete(list, value);
3285 }
3286 }
3287 }
3288 });
3289 Polymer.IronMeta.getIronMeta = function getIronMeta() {
3290 if (singleton === null) {
3291 singleton = new Polymer.IronMeta();
3292 }
3293 return singleton;
3294 };
3295 Polymer.IronMetaQuery = Polymer({
3296 is: 'iron-meta-query',
3297 properties: {
3298 type: {
3299 type: String,
3300 value: 'default',
3301 observer: '_typeChanged'
3302 },
3303 key: {
3304 type: String,
3305 observer: '_keyChanged'
3306 },
3307 value: {
3308 type: Object,
3309 notify: true,
3310 readOnly: true
3311 },
3312 list: {
3313 type: Array,
3314 notify: true
3315 }
3316 },
3317 factoryImpl: function(config) {
3318 if (config) {
3319 for (var n in config) {
3320 switch (n) {
3321 case 'type':
3322 case 'key':
3323 this[n] = config[n];
3324 break;
3325 }
3326 }
3327 }
3328 },
3329 created: function() {
3330 this._metaDatas = metaDatas;
3331 this._metaArrays = metaArrays;
3332 },
3333 _keyChanged: function(key) {
3334 this._setValue(this._metaData && this._metaData[key]);
3335 },
3336 _typeChanged: function(type) {
3337 this._metaData = metaDatas[type];
3338 this.list = metaArrays[type];
3339 if (this.key) {
3340 this._keyChanged(this.key);
3341 }
3342 },
3343 byKey: function(key) {
3344 return this._metaData && this._metaData[key];
3345 }
3346 });
3347 })();
3348
3349 Polymer.NeonAnimatableBehavior = {
3350 properties: {
3351 animationConfig: {
3352 type: Object
3353 },
3354 entryAnimation: {
3355 observer: '_entryAnimationChanged',
3356 type: String
3357 },
3358 exitAnimation: {
3359 observer: '_exitAnimationChanged',
3360 type: String
3361 }
3362 },
3363 _entryAnimationChanged: function() {
3364 this.animationConfig = this.animationConfig || {};
3365 this.animationConfig['entry'] = [ {
3366 name: this.entryAnimation,
3367 node: this
3368 } ];
3369 },
3370 _exitAnimationChanged: function() {
3371 this.animationConfig = this.animationConfig || {};
3372 this.animationConfig['exit'] = [ {
3373 name: this.exitAnimation,
3374 node: this
3375 } ];
3376 },
3377 _copyProperties: function(config1, config2) {
3378 for (var property in config2) {
3379 config1[property] = config2[property];
3380 }
3381 },
3382 _cloneConfig: function(config) {
3383 var clone = {
3384 isClone: true
3385 };
3386 this._copyProperties(clone, config);
3387 return clone;
3388 },
3389 _getAnimationConfigRecursive: function(type, map, allConfigs) {
3390 if (!this.animationConfig) {
3391 return;
3392 }
3393 if (this.animationConfig.value && typeof this.animationConfig.value === 'fun ction') {
3394 this._warn(this._logf('playAnimation', "Please put 'animationConfig' insid e of your components 'properties' object instead of outside of it."));
3395 return;
3396 }
3397 var thisConfig;
3398 if (type) {
3399 thisConfig = this.animationConfig[type];
3400 } else {
3401 thisConfig = this.animationConfig;
3402 }
3403 if (!Array.isArray(thisConfig)) {
3404 thisConfig = [ thisConfig ];
3405 }
3406 if (thisConfig) {
3407 for (var config, index = 0; config = thisConfig[index]; index++) {
3408 if (config.animatable) {
3409 config.animatable._getAnimationConfigRecursive(config.type || type, ma p, allConfigs);
3410 } else {
3411 if (config.id) {
3412 var cachedConfig = map[config.id];
3413 if (cachedConfig) {
3414 if (!cachedConfig.isClone) {
3415 map[config.id] = this._cloneConfig(cachedConfig);
3416 cachedConfig = map[config.id];
3417 }
3418 this._copyProperties(cachedConfig, config);
3419 } else {
3420 map[config.id] = config;
3421 }
3422 } else {
3423 allConfigs.push(config);
3424 }
3425 }
3426 }
3427 }
3428 },
3429 getAnimationConfig: function(type) {
3430 var map = {};
3431 var allConfigs = [];
3432 this._getAnimationConfigRecursive(type, map, allConfigs);
3433 for (var key in map) {
3434 allConfigs.push(map[key]);
3435 }
3436 return allConfigs;
3437 }
3438 };
3439
3440 Polymer.NeonAnimationRunnerBehaviorImpl = {
3441 _configureAnimations: function(configs) {
3442 var results = [];
3443 if (configs.length > 0) {
3444 for (var config, index = 0; config = configs[index]; index++) {
3445 var neonAnimation = document.createElement(config.name);
3446 if (neonAnimation.isNeonAnimation) {
3447 var result = null;
3448 try {
3449 result = neonAnimation.configure(config);
3450 if (typeof result.cancel != 'function') {
3451 result = document.timeline.play(result);
3452 }
3453 } catch (e) {
3454 result = null;
3455 console.warn('Couldnt play', '(', config.name, ').', e);
3456 }
3457 if (result) {
3458 results.push({
3459 neonAnimation: neonAnimation,
3460 config: config,
3461 animation: result
3462 });
3463 }
3464 } else {
3465 console.warn(this.is + ':', config.name, 'not found!');
3466 }
3467 }
3468 }
3469 return results;
3470 },
3471 _shouldComplete: function(activeEntries) {
3472 var finished = true;
3473 for (var i = 0; i < activeEntries.length; i++) {
3474 if (activeEntries[i].animation.playState != 'finished') {
3475 finished = false;
3476 break;
3477 }
3478 }
3479 return finished;
3480 },
3481 _complete: function(activeEntries) {
3482 for (var i = 0; i < activeEntries.length; i++) {
3483 activeEntries[i].neonAnimation.complete(activeEntries[i].config);
3484 }
3485 for (var i = 0; i < activeEntries.length; i++) {
3486 activeEntries[i].animation.cancel();
3487 }
3488 },
3489 playAnimation: function(type, cookie) {
3490 var configs = this.getAnimationConfig(type);
3491 if (!configs) {
3492 return;
3493 }
3494 this._active = this._active || {};
3495 if (this._active[type]) {
3496 this._complete(this._active[type]);
3497 delete this._active[type];
3498 }
3499 var activeEntries = this._configureAnimations(configs);
3500 if (activeEntries.length == 0) {
3501 this.fire('neon-animation-finish', cookie, {
3502 bubbles: false
3503 });
3504 return;
3505 }
3506 this._active[type] = activeEntries;
3507 for (var i = 0; i < activeEntries.length; i++) {
3508 activeEntries[i].animation.onfinish = function() {
3509 if (this._shouldComplete(activeEntries)) {
3510 this._complete(activeEntries);
3511 delete this._active[type];
3512 this.fire('neon-animation-finish', cookie, {
3513 bubbles: false
3514 });
3515 }
3516 }.bind(this);
3517 }
3518 },
3519 cancelAnimation: function() {
3520 for (var k in this._animations) {
3521 this._animations[k].cancel();
3522 }
3523 this._animations = {};
3524 }
3525 };
3526
3527 Polymer.NeonAnimationRunnerBehavior = [ Polymer.NeonAnimatableBehavior, Polymer. NeonAnimationRunnerBehaviorImpl ];
3528
3529 Polymer.NeonAnimationBehavior = {
3530 properties: {
3531 animationTiming: {
3532 type: Object,
3533 value: function() {
3534 return {
3535 duration: 500,
3536 easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
3537 fill: 'both'
3538 };
3539 }
3540 }
3541 },
3542 isNeonAnimation: true,
3543 timingFromConfig: function(config) {
3544 if (config.timing) {
3545 for (var property in config.timing) {
3546 this.animationTiming[property] = config.timing[property];
3547 }
3548 }
3549 return this.animationTiming;
3550 },
3551 setPrefixedProperty: function(node, property, value) {
3552 var map = {
3553 transform: [ 'webkitTransform' ],
3554 transformOrigin: [ 'mozTransformOrigin', 'webkitTransformOrigin' ]
3555 };
3556 var prefixes = map[property];
3557 for (var prefix, index = 0; prefix = prefixes[index]; index++) {
3558 node.style[prefix] = value;
3559 }
3560 node.style[property] = value;
3561 },
3562 complete: function() {}
3563 };
3564
3565 Polymer({
3566 is: 'opaque-animation',
3567 behaviors: [ Polymer.NeonAnimationBehavior ],
3568 configure: function(config) {
3569 var node = config.node;
3570 this._effect = new KeyframeEffect(node, [ {
3571 opacity: '1'
3572 }, {
3573 opacity: '1'
3574 } ], this.timingFromConfig(config));
3575 node.style.opacity = '0';
3576 return this._effect;
3577 },
3578 complete: function(config) {
3579 config.node.style.opacity = '';
3580 }
3581 });
3582
3583 (function() {
3584 'use strict';
3585 var LAST_TOUCH_POSITION = {
3586 pageX: 0,
3587 pageY: 0
3588 };
3589 var ROOT_TARGET = null;
3590 var SCROLLABLE_NODES = [];
3591 Polymer.IronDropdownScrollManager = {
3592 get currentLockingElement() {
3593 return this._lockingElements[this._lockingElements.length - 1];
3594 },
3595 elementIsScrollLocked: function(element) {
3596 var currentLockingElement = this.currentLockingElement;
3597 if (currentLockingElement === undefined) return false;
3598 var scrollLocked;
3599 if (this._hasCachedLockedElement(element)) {
3600 return true;
3601 }
3602 if (this._hasCachedUnlockedElement(element)) {
3603 return false;
3604 }
3605 scrollLocked = !!currentLockingElement && currentLockingElement !== elemen t && !this._composedTreeContains(currentLockingElement, element);
3606 if (scrollLocked) {
3607 this._lockedElementCache.push(element);
3608 } else {
3609 this._unlockedElementCache.push(element);
3610 }
3611 return scrollLocked;
3612 },
3613 pushScrollLock: function(element) {
3614 if (this._lockingElements.indexOf(element) >= 0) {
3615 return;
3616 }
3617 if (this._lockingElements.length === 0) {
3618 this._lockScrollInteractions();
3619 }
3620 this._lockingElements.push(element);
3621 this._lockedElementCache = [];
3622 this._unlockedElementCache = [];
3623 },
3624 removeScrollLock: function(element) {
3625 var index = this._lockingElements.indexOf(element);
3626 if (index === -1) {
3627 return;
3628 }
3629 this._lockingElements.splice(index, 1);
3630 this._lockedElementCache = [];
3631 this._unlockedElementCache = [];
3632 if (this._lockingElements.length === 0) {
3633 this._unlockScrollInteractions();
3634 }
3635 },
3636 _lockingElements: [],
3637 _lockedElementCache: null,
3638 _unlockedElementCache: null,
3639 _hasCachedLockedElement: function(element) {
3640 return this._lockedElementCache.indexOf(element) > -1;
3641 },
3642 _hasCachedUnlockedElement: function(element) {
3643 return this._unlockedElementCache.indexOf(element) > -1;
3644 },
3645 _composedTreeContains: function(element, child) {
3646 var contentElements;
3647 var distributedNodes;
3648 var contentIndex;
3649 var nodeIndex;
3650 if (element.contains(child)) {
3651 return true;
3652 }
3653 contentElements = Polymer.dom(element).querySelectorAll('content');
3654 for (contentIndex = 0; contentIndex < contentElements.length; ++contentInd ex) {
3655 distributedNodes = Polymer.dom(contentElements[contentIndex]).getDistrib utedNodes();
3656 for (nodeIndex = 0; nodeIndex < distributedNodes.length; ++nodeIndex) {
3657 if (this._composedTreeContains(distributedNodes[nodeIndex], child)) {
3658 return true;
3659 }
3660 }
3661 }
3662 return false;
3663 },
3664 _scrollInteractionHandler: function(event) {
3665 if (event.cancelable && this._shouldPreventScrolling(event)) {
3666 event.preventDefault();
3667 }
3668 if (event.targetTouches) {
3669 var touch = event.targetTouches[0];
3670 LAST_TOUCH_POSITION.pageX = touch.pageX;
3671 LAST_TOUCH_POSITION.pageY = touch.pageY;
3672 }
3673 },
3674 _lockScrollInteractions: function() {
3675 this._boundScrollHandler = this._boundScrollHandler || this._scrollInterac tionHandler.bind(this);
3676 document.addEventListener('wheel', this._boundScrollHandler, true);
3677 document.addEventListener('mousewheel', this._boundScrollHandler, true);
3678 document.addEventListener('DOMMouseScroll', this._boundScrollHandler, true );
3679 document.addEventListener('touchstart', this._boundScrollHandler, true);
3680 document.addEventListener('touchmove', this._boundScrollHandler, true);
3681 },
3682 _unlockScrollInteractions: function() {
3683 document.removeEventListener('wheel', this._boundScrollHandler, true);
3684 document.removeEventListener('mousewheel', this._boundScrollHandler, true) ;
3685 document.removeEventListener('DOMMouseScroll', this._boundScrollHandler, t rue);
3686 document.removeEventListener('touchstart', this._boundScrollHandler, true) ;
3687 document.removeEventListener('touchmove', this._boundScrollHandler, true);
3688 },
3689 _shouldPreventScrolling: function(event) {
3690 var target = Polymer.dom(event).rootTarget;
3691 if (event.type !== 'touchmove' && ROOT_TARGET !== target) {
3692 ROOT_TARGET = target;
3693 SCROLLABLE_NODES = this._getScrollableNodes(Polymer.dom(event).path);
3694 }
3695 if (!SCROLLABLE_NODES.length) {
3696 return true;
3697 }
3698 if (event.type === 'touchstart') {
3699 return false;
3700 }
3701 var info = this._getScrollInfo(event);
3702 return !this._getScrollingNode(SCROLLABLE_NODES, info.deltaX, info.deltaY) ;
3703 },
3704 _getScrollableNodes: function(nodes) {
3705 var scrollables = [];
3706 var lockingIndex = nodes.indexOf(this.currentLockingElement);
3707 for (var i = 0; i <= lockingIndex; i++) {
3708 var node = nodes[i];
3709 if (node.nodeType === 11) {
3710 continue;
3711 }
3712 var style = node.style;
3713 if (style.overflow !== 'scroll' && style.overflow !== 'auto') {
3714 style = window.getComputedStyle(node);
3715 }
3716 if (style.overflow === 'scroll' || style.overflow === 'auto') {
3717 scrollables.push(node);
3718 }
3719 }
3720 return scrollables;
3721 },
3722 _getScrollingNode: function(nodes, deltaX, deltaY) {
3723 if (!deltaX && !deltaY) {
3724 return;
3725 }
3726 var verticalScroll = Math.abs(deltaY) >= Math.abs(deltaX);
3727 for (var i = 0; i < nodes.length; i++) {
3728 var node = nodes[i];
3729 var canScroll = false;
3730 if (verticalScroll) {
3731 canScroll = deltaY < 0 ? node.scrollTop > 0 : node.scrollTop < node.sc rollHeight - node.clientHeight;
3732 } else {
3733 canScroll = deltaX < 0 ? node.scrollLeft > 0 : node.scrollLeft < node. scrollWidth - node.clientWidth;
3734 }
3735 if (canScroll) {
3736 return node;
3737 }
3738 }
3739 },
3740 _getScrollInfo: function(event) {
3741 var info = {
3742 deltaX: event.deltaX,
3743 deltaY: event.deltaY
3744 };
3745 if ('deltaX' in event) {} else if ('wheelDeltaX' in event) {
3746 info.deltaX = -event.wheelDeltaX;
3747 info.deltaY = -event.wheelDeltaY;
3748 } else if ('axis' in event) {
3749 info.deltaX = event.axis === 1 ? event.detail : 0;
3750 info.deltaY = event.axis === 2 ? event.detail : 0;
3751 } else if (event.targetTouches) {
3752 var touch = event.targetTouches[0];
3753 info.deltaX = LAST_TOUCH_POSITION.pageX - touch.pageX;
3754 info.deltaY = LAST_TOUCH_POSITION.pageY - touch.pageY;
3755 }
3756 return info;
3757 }
3758 };
3759 })();
3760
3761 (function() {
3762 'use strict';
3763 Polymer({
3764 is: 'iron-dropdown',
3765 behaviors: [ Polymer.IronControlState, Polymer.IronA11yKeysBehavior, Polymer .IronOverlayBehavior, Polymer.NeonAnimationRunnerBehavior ],
3766 properties: {
3767 horizontalAlign: {
3768 type: String,
3769 value: 'left',
3770 reflectToAttribute: true
3771 },
3772 verticalAlign: {
3773 type: String,
3774 value: 'top',
3775 reflectToAttribute: true
3776 },
3777 openAnimationConfig: {
3778 type: Object
3779 },
3780 closeAnimationConfig: {
3781 type: Object
3782 },
3783 focusTarget: {
3784 type: Object
3785 },
3786 noAnimations: {
3787 type: Boolean,
3788 value: false
3789 },
3790 allowOutsideScroll: {
3791 type: Boolean,
3792 value: false
3793 },
3794 _boundOnCaptureScroll: {
3795 type: Function,
3796 value: function() {
3797 return this._onCaptureScroll.bind(this);
3798 }
3799 }
3800 },
3801 listeners: {
3802 'neon-animation-finish': '_onNeonAnimationFinish'
3803 },
3804 observers: [ '_updateOverlayPosition(positionTarget, verticalAlign, horizont alAlign, verticalOffset, horizontalOffset)' ],
3805 get containedElement() {
3806 return Polymer.dom(this.$.content).getDistributedNodes()[0];
3807 },
3808 get _focusTarget() {
3809 return this.focusTarget || this.containedElement;
3810 },
3811 ready: function() {
3812 this._scrollTop = 0;
3813 this._scrollLeft = 0;
3814 this._refitOnScrollRAF = null;
3815 },
3816 attached: function() {
3817 if (!this.sizingTarget || this.sizingTarget === this) {
3818 this.sizingTarget = this.containedElement;
3819 }
3820 },
3821 detached: function() {
3822 this.cancelAnimation();
3823 document.removeEventListener('scroll', this._boundOnCaptureScroll);
3824 Polymer.IronDropdownScrollManager.removeScrollLock(this);
3825 },
3826 _openedChanged: function() {
3827 if (this.opened && this.disabled) {
3828 this.cancel();
3829 } else {
3830 this.cancelAnimation();
3831 this._updateAnimationConfig();
3832 this._saveScrollPosition();
3833 if (this.opened) {
3834 document.addEventListener('scroll', this._boundOnCaptureScroll);
3835 !this.allowOutsideScroll && Polymer.IronDropdownScrollManager.pushScro llLock(this);
3836 } else {
3837 document.removeEventListener('scroll', this._boundOnCaptureScroll);
3838 Polymer.IronDropdownScrollManager.removeScrollLock(this);
3839 }
3840 Polymer.IronOverlayBehaviorImpl._openedChanged.apply(this, arguments);
3841 }
3842 },
3843 _renderOpened: function() {
3844 if (!this.noAnimations && this.animationConfig.open) {
3845 this.$.contentWrapper.classList.add('animating');
3846 this.playAnimation('open');
3847 } else {
3848 Polymer.IronOverlayBehaviorImpl._renderOpened.apply(this, arguments);
3849 }
3850 },
3851 _renderClosed: function() {
3852 if (!this.noAnimations && this.animationConfig.close) {
3853 this.$.contentWrapper.classList.add('animating');
3854 this.playAnimation('close');
3855 } else {
3856 Polymer.IronOverlayBehaviorImpl._renderClosed.apply(this, arguments);
3857 }
3858 },
3859 _onNeonAnimationFinish: function() {
3860 this.$.contentWrapper.classList.remove('animating');
3861 if (this.opened) {
3862 this._finishRenderOpened();
3863 } else {
3864 this._finishRenderClosed();
3865 }
3866 },
3867 _onCaptureScroll: function() {
3868 if (!this.allowOutsideScroll) {
3869 this._restoreScrollPosition();
3870 } else {
3871 this._refitOnScrollRAF && window.cancelAnimationFrame(this._refitOnScrol lRAF);
3872 this._refitOnScrollRAF = window.requestAnimationFrame(this.refit.bind(th is));
3873 }
3874 },
3875 _saveScrollPosition: function() {
3876 if (document.scrollingElement) {
3877 this._scrollTop = document.scrollingElement.scrollTop;
3878 this._scrollLeft = document.scrollingElement.scrollLeft;
3879 } else {
3880 this._scrollTop = Math.max(document.documentElement.scrollTop, document. body.scrollTop);
3881 this._scrollLeft = Math.max(document.documentElement.scrollLeft, documen t.body.scrollLeft);
3882 }
3883 },
3884 _restoreScrollPosition: function() {
3885 if (document.scrollingElement) {
3886 document.scrollingElement.scrollTop = this._scrollTop;
3887 document.scrollingElement.scrollLeft = this._scrollLeft;
3888 } else {
3889 document.documentElement.scrollTop = this._scrollTop;
3890 document.documentElement.scrollLeft = this._scrollLeft;
3891 document.body.scrollTop = this._scrollTop;
3892 document.body.scrollLeft = this._scrollLeft;
3893 }
3894 },
3895 _updateAnimationConfig: function() {
3896 var animations = (this.openAnimationConfig || []).concat(this.closeAnimati onConfig || []);
3897 for (var i = 0; i < animations.length; i++) {
3898 animations[i].node = this.containedElement;
3899 }
3900 this.animationConfig = {
3901 open: this.openAnimationConfig,
3902 close: this.closeAnimationConfig
3903 };
3904 },
3905 _updateOverlayPosition: function() {
3906 if (this.isAttached) {
3907 this.notifyResize();
3908 }
3909 },
3910 _applyFocus: function() {
3911 var focusTarget = this.focusTarget || this.containedElement;
3912 if (focusTarget && this.opened && !this.noAutoFocus) {
3913 focusTarget.focus();
3914 } else {
3915 Polymer.IronOverlayBehaviorImpl._applyFocus.apply(this, arguments);
3916 }
3917 }
3918 });
3919 })();
3920
3921 Polymer({
3922 is: 'iron-icon',
3923 properties: {
3924 icon: {
3925 type: String,
3926 observer: '_iconChanged'
3927 },
3928 theme: {
3929 type: String,
3930 observer: '_updateIcon'
3931 },
3932 src: {
3933 type: String,
3934 observer: '_srcChanged'
3935 },
3936 _meta: {
3937 value: Polymer.Base.create('iron-meta', {
3938 type: 'iconset'
3939 }),
3940 observer: '_updateIcon'
3941 }
3942 },
3943 _DEFAULT_ICONSET: 'icons',
3944 _iconChanged: function(icon) {
3945 var parts = (icon || '').split(':');
3946 this._iconName = parts.pop();
3947 this._iconsetName = parts.pop() || this._DEFAULT_ICONSET;
3948 this._updateIcon();
3949 },
3950 _srcChanged: function(src) {
3951 this._updateIcon();
3952 },
3953 _usesIconset: function() {
3954 return this.icon || !this.src;
3955 },
3956 _updateIcon: function() {
3957 if (this._usesIconset()) {
3958 if (this._img && this._img.parentNode) {
3959 Polymer.dom(this.root).removeChild(this._img);
3960 }
3961 if (this._iconName === "") {
3962 if (this._iconset) {
3963 this._iconset.removeIcon(this);
3964 }
3965 } else if (this._iconsetName && this._meta) {
3966 this._iconset = this._meta.byKey(this._iconsetName);
3967 if (this._iconset) {
3968 this._iconset.applyIcon(this, this._iconName, this.theme);
3969 this.unlisten(window, 'iron-iconset-added', '_updateIcon');
3970 } else {
3971 this.listen(window, 'iron-iconset-added', '_updateIcon');
3972 }
3973 }
3974 } else {
3975 if (this._iconset) {
3976 this._iconset.removeIcon(this);
3977 }
3978 if (!this._img) {
3979 this._img = document.createElement('img');
3980 this._img.style.width = '100%';
3981 this._img.style.height = '100%';
3982 this._img.draggable = false;
3983 }
3984 this._img.src = this.src;
3985 Polymer.dom(this.root).appendChild(this._img);
3986 }
3987 }
3988 });
3989
3990 Polymer.IronButtonStateImpl = { 2182 Polymer.IronButtonStateImpl = {
3991 properties: { 2183 properties: {
3992 pressed: { 2184 pressed: {
3993 type: Boolean, 2185 type: Boolean,
3994 readOnly: true, 2186 readOnly: true,
3995 value: false, 2187 value: false,
3996 reflectToAttribute: true, 2188 reflectToAttribute: true,
3997 observer: '_pressedChanged' 2189 observer: '_pressedChanged'
3998 }, 2190 },
3999 toggles: { 2191 toggles: {
(...skipping 528 matching lines...) Expand 10 before | Expand all | Expand 10 after
4528 _createRipple: function() { 2720 _createRipple: function() {
4529 return document.createElement('paper-ripple'); 2721 return document.createElement('paper-ripple');
4530 }, 2722 },
4531 _noinkChanged: function(noink) { 2723 _noinkChanged: function(noink) {
4532 if (this.hasRipple()) { 2724 if (this.hasRipple()) {
4533 this._ripple.noink = noink; 2725 this._ripple.noink = noink;
4534 } 2726 }
4535 } 2727 }
4536 }; 2728 };
4537 2729
4538 Polymer.PaperButtonBehaviorImpl = {
4539 properties: {
4540 elevation: {
4541 type: Number,
4542 reflectToAttribute: true,
4543 readOnly: true
4544 }
4545 },
4546 observers: [ '_calculateElevation(focused, disabled, active, pressed, received FocusFromKeyboard)', '_computeKeyboardClass(receivedFocusFromKeyboard)' ],
4547 hostAttributes: {
4548 role: 'button',
4549 tabindex: '0',
4550 animated: true
4551 },
4552 _calculateElevation: function() {
4553 var e = 1;
4554 if (this.disabled) {
4555 e = 0;
4556 } else if (this.active || this.pressed) {
4557 e = 4;
4558 } else if (this.receivedFocusFromKeyboard) {
4559 e = 3;
4560 }
4561 this._setElevation(e);
4562 },
4563 _computeKeyboardClass: function(receivedFocusFromKeyboard) {
4564 this.toggleClass('keyboard-focus', receivedFocusFromKeyboard);
4565 },
4566 _spaceKeyDownHandler: function(event) {
4567 Polymer.IronButtonStateImpl._spaceKeyDownHandler.call(this, event);
4568 if (this.hasRipple() && this.getRipple().ripples.length < 1) {
4569 this._ripple.uiDownAction();
4570 }
4571 },
4572 _spaceKeyUpHandler: function(event) {
4573 Polymer.IronButtonStateImpl._spaceKeyUpHandler.call(this, event);
4574 if (this.hasRipple()) {
4575 this._ripple.uiUpAction();
4576 }
4577 }
4578 };
4579
4580 Polymer.PaperButtonBehavior = [ Polymer.IronButtonState, Polymer.IronControlStat e, Polymer.PaperRippleBehavior, Polymer.PaperButtonBehaviorImpl ];
4581
4582 Polymer({
4583 is: 'paper-button',
4584 behaviors: [ Polymer.PaperButtonBehavior ],
4585 properties: {
4586 raised: {
4587 type: Boolean,
4588 reflectToAttribute: true,
4589 value: false,
4590 observer: '_calculateElevation'
4591 }
4592 },
4593 _calculateElevation: function() {
4594 if (!this.raised) {
4595 this._setElevation(0);
4596 } else {
4597 Polymer.PaperButtonBehaviorImpl._calculateElevation.apply(this);
4598 }
4599 }
4600 });
4601
4602 Polymer({
4603 is: 'paper-icon-button-light',
4604 "extends": 'button',
4605 behaviors: [ Polymer.PaperRippleBehavior ],
4606 listeners: {
4607 down: '_rippleDown',
4608 up: '_rippleUp',
4609 focus: '_rippleDown',
4610 blur: '_rippleUp'
4611 },
4612 _rippleDown: function() {
4613 this.getRipple().downAction();
4614 },
4615 _rippleUp: function() {
4616 this.getRipple().upAction();
4617 },
4618 ensureRipple: function(var_args) {
4619 var lastRipple = this._ripple;
4620 Polymer.PaperRippleBehavior.ensureRipple.apply(this, arguments);
4621 if (this._ripple && this._ripple !== lastRipple) {
4622 this._ripple.center = true;
4623 this._ripple.classList.add('circle');
4624 }
4625 }
4626 });
4627
4628 Polymer.PaperInkyFocusBehaviorImpl = { 2730 Polymer.PaperInkyFocusBehaviorImpl = {
4629 observers: [ '_focusedChanged(receivedFocusFromKeyboard)' ], 2731 observers: [ '_focusedChanged(receivedFocusFromKeyboard)' ],
4630 _focusedChanged: function(receivedFocusFromKeyboard) { 2732 _focusedChanged: function(receivedFocusFromKeyboard) {
4631 if (receivedFocusFromKeyboard) { 2733 if (receivedFocusFromKeyboard) {
4632 this.ensureRipple(); 2734 this.ensureRipple();
4633 } 2735 }
4634 if (this.hasRipple()) { 2736 if (this.hasRipple()) {
4635 this._ripple.holdDown = receivedFocusFromKeyboard; 2737 this._ripple.holdDown = receivedFocusFromKeyboard;
4636 } 2738 }
4637 }, 2739 },
(...skipping 29 matching lines...) Expand all
4667 }, 2769 },
4668 _altChanged: function(newValue, oldValue) { 2770 _altChanged: function(newValue, oldValue) {
4669 var label = this.getAttribute('aria-label'); 2771 var label = this.getAttribute('aria-label');
4670 if (!label || oldValue == label) { 2772 if (!label || oldValue == label) {
4671 this.setAttribute('aria-label', newValue); 2773 this.setAttribute('aria-label', newValue);
4672 } 2774 }
4673 } 2775 }
4674 }); 2776 });
4675 2777
4676 Polymer({ 2778 Polymer({
4677 is: 'paper-tab',
4678 behaviors: [ Polymer.IronControlState, Polymer.IronButtonState, Polymer.PaperR ippleBehavior ],
4679 properties: {
4680 link: {
4681 type: Boolean,
4682 value: false,
4683 reflectToAttribute: true
4684 }
4685 },
4686 hostAttributes: {
4687 role: 'tab'
4688 },
4689 listeners: {
4690 down: '_updateNoink',
4691 tap: '_onTap'
4692 },
4693 attached: function() {
4694 this._updateNoink();
4695 },
4696 get _parentNoink() {
4697 var parent = Polymer.dom(this).parentNode;
4698 return !!parent && !!parent.noink;
4699 },
4700 _updateNoink: function() {
4701 this.noink = !!this.noink || !!this._parentNoink;
4702 },
4703 _onTap: function(event) {
4704 if (this.link) {
4705 var anchor = this.queryEffectiveChildren('a');
4706 if (!anchor) {
4707 return;
4708 }
4709 if (event.target === anchor) {
4710 return;
4711 }
4712 anchor.click();
4713 }
4714 }
4715 });
4716
4717 Polymer.IronMultiSelectableBehaviorImpl = {
4718 properties: {
4719 multi: {
4720 type: Boolean,
4721 value: false,
4722 observer: 'multiChanged'
4723 },
4724 selectedValues: {
4725 type: Array,
4726 notify: true
4727 },
4728 selectedItems: {
4729 type: Array,
4730 readOnly: true,
4731 notify: true
4732 }
4733 },
4734 observers: [ '_updateSelected(selectedValues.splices)' ],
4735 select: function(value) {
4736 if (this.multi) {
4737 if (this.selectedValues) {
4738 this._toggleSelected(value);
4739 } else {
4740 this.selectedValues = [ value ];
4741 }
4742 } else {
4743 this.selected = value;
4744 }
4745 },
4746 multiChanged: function(multi) {
4747 this._selection.multi = multi;
4748 },
4749 get _shouldUpdateSelection() {
4750 return this.selected != null || this.selectedValues != null && this.selected Values.length;
4751 },
4752 _updateAttrForSelected: function() {
4753 if (!this.multi) {
4754 Polymer.IronSelectableBehavior._updateAttrForSelected.apply(this);
4755 } else if (this._shouldUpdateSelection) {
4756 this.selectedValues = this.selectedItems.map(function(selectedItem) {
4757 return this._indexToValue(this.indexOf(selectedItem));
4758 }, this).filter(function(unfilteredValue) {
4759 return unfilteredValue != null;
4760 }, this);
4761 }
4762 },
4763 _updateSelected: function() {
4764 if (this.multi) {
4765 this._selectMulti(this.selectedValues);
4766 } else {
4767 this._selectSelected(this.selected);
4768 }
4769 },
4770 _selectMulti: function(values) {
4771 if (values) {
4772 var selectedItems = this._valuesToItems(values);
4773 this._selection.clear(selectedItems);
4774 for (var i = 0; i < selectedItems.length; i++) {
4775 this._selection.setItemSelected(selectedItems[i], true);
4776 }
4777 if (this.fallbackSelection && this.items.length && !this._selection.get(). length) {
4778 var fallback = this._valueToItem(this.fallbackSelection);
4779 if (fallback) {
4780 this.selectedValues = [ this.fallbackSelection ];
4781 }
4782 }
4783 } else {
4784 this._selection.clear();
4785 }
4786 },
4787 _selectionChange: function() {
4788 var s = this._selection.get();
4789 if (this.multi) {
4790 this._setSelectedItems(s);
4791 } else {
4792 this._setSelectedItems([ s ]);
4793 this._setSelectedItem(s);
4794 }
4795 },
4796 _toggleSelected: function(value) {
4797 var i = this.selectedValues.indexOf(value);
4798 var unselected = i < 0;
4799 if (unselected) {
4800 this.push('selectedValues', value);
4801 } else {
4802 this.splice('selectedValues', i, 1);
4803 }
4804 },
4805 _valuesToItems: function(values) {
4806 return values == null ? null : values.map(function(value) {
4807 return this._valueToItem(value);
4808 }, this);
4809 }
4810 };
4811
4812 Polymer.IronMultiSelectableBehavior = [ Polymer.IronSelectableBehavior, Polymer. IronMultiSelectableBehaviorImpl ];
4813
4814 Polymer.IronMenuBehaviorImpl = {
4815 properties: {
4816 focusedItem: {
4817 observer: '_focusedItemChanged',
4818 readOnly: true,
4819 type: Object
4820 },
4821 attrForItemTitle: {
4822 type: String
4823 }
4824 },
4825 hostAttributes: {
4826 role: 'menu',
4827 tabindex: '0'
4828 },
4829 observers: [ '_updateMultiselectable(multi)' ],
4830 listeners: {
4831 focus: '_onFocus',
4832 keydown: '_onKeydown',
4833 'iron-items-changed': '_onIronItemsChanged'
4834 },
4835 keyBindings: {
4836 up: '_onUpKey',
4837 down: '_onDownKey',
4838 esc: '_onEscKey',
4839 'shift+tab:keydown': '_onShiftTabDown'
4840 },
4841 attached: function() {
4842 this._resetTabindices();
4843 },
4844 select: function(value) {
4845 if (this._defaultFocusAsync) {
4846 this.cancelAsync(this._defaultFocusAsync);
4847 this._defaultFocusAsync = null;
4848 }
4849 var item = this._valueToItem(value);
4850 if (item && item.hasAttribute('disabled')) return;
4851 this._setFocusedItem(item);
4852 Polymer.IronMultiSelectableBehaviorImpl.select.apply(this, arguments);
4853 },
4854 _resetTabindices: function() {
4855 var selectedItem = this.multi ? this.selectedItems && this.selectedItems[0] : this.selectedItem;
4856 this.items.forEach(function(item) {
4857 item.setAttribute('tabindex', item === selectedItem ? '0' : '-1');
4858 }, this);
4859 },
4860 _updateMultiselectable: function(multi) {
4861 if (multi) {
4862 this.setAttribute('aria-multiselectable', 'true');
4863 } else {
4864 this.removeAttribute('aria-multiselectable');
4865 }
4866 },
4867 _focusWithKeyboardEvent: function(event) {
4868 for (var i = 0, item; item = this.items[i]; i++) {
4869 var attr = this.attrForItemTitle || 'textContent';
4870 var title = item[attr] || item.getAttribute(attr);
4871 if (!item.hasAttribute('disabled') && title && title.trim().charAt(0).toLo werCase() === String.fromCharCode(event.keyCode).toLowerCase()) {
4872 this._setFocusedItem(item);
4873 break;
4874 }
4875 }
4876 },
4877 _focusPrevious: function() {
4878 var length = this.items.length;
4879 var curFocusIndex = Number(this.indexOf(this.focusedItem));
4880 for (var i = 1; i < length + 1; i++) {
4881 var item = this.items[(curFocusIndex - i + length) % length];
4882 if (!item.hasAttribute('disabled')) {
4883 var owner = Polymer.dom(item).getOwnerRoot() || document;
4884 this._setFocusedItem(item);
4885 if (Polymer.dom(owner).activeElement == item) {
4886 return;
4887 }
4888 }
4889 }
4890 },
4891 _focusNext: function() {
4892 var length = this.items.length;
4893 var curFocusIndex = Number(this.indexOf(this.focusedItem));
4894 for (var i = 1; i < length + 1; i++) {
4895 var item = this.items[(curFocusIndex + i) % length];
4896 if (!item.hasAttribute('disabled')) {
4897 var owner = Polymer.dom(item).getOwnerRoot() || document;
4898 this._setFocusedItem(item);
4899 if (Polymer.dom(owner).activeElement == item) {
4900 return;
4901 }
4902 }
4903 }
4904 },
4905 _applySelection: function(item, isSelected) {
4906 if (isSelected) {
4907 item.setAttribute('aria-selected', 'true');
4908 } else {
4909 item.removeAttribute('aria-selected');
4910 }
4911 Polymer.IronSelectableBehavior._applySelection.apply(this, arguments);
4912 },
4913 _focusedItemChanged: function(focusedItem, old) {
4914 old && old.setAttribute('tabindex', '-1');
4915 if (focusedItem) {
4916 focusedItem.setAttribute('tabindex', '0');
4917 focusedItem.focus();
4918 }
4919 },
4920 _onIronItemsChanged: function(event) {
4921 if (event.detail.addedNodes.length) {
4922 this._resetTabindices();
4923 }
4924 },
4925 _onShiftTabDown: function(event) {
4926 var oldTabIndex = this.getAttribute('tabindex');
4927 Polymer.IronMenuBehaviorImpl._shiftTabPressed = true;
4928 this._setFocusedItem(null);
4929 this.setAttribute('tabindex', '-1');
4930 this.async(function() {
4931 this.setAttribute('tabindex', oldTabIndex);
4932 Polymer.IronMenuBehaviorImpl._shiftTabPressed = false;
4933 }, 1);
4934 },
4935 _onFocus: function(event) {
4936 if (Polymer.IronMenuBehaviorImpl._shiftTabPressed) {
4937 return;
4938 }
4939 var rootTarget = Polymer.dom(event).rootTarget;
4940 if (rootTarget !== this && typeof rootTarget.tabIndex !== "undefined" && !th is.isLightDescendant(rootTarget)) {
4941 return;
4942 }
4943 this._defaultFocusAsync = this.async(function() {
4944 var selectedItem = this.multi ? this.selectedItems && this.selectedItems[0 ] : this.selectedItem;
4945 this._setFocusedItem(null);
4946 if (selectedItem) {
4947 this._setFocusedItem(selectedItem);
4948 } else if (this.items[0]) {
4949 this._focusNext();
4950 }
4951 });
4952 },
4953 _onUpKey: function(event) {
4954 this._focusPrevious();
4955 event.detail.keyboardEvent.preventDefault();
4956 },
4957 _onDownKey: function(event) {
4958 this._focusNext();
4959 event.detail.keyboardEvent.preventDefault();
4960 },
4961 _onEscKey: function(event) {
4962 this.focusedItem.blur();
4963 },
4964 _onKeydown: function(event) {
4965 if (!this.keyboardEventMatchesKeys(event, 'up down esc')) {
4966 this._focusWithKeyboardEvent(event);
4967 }
4968 event.stopPropagation();
4969 },
4970 _activateHandler: function(event) {
4971 Polymer.IronSelectableBehavior._activateHandler.call(this, event);
4972 event.stopPropagation();
4973 }
4974 };
4975
4976 Polymer.IronMenuBehaviorImpl._shiftTabPressed = false;
4977
4978 Polymer.IronMenuBehavior = [ Polymer.IronMultiSelectableBehavior, Polymer.IronA1 1yKeysBehavior, Polymer.IronMenuBehaviorImpl ];
4979
4980 Polymer.IronMenubarBehaviorImpl = {
4981 hostAttributes: {
4982 role: 'menubar'
4983 },
4984 keyBindings: {
4985 left: '_onLeftKey',
4986 right: '_onRightKey'
4987 },
4988 _onUpKey: function(event) {
4989 this.focusedItem.click();
4990 event.detail.keyboardEvent.preventDefault();
4991 },
4992 _onDownKey: function(event) {
4993 this.focusedItem.click();
4994 event.detail.keyboardEvent.preventDefault();
4995 },
4996 get _isRTL() {
4997 return window.getComputedStyle(this)['direction'] === 'rtl';
4998 },
4999 _onLeftKey: function(event) {
5000 if (this._isRTL) {
5001 this._focusNext();
5002 } else {
5003 this._focusPrevious();
5004 }
5005 event.detail.keyboardEvent.preventDefault();
5006 },
5007 _onRightKey: function(event) {
5008 if (this._isRTL) {
5009 this._focusPrevious();
5010 } else {
5011 this._focusNext();
5012 }
5013 event.detail.keyboardEvent.preventDefault();
5014 },
5015 _onKeydown: function(event) {
5016 if (this.keyboardEventMatchesKeys(event, 'up down left right esc')) {
5017 return;
5018 }
5019 this._focusWithKeyboardEvent(event);
5020 }
5021 };
5022
5023 Polymer.IronMenubarBehavior = [ Polymer.IronMenuBehavior, Polymer.IronMenubarBeh aviorImpl ];
5024
5025 Polymer({
5026 is: 'iron-iconset-svg', 2779 is: 'iron-iconset-svg',
5027 properties: { 2780 properties: {
5028 name: { 2781 name: {
5029 type: String, 2782 type: String,
5030 observer: '_nameChanged' 2783 observer: '_nameChanged'
5031 }, 2784 },
5032 size: { 2785 size: {
5033 type: Number, 2786 type: Number,
5034 value: 24 2787 value: 24
5035 } 2788 }
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
5089 svg.setAttribute('viewBox', viewBox); 2842 svg.setAttribute('viewBox', viewBox);
5090 svg.setAttribute('preserveAspectRatio', 'xMidYMid meet'); 2843 svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
5091 svg.style.cssText = 'pointer-events: none; display: block; width: 100%; he ight: 100%;'; 2844 svg.style.cssText = 'pointer-events: none; display: block; width: 100%; he ight: 100%;';
5092 svg.appendChild(content).removeAttribute('id'); 2845 svg.appendChild(content).removeAttribute('id');
5093 return svg; 2846 return svg;
5094 } 2847 }
5095 return null; 2848 return null;
5096 } 2849 }
5097 }); 2850 });
5098 2851
5099 Polymer({
5100 is: 'paper-tabs',
5101 behaviors: [ Polymer.IronResizableBehavior, Polymer.IronMenubarBehavior ],
5102 properties: {
5103 noink: {
5104 type: Boolean,
5105 value: false,
5106 observer: '_noinkChanged'
5107 },
5108 noBar: {
5109 type: Boolean,
5110 value: false
5111 },
5112 noSlide: {
5113 type: Boolean,
5114 value: false
5115 },
5116 scrollable: {
5117 type: Boolean,
5118 value: false
5119 },
5120 fitContainer: {
5121 type: Boolean,
5122 value: false
5123 },
5124 disableDrag: {
5125 type: Boolean,
5126 value: false
5127 },
5128 hideScrollButtons: {
5129 type: Boolean,
5130 value: false
5131 },
5132 alignBottom: {
5133 type: Boolean,
5134 value: false
5135 },
5136 selectable: {
5137 type: String,
5138 value: 'paper-tab'
5139 },
5140 autoselect: {
5141 type: Boolean,
5142 value: false
5143 },
5144 autoselectDelay: {
5145 type: Number,
5146 value: 0
5147 },
5148 _step: {
5149 type: Number,
5150 value: 10
5151 },
5152 _holdDelay: {
5153 type: Number,
5154 value: 1
5155 },
5156 _leftHidden: {
5157 type: Boolean,
5158 value: false
5159 },
5160 _rightHidden: {
5161 type: Boolean,
5162 value: false
5163 },
5164 _previousTab: {
5165 type: Object
5166 }
5167 },
5168 hostAttributes: {
5169 role: 'tablist'
5170 },
5171 listeners: {
5172 'iron-resize': '_onTabSizingChanged',
5173 'iron-items-changed': '_onTabSizingChanged',
5174 'iron-select': '_onIronSelect',
5175 'iron-deselect': '_onIronDeselect'
5176 },
5177 keyBindings: {
5178 'left:keyup right:keyup': '_onArrowKeyup'
5179 },
5180 created: function() {
5181 this._holdJob = null;
5182 this._pendingActivationItem = undefined;
5183 this._pendingActivationTimeout = undefined;
5184 this._bindDelayedActivationHandler = this._delayedActivationHandler.bind(thi s);
5185 this.addEventListener('blur', this._onBlurCapture.bind(this), true);
5186 },
5187 ready: function() {
5188 this.setScrollDirection('y', this.$.tabsContainer);
5189 },
5190 detached: function() {
5191 this._cancelPendingActivation();
5192 },
5193 _noinkChanged: function(noink) {
5194 var childTabs = Polymer.dom(this).querySelectorAll('paper-tab');
5195 childTabs.forEach(noink ? this._setNoinkAttribute : this._removeNoinkAttribu te);
5196 },
5197 _setNoinkAttribute: function(element) {
5198 element.setAttribute('noink', '');
5199 },
5200 _removeNoinkAttribute: function(element) {
5201 element.removeAttribute('noink');
5202 },
5203 _computeScrollButtonClass: function(hideThisButton, scrollable, hideScrollButt ons) {
5204 if (!scrollable || hideScrollButtons) {
5205 return 'hidden';
5206 }
5207 if (hideThisButton) {
5208 return 'not-visible';
5209 }
5210 return '';
5211 },
5212 _computeTabsContentClass: function(scrollable, fitContainer) {
5213 return scrollable ? 'scrollable' + (fitContainer ? ' fit-container' : '') : ' fit-container';
5214 },
5215 _computeSelectionBarClass: function(noBar, alignBottom) {
5216 if (noBar) {
5217 return 'hidden';
5218 } else if (alignBottom) {
5219 return 'align-bottom';
5220 }
5221 return '';
5222 },
5223 _onTabSizingChanged: function() {
5224 this.debounce('_onTabSizingChanged', function() {
5225 this._scroll();
5226 this._tabChanged(this.selectedItem);
5227 }, 10);
5228 },
5229 _onIronSelect: function(event) {
5230 this._tabChanged(event.detail.item, this._previousTab);
5231 this._previousTab = event.detail.item;
5232 this.cancelDebouncer('tab-changed');
5233 },
5234 _onIronDeselect: function(event) {
5235 this.debounce('tab-changed', function() {
5236 this._tabChanged(null, this._previousTab);
5237 this._previousTab = null;
5238 }, 1);
5239 },
5240 _activateHandler: function() {
5241 this._cancelPendingActivation();
5242 Polymer.IronMenuBehaviorImpl._activateHandler.apply(this, arguments);
5243 },
5244 _scheduleActivation: function(item, delay) {
5245 this._pendingActivationItem = item;
5246 this._pendingActivationTimeout = this.async(this._bindDelayedActivationHandl er, delay);
5247 },
5248 _delayedActivationHandler: function() {
5249 var item = this._pendingActivationItem;
5250 this._pendingActivationItem = undefined;
5251 this._pendingActivationTimeout = undefined;
5252 item.fire(this.activateEvent, null, {
5253 bubbles: true,
5254 cancelable: true
5255 });
5256 },
5257 _cancelPendingActivation: function() {
5258 if (this._pendingActivationTimeout !== undefined) {
5259 this.cancelAsync(this._pendingActivationTimeout);
5260 this._pendingActivationItem = undefined;
5261 this._pendingActivationTimeout = undefined;
5262 }
5263 },
5264 _onArrowKeyup: function(event) {
5265 if (this.autoselect) {
5266 this._scheduleActivation(this.focusedItem, this.autoselectDelay);
5267 }
5268 },
5269 _onBlurCapture: function(event) {
5270 if (event.target === this._pendingActivationItem) {
5271 this._cancelPendingActivation();
5272 }
5273 },
5274 get _tabContainerScrollSize() {
5275 return Math.max(0, this.$.tabsContainer.scrollWidth - this.$.tabsContainer.o ffsetWidth);
5276 },
5277 _scroll: function(e, detail) {
5278 if (!this.scrollable) {
5279 return;
5280 }
5281 var ddx = detail && -detail.ddx || 0;
5282 this._affectScroll(ddx);
5283 },
5284 _down: function(e) {
5285 this.async(function() {
5286 if (this._defaultFocusAsync) {
5287 this.cancelAsync(this._defaultFocusAsync);
5288 this._defaultFocusAsync = null;
5289 }
5290 }, 1);
5291 },
5292 _affectScroll: function(dx) {
5293 this.$.tabsContainer.scrollLeft += dx;
5294 var scrollLeft = this.$.tabsContainer.scrollLeft;
5295 this._leftHidden = scrollLeft === 0;
5296 this._rightHidden = scrollLeft === this._tabContainerScrollSize;
5297 },
5298 _onLeftScrollButtonDown: function() {
5299 this._scrollToLeft();
5300 this._holdJob = setInterval(this._scrollToLeft.bind(this), this._holdDelay);
5301 },
5302 _onRightScrollButtonDown: function() {
5303 this._scrollToRight();
5304 this._holdJob = setInterval(this._scrollToRight.bind(this), this._holdDelay) ;
5305 },
5306 _onScrollButtonUp: function() {
5307 clearInterval(this._holdJob);
5308 this._holdJob = null;
5309 },
5310 _scrollToLeft: function() {
5311 this._affectScroll(-this._step);
5312 },
5313 _scrollToRight: function() {
5314 this._affectScroll(this._step);
5315 },
5316 _tabChanged: function(tab, old) {
5317 if (!tab) {
5318 this.$.selectionBar.classList.remove('expand');
5319 this.$.selectionBar.classList.remove('contract');
5320 this._positionBar(0, 0);
5321 return;
5322 }
5323 var r = this.$.tabsContent.getBoundingClientRect();
5324 var w = r.width;
5325 var tabRect = tab.getBoundingClientRect();
5326 var tabOffsetLeft = tabRect.left - r.left;
5327 this._pos = {
5328 width: this._calcPercent(tabRect.width, w),
5329 left: this._calcPercent(tabOffsetLeft, w)
5330 };
5331 if (this.noSlide || old == null) {
5332 this.$.selectionBar.classList.remove('expand');
5333 this.$.selectionBar.classList.remove('contract');
5334 this._positionBar(this._pos.width, this._pos.left);
5335 return;
5336 }
5337 var oldRect = old.getBoundingClientRect();
5338 var oldIndex = this.items.indexOf(old);
5339 var index = this.items.indexOf(tab);
5340 var m = 5;
5341 this.$.selectionBar.classList.add('expand');
5342 var moveRight = oldIndex < index;
5343 var isRTL = this._isRTL;
5344 if (isRTL) {
5345 moveRight = !moveRight;
5346 }
5347 if (moveRight) {
5348 this._positionBar(this._calcPercent(tabRect.left + tabRect.width - oldRect .left, w) - m, this._left);
5349 } else {
5350 this._positionBar(this._calcPercent(oldRect.left + oldRect.width - tabRect .left, w) - m, this._calcPercent(tabOffsetLeft, w) + m);
5351 }
5352 if (this.scrollable) {
5353 this._scrollToSelectedIfNeeded(tabRect.width, tabOffsetLeft);
5354 }
5355 },
5356 _scrollToSelectedIfNeeded: function(tabWidth, tabOffsetLeft) {
5357 var l = tabOffsetLeft - this.$.tabsContainer.scrollLeft;
5358 if (l < 0) {
5359 this.$.tabsContainer.scrollLeft += l;
5360 } else {
5361 l += tabWidth - this.$.tabsContainer.offsetWidth;
5362 if (l > 0) {
5363 this.$.tabsContainer.scrollLeft += l;
5364 }
5365 }
5366 },
5367 _calcPercent: function(w, w0) {
5368 return 100 * w / w0;
5369 },
5370 _positionBar: function(width, left) {
5371 width = width || 0;
5372 left = left || 0;
5373 this._width = width;
5374 this._left = left;
5375 this.transform('translateX(' + left + '%) scaleX(' + width / 100 + ')', this .$.selectionBar);
5376 },
5377 _onBarTransitionEnd: function(e) {
5378 var cl = this.$.selectionBar.classList;
5379 if (cl.contains('expand')) {
5380 cl.remove('expand');
5381 cl.add('contract');
5382 this._positionBar(this._pos.width, this._pos.left);
5383 } else if (cl.contains('contract')) {
5384 cl.remove('contract');
5385 }
5386 }
5387 });
5388
5389 // Copyright 2016 The Chromium Authors. All rights reserved. 2852 // Copyright 2016 The Chromium Authors. All rights reserved.
5390 // Use of this source code is governed by a BSD-style license that can be 2853 // Use of this source code is governed by a BSD-style license that can be
5391 // found in the LICENSE file. 2854 // found in the LICENSE file.
5392 Polymer({ 2855 Polymer({
5393 is: 'cr-lazy-render', 2856 is: 'cr-lazy-render',
5394 "extends": 'template', 2857 "extends": 'template',
5395 behaviors: [ Polymer.Templatizer ], 2858 behaviors: [ Polymer.Templatizer ],
5396 child_: null, 2859 child_: null,
5397 get: function() { 2860 get: function() {
5398 if (!this.child_) this.render_(); 2861 if (!this.child_) this.render_();
(...skipping 869 matching lines...) Expand 10 before | Expand all | Expand 10 after
6268 return count > 0 ? loadTimeData.getStringF('itemsSelected', count) : ''; 3731 return count > 0 ? loadTimeData.getStringF('itemsSelected', count) : '';
6269 }, 3732 },
6270 getHistoryInterval_: function(queryStartTime, queryEndTime) { 3733 getHistoryInterval_: function(queryStartTime, queryEndTime) {
6271 return loadTimeData.getStringF('historyInterval', queryStartTime, queryEndTi me); 3734 return loadTimeData.getStringF('historyInterval', queryStartTime, queryEndTi me);
6272 }, 3735 },
6273 hasDrawerChanged_: function() { 3736 hasDrawerChanged_: function() {
6274 this.updateStyles(); 3737 this.updateStyles();
6275 } 3738 }
6276 }); 3739 });
6277 3740
6278 // Copyright 2016 The Chromium Authors. All rights reserved.
6279 // Use of this source code is governed by a BSD-style license that can be
6280 // found in the LICENSE file.
6281 Polymer({
6282 is: 'cr-dialog',
6283 "extends": 'dialog',
6284 created: function() {
6285 window.addEventListener('popstate', function() {
6286 if (this.open) this.cancel();
6287 }.bind(this));
6288 },
6289 cancel: function() {
6290 this.fire('cancel');
6291 HTMLDialogElement.prototype.close.call(this, '');
6292 },
6293 close: function(opt_returnValue) {
6294 HTMLDialogElement.prototype.close.call(this, 'success');
6295 },
6296 getCloseButton: function() {
6297 return this.$.close;
6298 }
6299 });
6300
6301 Polymer({
6302 is: 'fade-in-animation',
6303 behaviors: [ Polymer.NeonAnimationBehavior ],
6304 configure: function(config) {
6305 var node = config.node;
6306 this._effect = new KeyframeEffect(node, [ {
6307 opacity: '0'
6308 }, {
6309 opacity: '1'
6310 } ], this.timingFromConfig(config));
6311 return this._effect;
6312 }
6313 });
6314
6315 Polymer({
6316 is: 'fade-out-animation',
6317 behaviors: [ Polymer.NeonAnimationBehavior ],
6318 configure: function(config) {
6319 var node = config.node;
6320 this._effect = new KeyframeEffect(node, [ {
6321 opacity: '1'
6322 }, {
6323 opacity: '0'
6324 } ], this.timingFromConfig(config));
6325 return this._effect;
6326 }
6327 });
6328
6329 Polymer({
6330 is: 'paper-menu-grow-height-animation',
6331 behaviors: [ Polymer.NeonAnimationBehavior ],
6332 configure: function(config) {
6333 var node = config.node;
6334 var rect = node.getBoundingClientRect();
6335 var height = rect.height;
6336 this._effect = new KeyframeEffect(node, [ {
6337 height: height / 2 + 'px'
6338 }, {
6339 height: height + 'px'
6340 } ], this.timingFromConfig(config));
6341 return this._effect;
6342 }
6343 });
6344
6345 Polymer({
6346 is: 'paper-menu-grow-width-animation',
6347 behaviors: [ Polymer.NeonAnimationBehavior ],
6348 configure: function(config) {
6349 var node = config.node;
6350 var rect = node.getBoundingClientRect();
6351 var width = rect.width;
6352 this._effect = new KeyframeEffect(node, [ {
6353 width: width / 2 + 'px'
6354 }, {
6355 width: width + 'px'
6356 } ], this.timingFromConfig(config));
6357 return this._effect;
6358 }
6359 });
6360
6361 Polymer({
6362 is: 'paper-menu-shrink-width-animation',
6363 behaviors: [ Polymer.NeonAnimationBehavior ],
6364 configure: function(config) {
6365 var node = config.node;
6366 var rect = node.getBoundingClientRect();
6367 var width = rect.width;
6368 this._effect = new KeyframeEffect(node, [ {
6369 width: width + 'px'
6370 }, {
6371 width: width - width / 20 + 'px'
6372 } ], this.timingFromConfig(config));
6373 return this._effect;
6374 }
6375 });
6376
6377 Polymer({
6378 is: 'paper-menu-shrink-height-animation',
6379 behaviors: [ Polymer.NeonAnimationBehavior ],
6380 configure: function(config) {
6381 var node = config.node;
6382 var rect = node.getBoundingClientRect();
6383 var height = rect.height;
6384 var top = rect.top;
6385 this.setPrefixedProperty(node, 'transformOrigin', '0 0');
6386 this._effect = new KeyframeEffect(node, [ {
6387 height: height + 'px',
6388 transform: 'translateY(0)'
6389 }, {
6390 height: height / 2 + 'px',
6391 transform: 'translateY(-20px)'
6392 } ], this.timingFromConfig(config));
6393 return this._effect;
6394 }
6395 });
6396
6397 // Copyright 2016 The Chromium Authors. All rights reserved.
6398 // Use of this source code is governed by a BSD-style license that can be
6399 // found in the LICENSE file.
6400 var SLIDE_CUBIC_BEZIER = 'cubic-bezier(0.3, 0.95, 0.5, 1)';
6401
6402 Polymer({
6403 is: 'cr-shared-menu',
6404 behaviors: [ Polymer.IronA11yKeysBehavior ],
6405 properties: {
6406 menuOpen: {
6407 type: Boolean,
6408 observer: 'menuOpenChanged_',
6409 value: false,
6410 notify: true
6411 },
6412 itemData: {
6413 type: Object,
6414 value: null
6415 },
6416 keyEventTarget: {
6417 type: Object,
6418 value: function() {
6419 return this.$.menu;
6420 }
6421 },
6422 openAnimationConfig: {
6423 type: Object,
6424 value: function() {
6425 return [ {
6426 name: 'fade-in-animation',
6427 timing: {
6428 delay: 50,
6429 duration: 200
6430 }
6431 }, {
6432 name: 'paper-menu-grow-width-animation',
6433 timing: {
6434 delay: 50,
6435 duration: 150,
6436 easing: SLIDE_CUBIC_BEZIER
6437 }
6438 }, {
6439 name: 'paper-menu-grow-height-animation',
6440 timing: {
6441 delay: 100,
6442 duration: 275,
6443 easing: SLIDE_CUBIC_BEZIER
6444 }
6445 } ];
6446 }
6447 },
6448 closeAnimationConfig: {
6449 type: Object,
6450 value: function() {
6451 return [ {
6452 name: 'fade-out-animation',
6453 timing: {
6454 duration: 150
6455 }
6456 } ];
6457 }
6458 }
6459 },
6460 keyBindings: {
6461 tab: 'onTabPressed_'
6462 },
6463 listeners: {
6464 'dropdown.iron-overlay-canceled': 'onOverlayCanceled_'
6465 },
6466 lastAnchor_: null,
6467 firstFocus_: null,
6468 lastFocus_: null,
6469 attached: function() {
6470 window.addEventListener('resize', this.closeMenu.bind(this));
6471 },
6472 closeMenu: function() {
6473 if (this.root.activeElement == null) {
6474 this.$.dropdown.restoreFocusOnClose = false;
6475 }
6476 this.menuOpen = false;
6477 },
6478 openMenu: function(anchor, itemData) {
6479 if (this.lastAnchor_ == anchor && this.menuOpen) return;
6480 if (this.menuOpen) this.closeMenu();
6481 this.itemData = itemData;
6482 this.lastAnchor_ = anchor;
6483 this.$.dropdown.restoreFocusOnClose = true;
6484 var focusableChildren = Polymer.dom(this).querySelectorAll('[tabindex]:not([ disabled]):not([hidden]),' + 'button:not([disabled]):not([hidden])');
6485 if (focusableChildren.length > 0) {
6486 this.$.dropdown.focusTarget = focusableChildren[0];
6487 this.firstFocus_ = focusableChildren[0];
6488 this.lastFocus_ = focusableChildren[focusableChildren.length - 1];
6489 }
6490 this.$.dropdown.positionTarget = anchor;
6491 this.menuOpen = true;
6492 },
6493 toggleMenu: function(anchor, itemData) {
6494 if (anchor == this.lastAnchor_ && this.menuOpen) this.closeMenu(); else this .openMenu(anchor, itemData);
6495 },
6496 onTabPressed_: function(e) {
6497 if (!this.firstFocus_ || !this.lastFocus_) return;
6498 var toFocus;
6499 var keyEvent = e.detail.keyboardEvent;
6500 if (keyEvent.shiftKey && keyEvent.target == this.firstFocus_) toFocus = this .lastFocus_; else if (!keyEvent.shiftKey && keyEvent.target == this.lastFocus_) toFocus = this.firstFocus_;
6501 if (!toFocus) return;
6502 e.preventDefault();
6503 toFocus.focus();
6504 },
6505 menuOpenChanged_: function() {
6506 if (!this.menuOpen) {
6507 this.itemData = null;
6508 this.lastAnchor_ = null;
6509 }
6510 },
6511 onOverlayCanceled_: function(e) {
6512 if (e.detail.type == 'tap') this.$.dropdown.restoreFocusOnClose = false;
6513 }
6514 });
6515
6516 Polymer.PaperItemBehaviorImpl = {
6517 hostAttributes: {
6518 role: 'option',
6519 tabindex: '0'
6520 }
6521 };
6522
6523 Polymer.PaperItemBehavior = [ Polymer.IronButtonState, Polymer.IronControlState, Polymer.PaperItemBehaviorImpl ];
6524
6525 Polymer({
6526 is: 'paper-item',
6527 behaviors: [ Polymer.PaperItemBehavior ]
6528 });
6529
6530 Polymer({
6531 is: 'iron-collapse',
6532 behaviors: [ Polymer.IronResizableBehavior ],
6533 properties: {
6534 horizontal: {
6535 type: Boolean,
6536 value: false,
6537 observer: '_horizontalChanged'
6538 },
6539 opened: {
6540 type: Boolean,
6541 value: false,
6542 notify: true,
6543 observer: '_openedChanged'
6544 },
6545 noAnimation: {
6546 type: Boolean
6547 },
6548 _desiredSize: {
6549 type: String,
6550 value: ''
6551 }
6552 },
6553 get dimension() {
6554 return this.horizontal ? 'width' : 'height';
6555 },
6556 get _dimensionMax() {
6557 return this.horizontal ? 'maxWidth' : 'maxHeight';
6558 },
6559 get _dimensionMaxCss() {
6560 return this.horizontal ? 'max-width' : 'max-height';
6561 },
6562 hostAttributes: {
6563 role: 'group',
6564 'aria-hidden': 'true',
6565 'aria-expanded': 'false'
6566 },
6567 listeners: {
6568 transitionend: '_transitionEnd'
6569 },
6570 attached: function() {
6571 this._transitionEnd();
6572 },
6573 toggle: function() {
6574 this.opened = !this.opened;
6575 },
6576 show: function() {
6577 this.opened = true;
6578 },
6579 hide: function() {
6580 this.opened = false;
6581 },
6582 updateSize: function(size, animated) {
6583 size = size === 'auto' ? '' : size;
6584 if (this._desiredSize === size) {
6585 return;
6586 }
6587 this._desiredSize = size;
6588 this._updateTransition(false);
6589 var willAnimate = animated && !this.noAnimation && this._isDisplayed;
6590 if (willAnimate) {
6591 var startSize = this._calcSize();
6592 if (size === '') {
6593 this.style[this._dimensionMax] = '';
6594 size = this._calcSize();
6595 }
6596 this.style[this._dimensionMax] = startSize;
6597 this.scrollTop = this.scrollTop;
6598 this._updateTransition(true);
6599 willAnimate = size !== startSize;
6600 }
6601 this.style[this._dimensionMax] = size;
6602 if (!willAnimate) {
6603 this._transitionEnd();
6604 }
6605 },
6606 enableTransition: function(enabled) {
6607 Polymer.Base._warn('`enableTransition()` is deprecated, use `noAnimation` in stead.');
6608 this.noAnimation = !enabled;
6609 },
6610 _updateTransition: function(enabled) {
6611 this.style.transitionDuration = enabled && !this.noAnimation ? '' : '0s';
6612 },
6613 _horizontalChanged: function() {
6614 this.style.transitionProperty = this._dimensionMaxCss;
6615 var otherDimension = this._dimensionMax === 'maxWidth' ? 'maxHeight' : 'maxW idth';
6616 this.style[otherDimension] = '';
6617 this.updateSize(this.opened ? 'auto' : '0px', false);
6618 },
6619 _openedChanged: function() {
6620 this.setAttribute('aria-expanded', this.opened);
6621 this.setAttribute('aria-hidden', !this.opened);
6622 this.toggleClass('iron-collapse-closed', false);
6623 this.toggleClass('iron-collapse-opened', false);
6624 this.updateSize(this.opened ? 'auto' : '0px', true);
6625 if (this.opened) {
6626 this.focus();
6627 }
6628 },
6629 _transitionEnd: function() {
6630 this.style[this._dimensionMax] = this._desiredSize;
6631 this.toggleClass('iron-collapse-closed', !this.opened);
6632 this.toggleClass('iron-collapse-opened', this.opened);
6633 this._updateTransition(false);
6634 this.notifyResize();
6635 },
6636 get _isDisplayed() {
6637 var rect = this.getBoundingClientRect();
6638 for (var prop in rect) {
6639 if (rect[prop] !== 0) return true;
6640 }
6641 return false;
6642 },
6643 _calcSize: function() {
6644 return this.getBoundingClientRect()[this.dimension] + 'px';
6645 }
6646 });
6647
6648 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
6649 // Use of this source code is governed by a BSD-style license that can be
6650 // found in the LICENSE file.
6651 var EventTrackerEntry;
6652
6653 function EventTracker() {
6654 this.listeners_ = [];
6655 }
6656
6657 EventTracker.prototype = {
6658 add: function(target, eventType, listener, opt_capture) {
6659 var capture = !!opt_capture;
6660 var h = {
6661 target: target,
6662 eventType: eventType,
6663 listener: listener,
6664 capture: capture
6665 };
6666 this.listeners_.push(h);
6667 target.addEventListener(eventType, listener, capture);
6668 },
6669 remove: function(target, eventType) {
6670 this.listeners_ = this.listeners_.filter(function(h) {
6671 if (h.target == target && (!eventType || h.eventType == eventType)) {
6672 EventTracker.removeEventListener_(h);
6673 return false;
6674 }
6675 return true;
6676 });
6677 },
6678 removeAll: function() {
6679 this.listeners_.forEach(EventTracker.removeEventListener_);
6680 this.listeners_ = [];
6681 }
6682 };
6683
6684 EventTracker.removeEventListener_ = function(h) {
6685 h.target.removeEventListener(h.eventType, h.listener, h.capture);
6686 };
6687
6688 // Copyright 2014 The Chromium Authors. All rights reserved.
6689 // Use of this source code is governed by a BSD-style license that can be
6690 // found in the LICENSE file.
6691 cr.define('cr.ui', function() {
6692 function FocusRow(root, boundary, opt_delegate) {
6693 this.root = root;
6694 this.boundary_ = boundary || document.documentElement;
6695 this.delegate = opt_delegate;
6696 this.eventTracker = new EventTracker();
6697 }
6698 FocusRow.Delegate = function() {};
6699 FocusRow.Delegate.prototype = {
6700 onKeydown: assertNotReached,
6701 onFocus: assertNotReached
6702 };
6703 FocusRow.ACTIVE_CLASS = 'focus-row-active';
6704 FocusRow.isFocusable = function(element) {
6705 if (!element || element.disabled) return false;
6706 function isVisible(element) {
6707 assertInstanceof(element, Element);
6708 var style = window.getComputedStyle(element);
6709 if (style.visibility == 'hidden' || style.display == 'none') return false;
6710 var parent = element.parentNode;
6711 if (!parent) return false;
6712 if (parent == element.ownerDocument || parent instanceof DocumentFragment) return true;
6713 return isVisible(parent);
6714 }
6715 return isVisible(element);
6716 };
6717 FocusRow.prototype = {
6718 addItem: function(type, query) {
6719 assert(type);
6720 var element = this.root.querySelector(query);
6721 if (!element) return false;
6722 element.setAttribute('focus-type', type);
6723 element.tabIndex = this.isActive() ? 0 : -1;
6724 this.eventTracker.add(element, 'blur', this.onBlur_.bind(this));
6725 this.eventTracker.add(element, 'focus', this.onFocus_.bind(this));
6726 this.eventTracker.add(element, 'keydown', this.onKeydown_.bind(this));
6727 this.eventTracker.add(element, 'mousedown', this.onMousedown_.bind(this));
6728 return true;
6729 },
6730 destroy: function() {
6731 this.eventTracker.removeAll();
6732 },
6733 getCustomEquivalent: function(sampleElement) {
6734 return assert(this.getFirstFocusable());
6735 },
6736 getElements: function() {
6737 var elements = this.root.querySelectorAll('[focus-type]');
6738 return Array.prototype.slice.call(elements);
6739 },
6740 getEquivalentElement: function(sampleElement) {
6741 if (this.getFocusableElements().indexOf(sampleElement) >= 0) return sample Element;
6742 var sampleFocusType = this.getTypeForElement(sampleElement);
6743 if (sampleFocusType) {
6744 var sameType = this.getFirstFocusable(sampleFocusType);
6745 if (sameType) return sameType;
6746 }
6747 return this.getCustomEquivalent(sampleElement);
6748 },
6749 getFirstFocusable: function(opt_type) {
6750 var filter = opt_type ? '="' + opt_type + '"' : '';
6751 var elements = this.root.querySelectorAll('[focus-type' + filter + ']');
6752 for (var i = 0; i < elements.length; ++i) {
6753 if (cr.ui.FocusRow.isFocusable(elements[i])) return elements[i];
6754 }
6755 return null;
6756 },
6757 getFocusableElements: function() {
6758 return this.getElements().filter(cr.ui.FocusRow.isFocusable);
6759 },
6760 getTypeForElement: function(element) {
6761 return element.getAttribute('focus-type') || '';
6762 },
6763 isActive: function() {
6764 return this.root.classList.contains(FocusRow.ACTIVE_CLASS);
6765 },
6766 makeActive: function(active) {
6767 if (active == this.isActive()) return;
6768 this.getElements().forEach(function(element) {
6769 element.tabIndex = active ? 0 : -1;
6770 });
6771 this.root.classList.toggle(FocusRow.ACTIVE_CLASS, active);
6772 },
6773 onBlur_: function(e) {
6774 if (!this.boundary_.contains(e.relatedTarget)) return;
6775 var currentTarget = e.currentTarget;
6776 if (this.getFocusableElements().indexOf(currentTarget) >= 0) this.makeActi ve(false);
6777 },
6778 onFocus_: function(e) {
6779 if (this.delegate) this.delegate.onFocus(this, e);
6780 },
6781 onMousedown_: function(e) {
6782 if (e.button) return;
6783 if (!e.currentTarget.disabled) e.currentTarget.tabIndex = 0;
6784 },
6785 onKeydown_: function(e) {
6786 var elements = this.getFocusableElements();
6787 var currentElement = e.currentTarget;
6788 var elementIndex = elements.indexOf(currentElement);
6789 assert(elementIndex >= 0);
6790 if (this.delegate && this.delegate.onKeydown(this, e)) return;
6791 if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return;
6792 var index = -1;
6793 if (e.key == 'ArrowLeft') index = elementIndex + (isRTL() ? 1 : -1); else if (e.key == 'ArrowRight') index = elementIndex + (isRTL() ? -1 : 1); else if (e .key == 'Home') index = 0; else if (e.key == 'End') index = elements.length - 1;
6794 var elementToFocus = elements[index];
6795 if (elementToFocus) {
6796 this.getEquivalentElement(elementToFocus).focus();
6797 e.preventDefault();
6798 }
6799 }
6800 };
6801 return {
6802 FocusRow: FocusRow
6803 };
6804 });
6805
6806 // Copyright 2016 The Chromium Authors. All rights reserved.
6807 // Use of this source code is governed by a BSD-style license that can be
6808 // found in the LICENSE file.
6809 cr.define('cr.icon', function() {
6810 function getSupportedScaleFactors() {
6811 var supportedScaleFactors = [];
6812 if (!cr.isIOS) {
6813 supportedScaleFactors.push(1);
6814 }
6815 if (cr.isMac || cr.isChromeOS || cr.isWindows || cr.isLinux) {
6816 supportedScaleFactors.push(2);
6817 } else {
6818 supportedScaleFactors.push(window.devicePixelRatio);
6819 }
6820 return supportedScaleFactors;
6821 }
6822 function getImageSet(path) {
6823 var supportedScaleFactors = getSupportedScaleFactors();
6824 var replaceStartIndex = path.indexOf('scalefactor');
6825 if (replaceStartIndex < 0) return url(path);
6826 var s = '';
6827 for (var i = 0; i < supportedScaleFactors.length; ++i) {
6828 var scaleFactor = supportedScaleFactors[i];
6829 var pathWithScaleFactor = path.substr(0, replaceStartIndex) + scaleFactor + path.substr(replaceStartIndex + 'scalefactor'.length);
6830 s += url(pathWithScaleFactor) + ' ' + scaleFactor + 'x';
6831 if (i != supportedScaleFactors.length - 1) s += ', ';
6832 }
6833 return '-webkit-image-set(' + s + ')';
6834 }
6835 function getImage(path) {
6836 var chromeThemePath = 'chrome://theme';
6837 var isChromeThemeUrl = path.slice(0, chromeThemePath.length) == chromeThemeP ath;
6838 return isChromeThemeUrl ? getImageSet(path + '@scalefactorx') : url(path);
6839 }
6840 var FAVICON_URL_REGEX = /\.ico$/i;
6841 function getFavicon(url, opt_size, opt_type) {
6842 var size = opt_size || 16;
6843 var type = opt_type || 'favicon';
6844 return getImageSet('chrome://' + type + '/size/' + size + '@scalefactorx/' + (FAVICON_URL_REGEX.test(url) ? 'iconurl/' : '') + url);
6845 }
6846 return {
6847 getImage: getImage,
6848 getFavicon: getFavicon
6849 };
6850 });
6851
6852 // Copyright 2016 The Chromium Authors. All rights reserved.
6853 // Use of this source code is governed by a BSD-style license that can be
6854 // found in the LICENSE file.
6855 Polymer({
6856 is: 'history-searched-label',
6857 properties: {
6858 title: String,
6859 searchTerm: String
6860 },
6861 observers: [ 'setSearchedTextToBold_(title, searchTerm)' ],
6862 setSearchedTextToBold_: function() {
6863 var i = 0;
6864 var titleText = this.title;
6865 if (this.searchTerm == '' || this.searchTerm == null) {
6866 this.textContent = titleText;
6867 return;
6868 }
6869 var re = new RegExp(quoteString(this.searchTerm), 'gim');
6870 var match;
6871 this.textContent = '';
6872 while (match = re.exec(titleText)) {
6873 if (match.index > i) this.appendChild(document.createTextNode(titleText.sl ice(i, match.index)));
6874 i = re.lastIndex;
6875 var b = document.createElement('b');
6876 b.textContent = titleText.substring(match.index, i);
6877 this.appendChild(b);
6878 }
6879 if (i < titleText.length) this.appendChild(document.createTextNode(titleText .slice(i)));
6880 }
6881 });
6882
6883 // Copyright 2015 The Chromium Authors. All rights reserved.
6884 // Use of this source code is governed by a BSD-style license that can be
6885 // found in the LICENSE file.
6886 function HistoryFocusRow(root, boundary, delegate) {
6887 cr.ui.FocusRow.call(this, root, boundary, delegate);
6888 this.addItems();
6889 }
6890
6891 HistoryFocusRow.prototype = {
6892 __proto__: cr.ui.FocusRow.prototype,
6893 getCustomEquivalent: function(sampleElement) {
6894 var equivalent;
6895 if (this.getTypeForElement(sampleElement) == 'star') equivalent = this.getFi rstFocusable('title');
6896 return equivalent || cr.ui.FocusRow.prototype.getCustomEquivalent.call(this, sampleElement);
6897 },
6898 addItems: function() {
6899 this.destroy();
6900 assert(this.addItem('checkbox', '#checkbox'));
6901 assert(this.addItem('title', '#title'));
6902 assert(this.addItem('menu-button', '#menu-button'));
6903 this.addItem('star', '#bookmark-star');
6904 }
6905 };
6906
6907 cr.define('md_history', function() {
6908 function FocusRowDelegate(historyItemElement) {
6909 this.historyItemElement = historyItemElement;
6910 }
6911 FocusRowDelegate.prototype = {
6912 onFocus: function(row, e) {
6913 this.historyItemElement.lastFocused = e.path[0];
6914 },
6915 onKeydown: function(row, e) {
6916 if (e.key == 'Enter') e.stopPropagation();
6917 return false;
6918 }
6919 };
6920 var HistoryItem = Polymer({
6921 is: 'history-item',
6922 properties: {
6923 item: {
6924 type: Object,
6925 observer: 'showIcon_'
6926 },
6927 searchTerm: {
6928 type: String
6929 },
6930 selected: {
6931 type: Boolean,
6932 reflectToAttribute: true
6933 },
6934 isCardStart: {
6935 type: Boolean,
6936 reflectToAttribute: true
6937 },
6938 isCardEnd: {
6939 type: Boolean,
6940 reflectToAttribute: true
6941 },
6942 embedded: {
6943 type: Boolean,
6944 reflectToAttribute: true
6945 },
6946 hasTimeGap: {
6947 type: Boolean
6948 },
6949 numberOfItems: {
6950 type: Number
6951 },
6952 path: String,
6953 index: Number,
6954 lastFocused: {
6955 type: Object,
6956 notify: true
6957 },
6958 ironListTabIndex: {
6959 type: Number,
6960 observer: 'ironListTabIndexChanged_'
6961 }
6962 },
6963 row_: null,
6964 attached: function() {
6965 Polymer.RenderStatus.afterNextRender(this, function() {
6966 this.row_ = new HistoryFocusRow(this.$['sizing-container'], null, new Fo cusRowDelegate(this));
6967 this.row_.makeActive(this.ironListTabIndex == 0);
6968 this.listen(this, 'focus', 'onFocus_');
6969 this.listen(this, 'dom-change', 'onDomChange_');
6970 });
6971 },
6972 detached: function() {
6973 this.unlisten(this, 'focus', 'onFocus_');
6974 this.unlisten(this, 'dom-change', 'onDomChange_');
6975 if (this.row_) this.row_.destroy();
6976 },
6977 onFocus_: function() {
6978 if (this.lastFocused) this.row_.getEquivalentElement(this.lastFocused).foc us(); else this.row_.getFirstFocusable().focus();
6979 this.tabIndex = -1;
6980 },
6981 ironListTabIndexChanged_: function() {
6982 if (this.row_) this.row_.makeActive(this.ironListTabIndex == 0);
6983 },
6984 onDomChange_: function() {
6985 if (this.row_) this.row_.addItems();
6986 },
6987 onCheckboxSelected_: function(e) {
6988 this.fire('history-checkbox-select', {
6989 element: this,
6990 shiftKey: e.shiftKey
6991 });
6992 e.preventDefault();
6993 },
6994 onCheckboxMousedown_: function(e) {
6995 if (e.shiftKey) e.preventDefault();
6996 },
6997 getEntrySummary_: function() {
6998 var item = this.item;
6999 return loadTimeData.getStringF('entrySummary', item.dateTimeOfDay, item.st arred ? loadTimeData.getString('bookmarked') : '', item.title, item.domain);
7000 },
7001 getAriaChecked_: function(selected) {
7002 return selected ? 'true' : 'false';
7003 },
7004 onRemoveBookmarkTap_: function() {
7005 if (!this.item.starred) return;
7006 if (this.$$('#bookmark-star') == this.root.activeElement) this.$['menu-but ton'].focus();
7007 var browserService = md_history.BrowserService.getInstance();
7008 browserService.removeBookmark(this.item.url);
7009 browserService.recordAction('BookmarkStarClicked');
7010 this.fire('remove-bookmark-stars', this.item.url);
7011 },
7012 onMenuButtonTap_: function(e) {
7013 this.fire('toggle-menu', {
7014 target: Polymer.dom(e).localTarget,
7015 index: this.index,
7016 item: this.item,
7017 path: this.path
7018 });
7019 e.stopPropagation();
7020 },
7021 onLinkClick_: function() {
7022 var browserService = md_history.BrowserService.getInstance();
7023 browserService.recordAction('EntryLinkClick');
7024 if (this.searchTerm) browserService.recordAction('SearchResultClick');
7025 if (this.index == undefined) return;
7026 browserService.recordHistogram('HistoryPage.ClickPosition', this.index, UM A_MAX_BUCKET_VALUE);
7027 if (this.index <= UMA_MAX_SUBSET_BUCKET_VALUE) {
7028 browserService.recordHistogram('HistoryPage.ClickPositionSubset', this.i ndex, UMA_MAX_SUBSET_BUCKET_VALUE);
7029 }
7030 },
7031 onLinkRightClick_: function() {
7032 md_history.BrowserService.getInstance().recordAction('EntryLinkRightClick' );
7033 },
7034 showIcon_: function() {
7035 this.$.icon.style.backgroundImage = cr.icon.getFavicon(this.item.url);
7036 },
7037 selectionNotAllowed_: function() {
7038 return !loadTimeData.getBoolean('allowDeletingHistory');
7039 },
7040 cardTitle_: function(numberOfItems, historyDate, search) {
7041 if (!search) return this.item.dateRelativeDay;
7042 var resultId = numberOfItems == 1 ? 'searchResult' : 'searchResults';
7043 return loadTimeData.getStringF('foundSearchResults', numberOfItems, loadTi meData.getString(resultId), search);
7044 }
7045 });
7046 HistoryItem.needsTimeGap = function(visits, currentIndex, searchedTerm) {
7047 if (currentIndex >= visits.length - 1 || visits.length == 0) return false;
7048 var currentItem = visits[currentIndex];
7049 var nextItem = visits[currentIndex + 1];
7050 if (searchedTerm) return currentItem.dateShort != nextItem.dateShort;
7051 return currentItem.time - nextItem.time > BROWSING_GAP_TIME && currentItem.d ateRelativeDay == nextItem.dateRelativeDay;
7052 };
7053 return {
7054 HistoryItem: HistoryItem
7055 };
7056 });
7057
7058 // Copyright 2016 The Chromium Authors. All rights reserved.
7059 // Use of this source code is governed by a BSD-style license that can be
7060 // found in the LICENSE file.
7061 var SelectionTreeNode = function(currentPath) {
7062 this.currentPath = currentPath;
7063 this.leaf = false;
7064 this.indexes = [];
7065 this.children = [];
7066 };
7067
7068 SelectionTreeNode.prototype.addChild = function(index, path) {
7069 this.indexes.push(index);
7070 this.children[index] = new SelectionTreeNode(path);
7071 };
7072
7073 var HistoryListBehavior = {
7074 properties: {
7075 selectedPaths: {
7076 type: Object,
7077 value: function() {
7078 return new Set();
7079 }
7080 },
7081 lastSelectedPath: String
7082 },
7083 listeners: {
7084 'history-checkbox-select': 'itemSelected_'
7085 },
7086 hasResults: function(historyDataLength) {
7087 return historyDataLength > 0;
7088 },
7089 noResultsMessage: function(searchedTerm, isLoading) {
7090 if (isLoading) return '';
7091 var messageId = searchedTerm !== '' ? 'noSearchResults' : 'noResults';
7092 return loadTimeData.getString(messageId);
7093 },
7094 unselectAllItems: function() {
7095 this.selectedPaths.forEach(function(path) {
7096 this.set(path + '.selected', false);
7097 }.bind(this));
7098 this.selectedPaths.clear();
7099 },
7100 deleteSelected: function() {
7101 var toBeRemoved = Array.from(this.selectedPaths.values()).map(function(path) {
7102 return this.get(path);
7103 }.bind(this));
7104 md_history.BrowserService.getInstance().deleteItems(toBeRemoved).then(functi on() {
7105 this.removeItemsByPath(Array.from(this.selectedPaths));
7106 this.fire('unselect-all');
7107 }.bind(this));
7108 },
7109 removeItemsByPath: function(paths) {
7110 if (paths.length == 0) return;
7111 this.removeItemsBeneathNode_(this.buildRemovalTree_(paths));
7112 },
7113 buildRemovalTree_: function(paths) {
7114 var rootNode = new SelectionTreeNode(paths[0].split('.')[0]);
7115 paths.forEach(function(path) {
7116 var components = path.split('.');
7117 var node = rootNode;
7118 components.shift();
7119 while (components.length > 1) {
7120 var index = Number(components.shift());
7121 var arrayName = components.shift();
7122 if (!node.children[index]) node.addChild(index, [ node.currentPath, inde x, arrayName ].join('.'));
7123 node = node.children[index];
7124 }
7125 node.leaf = true;
7126 node.indexes.push(Number(components.shift()));
7127 });
7128 return rootNode;
7129 },
7130 removeItemsBeneathNode_: function(node) {
7131 var array = this.get(node.currentPath);
7132 var splices = [];
7133 node.indexes.sort(function(a, b) {
7134 return b - a;
7135 });
7136 node.indexes.forEach(function(index) {
7137 if (node.leaf || this.removeItemsBeneathNode_(node.children[index])) {
7138 var item = array.splice(index, 1)[0];
7139 splices.push({
7140 index: index,
7141 removed: [ item ],
7142 addedCount: 0,
7143 object: array,
7144 type: 'splice'
7145 });
7146 }
7147 }.bind(this));
7148 if (array.length == 0 && node.currentPath.indexOf('.') != -1) return true;
7149 this.notifySplices(node.currentPath, splices);
7150 return false;
7151 },
7152 itemSelected_: function(e) {
7153 var item = e.detail.element;
7154 var paths = [];
7155 var itemPath = item.path;
7156 if (e.detail.shiftKey && this.lastSelectedPath) {
7157 var itemPathComponents = itemPath.split('.');
7158 var itemIndex = Number(itemPathComponents.pop());
7159 var itemArrayPath = itemPathComponents.join('.');
7160 var lastItemPathComponents = this.lastSelectedPath.split('.');
7161 var lastItemIndex = Number(lastItemPathComponents.pop());
7162 if (itemArrayPath == lastItemPathComponents.join('.')) {
7163 for (var i = Math.min(itemIndex, lastItemIndex); i <= Math.max(itemIndex , lastItemIndex); i++) {
7164 paths.push(itemArrayPath + '.' + i);
7165 }
7166 }
7167 }
7168 if (paths.length == 0) paths.push(item.path);
7169 var selected = !this.selectedPaths.has(item.path);
7170 paths.forEach(function(path) {
7171 this.set(path + '.selected', selected);
7172 if (selected) {
7173 this.selectedPaths.add(path);
7174 return;
7175 }
7176 this.selectedPaths.delete(path);
7177 }.bind(this));
7178 this.lastSelectedPath = itemPath;
7179 }
7180 };
7181
7182 // Copyright 2016 The Chromium Authors. All rights reserved.
7183 // Use of this source code is governed by a BSD-style license that can be
7184 // found in the LICENSE file.
7185 var HistoryDomain;
7186
7187 var HistoryGroup;
7188
7189 Polymer({
7190 is: 'history-grouped-list',
7191 behaviors: [ HistoryListBehavior ],
7192 properties: {
7193 historyData: {
7194 type: Array
7195 },
7196 groupedHistoryData_: {
7197 type: Array
7198 },
7199 searchedTerm: {
7200 type: String,
7201 value: ''
7202 },
7203 range: {
7204 type: Number
7205 },
7206 queryStartTime: String,
7207 queryEndTime: String
7208 },
7209 observers: [ 'updateGroupedHistoryData_(range, historyData)' ],
7210 createHistoryDomains_: function(visits) {
7211 var domainIndexes = {};
7212 var domains = [];
7213 for (var i = 0, visit; visit = visits[i]; i++) {
7214 var domain = visit.domain;
7215 if (domainIndexes[domain] == undefined) {
7216 domainIndexes[domain] = domains.length;
7217 domains.push({
7218 domain: domain,
7219 visits: [],
7220 expanded: false,
7221 rendered: false
7222 });
7223 }
7224 domains[domainIndexes[domain]].visits.push(visit);
7225 }
7226 var sortByVisits = function(a, b) {
7227 return b.visits.length - a.visits.length;
7228 };
7229 domains.sort(sortByVisits);
7230 return domains;
7231 },
7232 updateGroupedHistoryData_: function() {
7233 if (this.historyData.length == 0) {
7234 this.groupedHistoryData_ = [];
7235 return;
7236 }
7237 if (this.range == HistoryRange.WEEK) {
7238 var days = [];
7239 var currentDayVisits = [ this.historyData[0] ];
7240 var pushCurrentDay = function() {
7241 days.push({
7242 title: this.searchedTerm ? currentDayVisits[0].dateShort : currentDayV isits[0].dateRelativeDay,
7243 domains: this.createHistoryDomains_(currentDayVisits)
7244 });
7245 }.bind(this);
7246 var visitsSameDay = function(a, b) {
7247 if (this.searchedTerm) return a.dateShort == b.dateShort;
7248 return a.dateRelativeDay == b.dateRelativeDay;
7249 }.bind(this);
7250 for (var i = 1; i < this.historyData.length; i++) {
7251 var visit = this.historyData[i];
7252 if (!visitsSameDay(visit, currentDayVisits[0])) {
7253 pushCurrentDay();
7254 currentDayVisits = [];
7255 }
7256 currentDayVisits.push(visit);
7257 }
7258 pushCurrentDay();
7259 this.groupedHistoryData_ = days;
7260 } else if (this.range == HistoryRange.MONTH) {
7261 this.groupedHistoryData_ = [ {
7262 title: this.queryStartTime + ' – ' + this.queryEndTime,
7263 domains: this.createHistoryDomains_(this.historyData)
7264 } ];
7265 }
7266 },
7267 toggleDomainExpanded_: function(e) {
7268 var collapse = e.currentTarget.parentNode.querySelector('iron-collapse');
7269 e.model.set('domain.rendered', true);
7270 setTimeout(function() {
7271 collapse.toggle();
7272 }, 0);
7273 },
7274 needsTimeGap_: function(groupIndex, domainIndex, itemIndex) {
7275 var visits = this.groupedHistoryData_[groupIndex].domains[domainIndex].visit s;
7276 return md_history.HistoryItem.needsTimeGap(visits, itemIndex, this.searchedT erm);
7277 },
7278 pathForItem_: function(groupIndex, domainIndex, itemIndex) {
7279 return [ 'groupedHistoryData_', groupIndex, 'domains', domainIndex, 'visits' , itemIndex ].join('.');
7280 },
7281 getWebsiteIconStyle_: function(domain) {
7282 return 'background-image: ' + cr.icon.getFavicon(domain.visits[0].url);
7283 },
7284 getDropdownIcon_: function(expanded) {
7285 return expanded ? 'cr:expand-less' : 'cr:expand-more';
7286 }
7287 });
7288
7289 (function() { 3741 (function() {
7290 var IOS = navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/); 3742 var IOS = navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/);
7291 var IOS_TOUCH_SCROLLING = IOS && IOS[1] >= 8; 3743 var IOS_TOUCH_SCROLLING = IOS && IOS[1] >= 8;
7292 var DEFAULT_PHYSICAL_COUNT = 3; 3744 var DEFAULT_PHYSICAL_COUNT = 3;
7293 var HIDDEN_Y = '-10000px'; 3745 var HIDDEN_Y = '-10000px';
7294 var DEFAULT_GRID_SIZE = 200; 3746 var DEFAULT_GRID_SIZE = 200;
7295 var SECRET_TABINDEX = -100; 3747 var SECRET_TABINDEX = -100;
7296 Polymer({ 3748 Polymer({
7297 is: 'iron-list', 3749 is: 'iron-list',
7298 properties: { 3750 properties: {
(...skipping 933 matching lines...) Expand 10 before | Expand all | Expand 10 after
8232 this._setLowerTriggered(true); 4684 this._setLowerTriggered(true);
8233 this.fire('lower-threshold'); 4685 this.fire('lower-threshold');
8234 } 4686 }
8235 }, 4687 },
8236 clearTriggers: function() { 4688 clearTriggers: function() {
8237 this._setUpperTriggered(false); 4689 this._setUpperTriggered(false);
8238 this._setLowerTriggered(false); 4690 this._setLowerTriggered(false);
8239 } 4691 }
8240 }); 4692 });
8241 4693
4694 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
4695 // Use of this source code is governed by a BSD-style license that can be
4696 // found in the LICENSE file.
4697 var EventTrackerEntry;
4698
4699 function EventTracker() {
4700 this.listeners_ = [];
4701 }
4702
4703 EventTracker.prototype = {
4704 add: function(target, eventType, listener, opt_capture) {
4705 var capture = !!opt_capture;
4706 var h = {
4707 target: target,
4708 eventType: eventType,
4709 listener: listener,
4710 capture: capture
4711 };
4712 this.listeners_.push(h);
4713 target.addEventListener(eventType, listener, capture);
4714 },
4715 remove: function(target, eventType) {
4716 this.listeners_ = this.listeners_.filter(function(h) {
4717 if (h.target == target && (!eventType || h.eventType == eventType)) {
4718 EventTracker.removeEventListener_(h);
4719 return false;
4720 }
4721 return true;
4722 });
4723 },
4724 removeAll: function() {
4725 this.listeners_.forEach(EventTracker.removeEventListener_);
4726 this.listeners_ = [];
4727 }
4728 };
4729
4730 EventTracker.removeEventListener_ = function(h) {
4731 h.target.removeEventListener(h.eventType, h.listener, h.capture);
4732 };
4733
4734 // Copyright 2014 The Chromium Authors. All rights reserved.
4735 // Use of this source code is governed by a BSD-style license that can be
4736 // found in the LICENSE file.
4737 cr.define('cr.ui', function() {
4738 function FocusRow(root, boundary, opt_delegate) {
4739 this.root = root;
4740 this.boundary_ = boundary || document.documentElement;
4741 this.delegate = opt_delegate;
4742 this.eventTracker = new EventTracker();
4743 }
4744 FocusRow.Delegate = function() {};
4745 FocusRow.Delegate.prototype = {
4746 onKeydown: assertNotReached,
4747 onFocus: assertNotReached
4748 };
4749 FocusRow.ACTIVE_CLASS = 'focus-row-active';
4750 FocusRow.isFocusable = function(element) {
4751 if (!element || element.disabled) return false;
4752 function isVisible(element) {
4753 assertInstanceof(element, Element);
4754 var style = window.getComputedStyle(element);
4755 if (style.visibility == 'hidden' || style.display == 'none') return false;
4756 var parent = element.parentNode;
4757 if (!parent) return false;
4758 if (parent == element.ownerDocument || parent instanceof DocumentFragment) return true;
4759 return isVisible(parent);
4760 }
4761 return isVisible(element);
4762 };
4763 FocusRow.prototype = {
4764 addItem: function(type, query) {
4765 assert(type);
4766 var element = this.root.querySelector(query);
4767 if (!element) return false;
4768 element.setAttribute('focus-type', type);
4769 element.tabIndex = this.isActive() ? 0 : -1;
4770 this.eventTracker.add(element, 'blur', this.onBlur_.bind(this));
4771 this.eventTracker.add(element, 'focus', this.onFocus_.bind(this));
4772 this.eventTracker.add(element, 'keydown', this.onKeydown_.bind(this));
4773 this.eventTracker.add(element, 'mousedown', this.onMousedown_.bind(this));
4774 return true;
4775 },
4776 destroy: function() {
4777 this.eventTracker.removeAll();
4778 },
4779 getCustomEquivalent: function(sampleElement) {
4780 return assert(this.getFirstFocusable());
4781 },
4782 getElements: function() {
4783 var elements = this.root.querySelectorAll('[focus-type]');
4784 return Array.prototype.slice.call(elements);
4785 },
4786 getEquivalentElement: function(sampleElement) {
4787 if (this.getFocusableElements().indexOf(sampleElement) >= 0) return sample Element;
4788 var sampleFocusType = this.getTypeForElement(sampleElement);
4789 if (sampleFocusType) {
4790 var sameType = this.getFirstFocusable(sampleFocusType);
4791 if (sameType) return sameType;
4792 }
4793 return this.getCustomEquivalent(sampleElement);
4794 },
4795 getFirstFocusable: function(opt_type) {
4796 var filter = opt_type ? '="' + opt_type + '"' : '';
4797 var elements = this.root.querySelectorAll('[focus-type' + filter + ']');
4798 for (var i = 0; i < elements.length; ++i) {
4799 if (cr.ui.FocusRow.isFocusable(elements[i])) return elements[i];
4800 }
4801 return null;
4802 },
4803 getFocusableElements: function() {
4804 return this.getElements().filter(cr.ui.FocusRow.isFocusable);
4805 },
4806 getTypeForElement: function(element) {
4807 return element.getAttribute('focus-type') || '';
4808 },
4809 isActive: function() {
4810 return this.root.classList.contains(FocusRow.ACTIVE_CLASS);
4811 },
4812 makeActive: function(active) {
4813 if (active == this.isActive()) return;
4814 this.getElements().forEach(function(element) {
4815 element.tabIndex = active ? 0 : -1;
4816 });
4817 this.root.classList.toggle(FocusRow.ACTIVE_CLASS, active);
4818 },
4819 onBlur_: function(e) {
4820 if (!this.boundary_.contains(e.relatedTarget)) return;
4821 var currentTarget = e.currentTarget;
4822 if (this.getFocusableElements().indexOf(currentTarget) >= 0) this.makeActi ve(false);
4823 },
4824 onFocus_: function(e) {
4825 if (this.delegate) this.delegate.onFocus(this, e);
4826 },
4827 onMousedown_: function(e) {
4828 if (e.button) return;
4829 if (!e.currentTarget.disabled) e.currentTarget.tabIndex = 0;
4830 },
4831 onKeydown_: function(e) {
4832 var elements = this.getFocusableElements();
4833 var currentElement = e.currentTarget;
4834 var elementIndex = elements.indexOf(currentElement);
4835 assert(elementIndex >= 0);
4836 if (this.delegate && this.delegate.onKeydown(this, e)) return;
4837 if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return;
4838 var index = -1;
4839 if (e.key == 'ArrowLeft') index = elementIndex + (isRTL() ? 1 : -1); else if (e.key == 'ArrowRight') index = elementIndex + (isRTL() ? -1 : 1); else if (e .key == 'Home') index = 0; else if (e.key == 'End') index = elements.length - 1;
4840 var elementToFocus = elements[index];
4841 if (elementToFocus) {
4842 this.getEquivalentElement(elementToFocus).focus();
4843 e.preventDefault();
4844 }
4845 }
4846 };
4847 return {
4848 FocusRow: FocusRow
4849 };
4850 });
4851
4852 // Copyright 2016 The Chromium Authors. All rights reserved.
4853 // Use of this source code is governed by a BSD-style license that can be
4854 // found in the LICENSE file.
4855 cr.define('cr.icon', function() {
4856 function getSupportedScaleFactors() {
4857 var supportedScaleFactors = [];
4858 if (!cr.isIOS) {
4859 supportedScaleFactors.push(1);
4860 }
4861 if (cr.isMac || cr.isChromeOS || cr.isWindows || cr.isLinux) {
4862 supportedScaleFactors.push(2);
4863 } else {
4864 supportedScaleFactors.push(window.devicePixelRatio);
4865 }
4866 return supportedScaleFactors;
4867 }
4868 function getImageSet(path) {
4869 var supportedScaleFactors = getSupportedScaleFactors();
4870 var replaceStartIndex = path.indexOf('scalefactor');
4871 if (replaceStartIndex < 0) return url(path);
4872 var s = '';
4873 for (var i = 0; i < supportedScaleFactors.length; ++i) {
4874 var scaleFactor = supportedScaleFactors[i];
4875 var pathWithScaleFactor = path.substr(0, replaceStartIndex) + scaleFactor + path.substr(replaceStartIndex + 'scalefactor'.length);
4876 s += url(pathWithScaleFactor) + ' ' + scaleFactor + 'x';
4877 if (i != supportedScaleFactors.length - 1) s += ', ';
4878 }
4879 return '-webkit-image-set(' + s + ')';
4880 }
4881 function getImage(path) {
4882 var chromeThemePath = 'chrome://theme';
4883 var isChromeThemeUrl = path.slice(0, chromeThemePath.length) == chromeThemeP ath;
4884 return isChromeThemeUrl ? getImageSet(path + '@scalefactorx') : url(path);
4885 }
4886 var FAVICON_URL_REGEX = /\.ico$/i;
4887 function getFavicon(url, opt_size, opt_type) {
4888 var size = opt_size || 16;
4889 var type = opt_type || 'favicon';
4890 return getImageSet('chrome://' + type + '/size/' + size + '@scalefactorx/' + (FAVICON_URL_REGEX.test(url) ? 'iconurl/' : '') + url);
4891 }
4892 return {
4893 getImage: getImage,
4894 getFavicon: getFavicon
4895 };
4896 });
4897
4898 // Copyright 2016 The Chromium Authors. All rights reserved.
4899 // Use of this source code is governed by a BSD-style license that can be
4900 // found in the LICENSE file.
4901 Polymer({
4902 is: 'history-searched-label',
4903 properties: {
4904 title: String,
4905 searchTerm: String
4906 },
4907 observers: [ 'setSearchedTextToBold_(title, searchTerm)' ],
4908 setSearchedTextToBold_: function() {
4909 var i = 0;
4910 var titleText = this.title;
4911 if (this.searchTerm == '' || this.searchTerm == null) {
4912 this.textContent = titleText;
4913 return;
4914 }
4915 var re = new RegExp(quoteString(this.searchTerm), 'gim');
4916 var match;
4917 this.textContent = '';
4918 while (match = re.exec(titleText)) {
4919 if (match.index > i) this.appendChild(document.createTextNode(titleText.sl ice(i, match.index)));
4920 i = re.lastIndex;
4921 var b = document.createElement('b');
4922 b.textContent = titleText.substring(match.index, i);
4923 this.appendChild(b);
4924 }
4925 if (i < titleText.length) this.appendChild(document.createTextNode(titleText .slice(i)));
4926 }
4927 });
4928
8242 // Copyright 2015 The Chromium Authors. All rights reserved. 4929 // Copyright 2015 The Chromium Authors. All rights reserved.
8243 // Use of this source code is governed by a BSD-style license that can be 4930 // Use of this source code is governed by a BSD-style license that can be
4931 // found in the LICENSE file.
4932 function HistoryFocusRow(root, boundary, delegate) {
4933 cr.ui.FocusRow.call(this, root, boundary, delegate);
4934 this.addItems();
4935 }
4936
4937 HistoryFocusRow.prototype = {
4938 __proto__: cr.ui.FocusRow.prototype,
4939 getCustomEquivalent: function(sampleElement) {
4940 var equivalent;
4941 if (this.getTypeForElement(sampleElement) == 'star') equivalent = this.getFi rstFocusable('title');
4942 return equivalent || cr.ui.FocusRow.prototype.getCustomEquivalent.call(this, sampleElement);
4943 },
4944 addItems: function() {
4945 this.destroy();
4946 assert(this.addItem('checkbox', '#checkbox'));
4947 assert(this.addItem('title', '#title'));
4948 assert(this.addItem('menu-button', '#menu-button'));
4949 this.addItem('star', '#bookmark-star');
4950 }
4951 };
4952
4953 cr.define('md_history', function() {
4954 function FocusRowDelegate(historyItemElement) {
4955 this.historyItemElement = historyItemElement;
4956 }
4957 FocusRowDelegate.prototype = {
4958 onFocus: function(row, e) {
4959 this.historyItemElement.lastFocused = e.path[0];
4960 },
4961 onKeydown: function(row, e) {
4962 if (e.key == 'Enter') e.stopPropagation();
4963 return false;
4964 }
4965 };
4966 var HistoryItem = Polymer({
4967 is: 'history-item',
4968 properties: {
4969 item: {
4970 type: Object,
4971 observer: 'showIcon_'
4972 },
4973 searchTerm: {
4974 type: String
4975 },
4976 selected: {
4977 type: Boolean,
4978 reflectToAttribute: true
4979 },
4980 isCardStart: {
4981 type: Boolean,
4982 reflectToAttribute: true
4983 },
4984 isCardEnd: {
4985 type: Boolean,
4986 reflectToAttribute: true
4987 },
4988 embedded: {
4989 type: Boolean,
4990 reflectToAttribute: true
4991 },
4992 hasTimeGap: {
4993 type: Boolean
4994 },
4995 numberOfItems: {
4996 type: Number
4997 },
4998 path: String,
4999 index: Number,
5000 lastFocused: {
5001 type: Object,
5002 notify: true
5003 },
5004 ironListTabIndex: {
5005 type: Number,
5006 observer: 'ironListTabIndexChanged_'
5007 }
5008 },
5009 row_: null,
5010 attached: function() {
5011 Polymer.RenderStatus.afterNextRender(this, function() {
5012 this.row_ = new HistoryFocusRow(this.$['sizing-container'], null, new Fo cusRowDelegate(this));
5013 this.row_.makeActive(this.ironListTabIndex == 0);
5014 this.listen(this, 'focus', 'onFocus_');
5015 this.listen(this, 'dom-change', 'onDomChange_');
5016 });
5017 },
5018 detached: function() {
5019 this.unlisten(this, 'focus', 'onFocus_');
5020 this.unlisten(this, 'dom-change', 'onDomChange_');
5021 if (this.row_) this.row_.destroy();
5022 },
5023 onFocus_: function() {
5024 if (this.lastFocused) this.row_.getEquivalentElement(this.lastFocused).foc us(); else this.row_.getFirstFocusable().focus();
5025 this.tabIndex = -1;
5026 },
5027 ironListTabIndexChanged_: function() {
5028 if (this.row_) this.row_.makeActive(this.ironListTabIndex == 0);
5029 },
5030 onDomChange_: function() {
5031 if (this.row_) this.row_.addItems();
5032 },
5033 onCheckboxSelected_: function(e) {
5034 this.fire('history-checkbox-select', {
5035 element: this,
5036 shiftKey: e.shiftKey
5037 });
5038 e.preventDefault();
5039 },
5040 onCheckboxMousedown_: function(e) {
5041 if (e.shiftKey) e.preventDefault();
5042 },
5043 getEntrySummary_: function() {
5044 var item = this.item;
5045 return loadTimeData.getStringF('entrySummary', item.dateTimeOfDay, item.st arred ? loadTimeData.getString('bookmarked') : '', item.title, item.domain);
5046 },
5047 getAriaChecked_: function(selected) {
5048 return selected ? 'true' : 'false';
5049 },
5050 onRemoveBookmarkTap_: function() {
5051 if (!this.item.starred) return;
5052 if (this.$$('#bookmark-star') == this.root.activeElement) this.$['menu-but ton'].focus();
5053 var browserService = md_history.BrowserService.getInstance();
5054 browserService.removeBookmark(this.item.url);
5055 browserService.recordAction('BookmarkStarClicked');
5056 this.fire('remove-bookmark-stars', this.item.url);
5057 },
5058 onMenuButtonTap_: function(e) {
5059 this.fire('toggle-menu', {
5060 target: Polymer.dom(e).localTarget,
5061 index: this.index,
5062 item: this.item,
5063 path: this.path
5064 });
5065 e.stopPropagation();
5066 },
5067 onLinkClick_: function() {
5068 var browserService = md_history.BrowserService.getInstance();
5069 browserService.recordAction('EntryLinkClick');
5070 if (this.searchTerm) browserService.recordAction('SearchResultClick');
5071 if (this.index == undefined) return;
5072 browserService.recordHistogram('HistoryPage.ClickPosition', this.index, UM A_MAX_BUCKET_VALUE);
5073 if (this.index <= UMA_MAX_SUBSET_BUCKET_VALUE) {
5074 browserService.recordHistogram('HistoryPage.ClickPositionSubset', this.i ndex, UMA_MAX_SUBSET_BUCKET_VALUE);
5075 }
5076 },
5077 onLinkRightClick_: function() {
5078 md_history.BrowserService.getInstance().recordAction('EntryLinkRightClick' );
5079 },
5080 showIcon_: function() {
5081 this.$.icon.style.backgroundImage = cr.icon.getFavicon(this.item.url);
5082 },
5083 selectionNotAllowed_: function() {
5084 return !loadTimeData.getBoolean('allowDeletingHistory');
5085 },
5086 cardTitle_: function(numberOfItems, historyDate, search) {
5087 if (!search) return this.item.dateRelativeDay;
5088 var resultId = numberOfItems == 1 ? 'searchResult' : 'searchResults';
5089 return loadTimeData.getStringF('foundSearchResults', numberOfItems, loadTi meData.getString(resultId), search);
5090 }
5091 });
5092 HistoryItem.needsTimeGap = function(visits, currentIndex, searchedTerm) {
5093 if (currentIndex >= visits.length - 1 || visits.length == 0) return false;
5094 var currentItem = visits[currentIndex];
5095 var nextItem = visits[currentIndex + 1];
5096 if (searchedTerm) return currentItem.dateShort != nextItem.dateShort;
5097 return currentItem.time - nextItem.time > BROWSING_GAP_TIME && currentItem.d ateRelativeDay == nextItem.dateRelativeDay;
5098 };
5099 return {
5100 HistoryItem: HistoryItem
5101 };
5102 });
5103
5104 // Copyright 2016 The Chromium Authors. All rights reserved.
5105 // Use of this source code is governed by a BSD-style license that can be
5106 // found in the LICENSE file.
5107 var SelectionTreeNode = function(currentPath) {
5108 this.currentPath = currentPath;
5109 this.leaf = false;
5110 this.indexes = [];
5111 this.children = [];
5112 };
5113
5114 SelectionTreeNode.prototype.addChild = function(index, path) {
5115 this.indexes.push(index);
5116 this.children[index] = new SelectionTreeNode(path);
5117 };
5118
5119 var HistoryListBehavior = {
5120 properties: {
5121 selectedPaths: {
5122 type: Object,
5123 value: function() {
5124 return new Set();
5125 }
5126 },
5127 lastSelectedPath: String
5128 },
5129 listeners: {
5130 'history-checkbox-select': 'itemSelected_'
5131 },
5132 hasResults: function(historyDataLength) {
5133 return historyDataLength > 0;
5134 },
5135 noResultsMessage: function(searchedTerm, isLoading) {
5136 if (isLoading) return '';
5137 var messageId = searchedTerm !== '' ? 'noSearchResults' : 'noResults';
5138 return loadTimeData.getString(messageId);
5139 },
5140 unselectAllItems: function() {
5141 this.selectedPaths.forEach(function(path) {
5142 this.set(path + '.selected', false);
5143 }.bind(this));
5144 this.selectedPaths.clear();
5145 },
5146 deleteSelected: function() {
5147 var toBeRemoved = Array.from(this.selectedPaths.values()).map(function(path) {
5148 return this.get(path);
5149 }.bind(this));
5150 md_history.BrowserService.getInstance().deleteItems(toBeRemoved).then(functi on() {
5151 this.removeItemsByPath(Array.from(this.selectedPaths));
5152 this.fire('unselect-all');
5153 }.bind(this));
5154 },
5155 removeItemsByPath: function(paths) {
5156 if (paths.length == 0) return;
5157 this.removeItemsBeneathNode_(this.buildRemovalTree_(paths));
5158 },
5159 buildRemovalTree_: function(paths) {
5160 var rootNode = new SelectionTreeNode(paths[0].split('.')[0]);
5161 paths.forEach(function(path) {
5162 var components = path.split('.');
5163 var node = rootNode;
5164 components.shift();
5165 while (components.length > 1) {
5166 var index = Number(components.shift());
5167 var arrayName = components.shift();
5168 if (!node.children[index]) node.addChild(index, [ node.currentPath, inde x, arrayName ].join('.'));
5169 node = node.children[index];
5170 }
5171 node.leaf = true;
5172 node.indexes.push(Number(components.shift()));
5173 });
5174 return rootNode;
5175 },
5176 removeItemsBeneathNode_: function(node) {
5177 var array = this.get(node.currentPath);
5178 var splices = [];
5179 node.indexes.sort(function(a, b) {
5180 return b - a;
5181 });
5182 node.indexes.forEach(function(index) {
5183 if (node.leaf || this.removeItemsBeneathNode_(node.children[index])) {
5184 var item = array.splice(index, 1)[0];
5185 splices.push({
5186 index: index,
5187 removed: [ item ],
5188 addedCount: 0,
5189 object: array,
5190 type: 'splice'
5191 });
5192 }
5193 }.bind(this));
5194 if (array.length == 0 && node.currentPath.indexOf('.') != -1) return true;
5195 this.notifySplices(node.currentPath, splices);
5196 return false;
5197 },
5198 itemSelected_: function(e) {
5199 var item = e.detail.element;
5200 var paths = [];
5201 var itemPath = item.path;
5202 if (e.detail.shiftKey && this.lastSelectedPath) {
5203 var itemPathComponents = itemPath.split('.');
5204 var itemIndex = Number(itemPathComponents.pop());
5205 var itemArrayPath = itemPathComponents.join('.');
5206 var lastItemPathComponents = this.lastSelectedPath.split('.');
5207 var lastItemIndex = Number(lastItemPathComponents.pop());
5208 if (itemArrayPath == lastItemPathComponents.join('.')) {
5209 for (var i = Math.min(itemIndex, lastItemIndex); i <= Math.max(itemIndex , lastItemIndex); i++) {
5210 paths.push(itemArrayPath + '.' + i);
5211 }
5212 }
5213 }
5214 if (paths.length == 0) paths.push(item.path);
5215 var selected = !this.selectedPaths.has(item.path);
5216 paths.forEach(function(path) {
5217 this.set(path + '.selected', selected);
5218 if (selected) {
5219 this.selectedPaths.add(path);
5220 return;
5221 }
5222 this.selectedPaths.delete(path);
5223 }.bind(this));
5224 this.lastSelectedPath = itemPath;
5225 }
5226 };
5227
5228 // Copyright 2015 The Chromium Authors. All rights reserved.
5229 // Use of this source code is governed by a BSD-style license that can be
8244 // found in the LICENSE file. 5230 // found in the LICENSE file.
8245 Polymer({ 5231 Polymer({
8246 is: 'history-list', 5232 is: 'history-list',
8247 behaviors: [ HistoryListBehavior ], 5233 behaviors: [ HistoryListBehavior ],
8248 properties: { 5234 properties: {
8249 searchedTerm: { 5235 searchedTerm: {
8250 type: String, 5236 type: String,
8251 value: '' 5237 value: ''
8252 }, 5238 },
8253 querying: Boolean, 5239 querying: Boolean,
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after
8449 browserService.recordHistogram('HistoryPage.RemoveEntryPositionSubset', index, UMA_MAX_SUBSET_BUCKET_VALUE); 5435 browserService.recordHistogram('HistoryPage.RemoveEntryPositionSubset', index, UMA_MAX_SUBSET_BUCKET_VALUE);
8450 } 5436 }
8451 }.bind(this)); 5437 }.bind(this));
8452 menu.closeMenu(); 5438 menu.closeMenu();
8453 }, 5439 },
8454 getSelectedList_: function() { 5440 getSelectedList_: function() {
8455 return this.$.content.selectedItem; 5441 return this.$.content.selectedItem;
8456 } 5442 }
8457 }); 5443 });
8458 5444
8459 // Copyright 2016 The Chromium Authors. All rights reserved. 5445 Polymer.IronMultiSelectableBehaviorImpl = {
8460 // Use of this source code is governed by a BSD-style license that can be
8461 // found in the LICENSE file.
8462 Polymer({
8463 is: 'history-synced-device-card',
8464 properties: { 5446 properties: {
8465 device: String, 5447 multi: {
8466 lastUpdateTime: String, 5448 type: Boolean,
8467 tabs: { 5449 value: false,
5450 observer: 'multiChanged'
5451 },
5452 selectedValues: {
8468 type: Array, 5453 type: Array,
8469 value: function() { 5454 notify: true
8470 return [];
8471 },
8472 observer: 'updateIcons_'
8473 }, 5455 },
8474 separatorIndexes: Array, 5456 selectedItems: {
8475 opened: Boolean, 5457 type: Array,
8476 searchTerm: String, 5458 readOnly: true,
8477 sessionTag: String 5459 notify: true
5460 }
8478 }, 5461 },
8479 openTab_: function(e) { 5462 observers: [ '_updateSelected(selectedValues.splices)' ],
8480 var tab = e.model.tab; 5463 select: function(value) {
8481 var browserService = md_history.BrowserService.getInstance(); 5464 if (this.multi) {
8482 browserService.recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogr am.LINK_CLICKED, SyncedTabsHistogram.LIMIT); 5465 if (this.selectedValues) {
8483 browserService.openForeignSessionTab(this.sessionTag, tab.windowId, tab.sess ionId, e); 5466 this._toggleSelected(value);
8484 e.preventDefault(); 5467 } else {
5468 this.selectedValues = [ value ];
5469 }
5470 } else {
5471 this.selected = value;
5472 }
8485 }, 5473 },
8486 toggleTabCard: function() { 5474 multiChanged: function(multi) {
8487 var histogramValue = this.$.collapse.opened ? SyncedTabsHistogram.COLLAPSE_S ESSION : SyncedTabsHistogram.EXPAND_SESSION; 5475 this._selection.multi = multi;
8488 md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRA M_NAME, histogramValue, SyncedTabsHistogram.LIMIT);
8489 this.$.collapse.toggle();
8490 this.$['dropdown-indicator'].icon = this.$.collapse.opened ? 'cr:expand-less ' : 'cr:expand-more';
8491 }, 5476 },
8492 updateIcons_: function() { 5477 get _shouldUpdateSelection() {
8493 this.async(function() { 5478 return this.selected != null || this.selectedValues != null && this.selected Values.length;
8494 var icons = Polymer.dom(this.root).querySelectorAll('.website-icon'); 5479 },
8495 for (var i = 0; i < this.tabs.length; i++) { 5480 _updateAttrForSelected: function() {
8496 icons[i].style.backgroundImage = cr.icon.getFavicon(this.tabs[i].url); 5481 if (!this.multi) {
5482 Polymer.IronSelectableBehavior._updateAttrForSelected.apply(this);
5483 } else if (this._shouldUpdateSelection) {
5484 this.selectedValues = this.selectedItems.map(function(selectedItem) {
5485 return this._indexToValue(this.indexOf(selectedItem));
5486 }, this).filter(function(unfilteredValue) {
5487 return unfilteredValue != null;
5488 }, this);
5489 }
5490 },
5491 _updateSelected: function() {
5492 if (this.multi) {
5493 this._selectMulti(this.selectedValues);
5494 } else {
5495 this._selectSelected(this.selected);
5496 }
5497 },
5498 _selectMulti: function(values) {
5499 if (values) {
5500 var selectedItems = this._valuesToItems(values);
5501 this._selection.clear(selectedItems);
5502 for (var i = 0; i < selectedItems.length; i++) {
5503 this._selection.setItemSelected(selectedItems[i], true);
8497 } 5504 }
8498 }); 5505 if (this.fallbackSelection && this.items.length && !this._selection.get(). length) {
8499 }, 5506 var fallback = this._valueToItem(this.fallbackSelection);
8500 isWindowSeparatorIndex_: function(index, separatorIndexes) { 5507 if (fallback) {
8501 return this.separatorIndexes.indexOf(index) != -1; 5508 this.selectedValues = [ this.fallbackSelection ];
8502 },
8503 getCollapseIcon_: function(opened) {
8504 return opened ? 'cr:expand-less' : 'cr:expand-more';
8505 },
8506 getCollapseTitle_: function(opened) {
8507 return opened ? loadTimeData.getString('collapseSessionButton') : loadTimeDa ta.getString('expandSessionButton');
8508 },
8509 onMenuButtonTap_: function(e) {
8510 this.fire('toggle-menu', {
8511 target: Polymer.dom(e).localTarget,
8512 tag: this.sessionTag
8513 });
8514 e.stopPropagation();
8515 },
8516 onLinkRightClick_: function() {
8517 md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRA M_NAME, SyncedTabsHistogram.LINK_RIGHT_CLICKED, SyncedTabsHistogram.LIMIT);
8518 }
8519 });
8520
8521 // Copyright 2016 The Chromium Authors. All rights reserved.
8522 // Use of this source code is governed by a BSD-style license that can be
8523 // found in the LICENSE file.
8524 var ForeignDeviceInternal;
8525
8526 Polymer({
8527 is: 'history-synced-device-manager',
8528 properties: {
8529 sessionList: {
8530 type: Array,
8531 observer: 'updateSyncedDevices'
8532 },
8533 searchTerm: {
8534 type: String,
8535 observer: 'searchTermChanged'
8536 },
8537 syncedDevices_: {
8538 type: Array,
8539 value: function() {
8540 return [];
8541 }
8542 },
8543 signInState: {
8544 type: Boolean,
8545 observer: 'signInStateChanged_'
8546 },
8547 guestSession_: {
8548 type: Boolean,
8549 value: loadTimeData.getBoolean('isGuestSession')
8550 },
8551 fetchingSyncedTabs_: {
8552 type: Boolean,
8553 value: false
8554 },
8555 hasSeenForeignData_: Boolean
8556 },
8557 listeners: {
8558 'toggle-menu': 'onToggleMenu_',
8559 scroll: 'onListScroll_'
8560 },
8561 attached: function() {
8562 chrome.send('otherDevicesInitialized');
8563 md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRA M_NAME, SyncedTabsHistogram.INITIALIZED, SyncedTabsHistogram.LIMIT);
8564 },
8565 getContentScrollTarget: function() {
8566 return this;
8567 },
8568 createInternalDevice_: function(session) {
8569 var tabs = [];
8570 var separatorIndexes = [];
8571 for (var i = 0; i < session.windows.length; i++) {
8572 var windowId = session.windows[i].sessionId;
8573 var newTabs = session.windows[i].tabs;
8574 if (newTabs.length == 0) continue;
8575 newTabs.forEach(function(tab) {
8576 tab.windowId = windowId;
8577 });
8578 var windowAdded = false;
8579 if (!this.searchTerm) {
8580 tabs = tabs.concat(newTabs);
8581 windowAdded = true;
8582 } else {
8583 var searchText = this.searchTerm.toLowerCase();
8584 for (var j = 0; j < newTabs.length; j++) {
8585 var tab = newTabs[j];
8586 if (tab.title.toLowerCase().indexOf(searchText) != -1) {
8587 tabs.push(tab);
8588 windowAdded = true;
8589 }
8590 } 5509 }
8591 } 5510 }
8592 if (windowAdded && i != session.windows.length - 1) separatorIndexes.push( tabs.length - 1); 5511 } else {
8593 } 5512 this._selection.clear();
8594 return {
8595 device: session.name,
8596 lastUpdateTime: '– ' + session.modifiedTime,
8597 opened: true,
8598 separatorIndexes: separatorIndexes,
8599 timestamp: session.timestamp,
8600 tabs: tabs,
8601 tag: session.tag
8602 };
8603 },
8604 onSignInTap_: function() {
8605 chrome.send('startSignInFlow');
8606 },
8607 onListScroll_: function() {
8608 var menu = this.$.menu.getIfExists();
8609 if (menu) menu.closeMenu();
8610 },
8611 onToggleMenu_: function(e) {
8612 var menu = this.$.menu.get();
8613 menu.toggleMenu(e.detail.target, e.detail.tag);
8614 if (menu.menuOpen) {
8615 md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOG RAM_NAME, SyncedTabsHistogram.SHOW_SESSION_MENU, SyncedTabsHistogram.LIMIT);
8616 } 5513 }
8617 }, 5514 },
8618 onOpenAllTap_: function() { 5515 _selectionChange: function() {
8619 var menu = assert(this.$.menu.getIfExists()); 5516 var s = this._selection.get();
8620 var browserService = md_history.BrowserService.getInstance(); 5517 if (this.multi) {
8621 browserService.recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogr am.OPEN_ALL, SyncedTabsHistogram.LIMIT); 5518 this._setSelectedItems(s);
8622 browserService.openForeignSessionAllTabs(menu.itemData);
8623 menu.closeMenu();
8624 },
8625 onDeleteSessionTap_: function() {
8626 var menu = assert(this.$.menu.getIfExists());
8627 var browserService = md_history.BrowserService.getInstance();
8628 browserService.recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogr am.HIDE_FOR_NOW, SyncedTabsHistogram.LIMIT);
8629 browserService.deleteForeignSession(menu.itemData);
8630 menu.closeMenu();
8631 },
8632 clearDisplayedSyncedDevices_: function() {
8633 this.syncedDevices_ = [];
8634 },
8635 showNoSyncedMessage: function(signInState, syncedDevicesLength, guestSession) {
8636 if (guestSession) return true;
8637 return signInState && syncedDevicesLength == 0;
8638 },
8639 showSignInGuide: function(signInState, guestSession) {
8640 var show = !signInState && !guestSession;
8641 if (show) {
8642 md_history.BrowserService.getInstance().recordAction('Signin_Impression_Fr omRecentTabs');
8643 }
8644 return show;
8645 },
8646 noSyncedTabsMessage: function(fetchingSyncedTabs) {
8647 return loadTimeData.getString(fetchingSyncedTabs ? 'loading' : 'noSyncedResu lts');
8648 },
8649 updateSyncedDevices: function(sessionList) {
8650 this.fetchingSyncedTabs_ = false;
8651 if (!sessionList) return;
8652 if (sessionList.length > 0 && !this.hasSeenForeignData_) {
8653 this.hasSeenForeignData_ = true;
8654 md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOG RAM_NAME, SyncedTabsHistogram.HAS_FOREIGN_DATA, SyncedTabsHistogram.LIMIT);
8655 }
8656 var updateCount = Math.min(sessionList.length, this.syncedDevices_.length);
8657 for (var i = 0; i < updateCount; i++) {
8658 var oldDevice = this.syncedDevices_[i];
8659 if (oldDevice.tag != sessionList[i].tag || oldDevice.timestamp != sessionL ist[i].timestamp) {
8660 this.splice('syncedDevices_', i, 1, this.createInternalDevice_(sessionLi st[i]));
8661 }
8662 }
8663 if (sessionList.length >= this.syncedDevices_.length) {
8664 for (var i = updateCount; i < sessionList.length; i++) {
8665 this.push('syncedDevices_', this.createInternalDevice_(sessionList[i]));
8666 }
8667 } else { 5519 } else {
8668 this.splice('syncedDevices_', updateCount, this.syncedDevices_.length - up dateCount); 5520 this._setSelectedItems([ s ]);
5521 this._setSelectedItem(s);
8669 } 5522 }
8670 }, 5523 },
8671 tabSyncDisabled: function() { 5524 _toggleSelected: function(value) {
8672 this.fetchingSyncedTabs_ = false; 5525 var i = this.selectedValues.indexOf(value);
8673 this.clearDisplayedSyncedDevices_(); 5526 var unselected = i < 0;
5527 if (unselected) {
5528 this.push('selectedValues', value);
5529 } else {
5530 this.splice('selectedValues', i, 1);
5531 }
8674 }, 5532 },
8675 signInStateChanged_: function() { 5533 _valuesToItems: function(values) {
8676 this.fire('history-view-changed'); 5534 return values == null ? null : values.map(function(value) {
8677 if (!this.signInState) { 5535 return this._valueToItem(value);
8678 this.clearDisplayedSyncedDevices_(); 5536 }, this);
8679 return;
8680 }
8681 this.fetchingSyncedTabs_ = true;
8682 },
8683 searchTermChanged: function(searchTerm) {
8684 this.clearDisplayedSyncedDevices_();
8685 this.updateSyncedDevices(this.sessionList);
8686 } 5537 }
8687 }); 5538 };
5539
5540 Polymer.IronMultiSelectableBehavior = [ Polymer.IronSelectableBehavior, Polymer. IronMultiSelectableBehaviorImpl ];
8688 5541
8689 Polymer({ 5542 Polymer({
8690 is: 'iron-selector', 5543 is: 'iron-selector',
8691 behaviors: [ Polymer.IronMultiSelectableBehavior ] 5544 behaviors: [ Polymer.IronMultiSelectableBehavior ]
8692 }); 5545 });
8693 5546
8694 // Copyright 2016 The Chromium Authors. All rights reserved. 5547 // Copyright 2016 The Chromium Authors. All rights reserved.
8695 // Use of this source code is governed by a BSD-style license that can be 5548 // Use of this source code is governed by a BSD-style license that can be
8696 // found in the LICENSE file. 5549 // found in the LICENSE file.
8697 Polymer({ 5550 Polymer({
(...skipping 28 matching lines...) Expand all
8726 e.preventDefault(); 5579 e.preventDefault();
8727 }, 5580 },
8728 getQueryString_: function(route) { 5581 getQueryString_: function(route) {
8729 return window.location.search; 5582 return window.location.search;
8730 } 5583 }
8731 }); 5584 });
8732 5585
8733 // Copyright 2016 The Chromium Authors. All rights reserved. 5586 // Copyright 2016 The Chromium Authors. All rights reserved.
8734 // Use of this source code is governed by a BSD-style license that can be 5587 // Use of this source code is governed by a BSD-style license that can be
8735 // found in the LICENSE file. 5588 // found in the LICENSE file.
5589 cr.define('md_history', function() {
5590 var lazyLoadPromise = null;
5591 function ensureLazyLoaded() {
5592 if (!lazyLoadPromise) {
5593 lazyLoadPromise = new Promise(function(resolve, reject) {
5594 Polymer.Base.importHref('chrome://history/lazy_load.html', resolve, reje ct, true);
5595 });
5596 }
5597 return lazyLoadPromise;
5598 }
5599 return {
5600 ensureLazyLoaded: ensureLazyLoaded
5601 };
5602 });
5603
8736 Polymer({ 5604 Polymer({
8737 is: 'history-app', 5605 is: 'history-app',
8738 behaviors: [ Polymer.IronScrollTargetBehavior ], 5606 behaviors: [ Polymer.IronScrollTargetBehavior ],
8739 properties: { 5607 properties: {
8740 showSidebarFooter: Boolean, 5608 showSidebarFooter: Boolean,
8741 hasSyncedResults: Boolean, 5609 hasSyncedResults: Boolean,
8742 selectedPage_: { 5610 selectedPage_: {
8743 type: String, 5611 type: String,
8744 observer: 'unselectAll' 5612 observer: 'unselectAll'
8745 }, 5613 },
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
8808 window.location.href = window.location.href.split('#')[0] + '?' + window.l ocation.hash.substr(1); 5676 window.location.href = window.location.href.split('#')[0] + '?' + window.l ocation.hash.substr(1);
8809 } 5677 }
8810 }, 5678 },
8811 onFirstRender: function() { 5679 onFirstRender: function() {
8812 setTimeout(function() { 5680 setTimeout(function() {
8813 chrome.send('metricsHandler:recordTime', [ 'History.ResultsRenderedTime', window.performance.now() ]); 5681 chrome.send('metricsHandler:recordTime', [ 'History.ResultsRenderedTime', window.performance.now() ]);
8814 }); 5682 });
8815 if (!this.hasDrawer_) { 5683 if (!this.hasDrawer_) {
8816 this.focusToolbarSearchField(); 5684 this.focusToolbarSearchField();
8817 } 5685 }
5686 md_history.ensureLazyLoaded();
8818 }, 5687 },
8819 _scrollHandler: function() { 5688 _scrollHandler: function() {
8820 this.toolbarShadow_ = this.scrollTarget.scrollTop != 0; 5689 this.toolbarShadow_ = this.scrollTarget.scrollTop != 0;
8821 }, 5690 },
8822 onMenuTap_: function() { 5691 onMenuTap_: function() {
8823 var drawer = this.$$('#drawer'); 5692 var drawer = this.$$('#drawer');
8824 if (drawer) drawer.toggle(); 5693 if (drawer) drawer.toggle();
8825 }, 5694 },
8826 checkboxSelected: function(e) { 5695 checkboxSelected: function(e) {
8827 var toolbar = this.$.toolbar; 5696 var toolbar = this.$.toolbar;
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
8940 5809
8941 case HistoryRange.MONTH: 5810 case HistoryRange.MONTH:
8942 histogramValue = HistoryPageViewHistogram.GROUPED_MONTH; 5811 histogramValue = HistoryPageViewHistogram.GROUPED_MONTH;
8943 break; 5812 break;
8944 } 5813 }
8945 break; 5814 break;
8946 } 5815 }
8947 md_history.BrowserService.getInstance().recordHistogram('History.HistoryPage View', histogramValue, HistoryPageViewHistogram.END); 5816 md_history.BrowserService.getInstance().recordHistogram('History.HistoryPage View', histogramValue, HistoryPageViewHistogram.END);
8948 } 5817 }
8949 }); 5818 });
OLDNEW
« no previous file with comments | « chrome/browser/resources/md_history/app.js ('k') | chrome/browser/resources/md_history/app.vulcanized.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698