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

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: Minor tweaks and 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 762 matching lines...) Expand 10 before | Expand all | Expand 10 after
6161 return loadTimeData.getStringF('historyInterval', queryStartTime, queryEndTi me); 3624 return loadTimeData.getStringF('historyInterval', queryStartTime, queryEndTi me);
6162 }, 3625 },
6163 hasDrawerChanged_: function() { 3626 hasDrawerChanged_: function() {
6164 this.updateStyles(); 3627 this.updateStyles();
6165 } 3628 }
6166 }); 3629 });
6167 3630
6168 // Copyright 2016 The Chromium Authors. All rights reserved. 3631 // Copyright 2016 The Chromium Authors. All rights reserved.
6169 // Use of this source code is governed by a BSD-style license that can be 3632 // Use of this source code is governed by a BSD-style license that can be
6170 // found in the LICENSE file. 3633 // found in the LICENSE file.
6171 Polymer({
6172 is: 'cr-dialog',
6173 "extends": 'dialog',
6174 created: function() {
6175 window.addEventListener('popstate', function() {
6176 if (this.open) this.cancel();
6177 }.bind(this));
6178 },
6179 cancel: function() {
6180 this.fire('cancel');
6181 HTMLDialogElement.prototype.close.call(this, '');
6182 },
6183 close: function(opt_returnValue) {
6184 HTMLDialogElement.prototype.close.call(this, 'success');
6185 },
6186 getCloseButton: function() {
6187 return this.$.close;
6188 }
6189 });
6190
6191 Polymer({
6192 is: 'fade-in-animation',
6193 behaviors: [ Polymer.NeonAnimationBehavior ],
6194 configure: function(config) {
6195 var node = config.node;
6196 this._effect = new KeyframeEffect(node, [ {
6197 opacity: '0'
6198 }, {
6199 opacity: '1'
6200 } ], this.timingFromConfig(config));
6201 return this._effect;
6202 }
6203 });
6204
6205 Polymer({
6206 is: 'fade-out-animation',
6207 behaviors: [ Polymer.NeonAnimationBehavior ],
6208 configure: function(config) {
6209 var node = config.node;
6210 this._effect = new KeyframeEffect(node, [ {
6211 opacity: '1'
6212 }, {
6213 opacity: '0'
6214 } ], this.timingFromConfig(config));
6215 return this._effect;
6216 }
6217 });
6218
6219 Polymer({
6220 is: 'paper-menu-grow-height-animation',
6221 behaviors: [ Polymer.NeonAnimationBehavior ],
6222 configure: function(config) {
6223 var node = config.node;
6224 var rect = node.getBoundingClientRect();
6225 var height = rect.height;
6226 this._effect = new KeyframeEffect(node, [ {
6227 height: height / 2 + 'px'
6228 }, {
6229 height: height + 'px'
6230 } ], this.timingFromConfig(config));
6231 return this._effect;
6232 }
6233 });
6234
6235 Polymer({
6236 is: 'paper-menu-grow-width-animation',
6237 behaviors: [ Polymer.NeonAnimationBehavior ],
6238 configure: function(config) {
6239 var node = config.node;
6240 var rect = node.getBoundingClientRect();
6241 var width = rect.width;
6242 this._effect = new KeyframeEffect(node, [ {
6243 width: width / 2 + 'px'
6244 }, {
6245 width: width + 'px'
6246 } ], this.timingFromConfig(config));
6247 return this._effect;
6248 }
6249 });
6250
6251 Polymer({
6252 is: 'paper-menu-shrink-width-animation',
6253 behaviors: [ Polymer.NeonAnimationBehavior ],
6254 configure: function(config) {
6255 var node = config.node;
6256 var rect = node.getBoundingClientRect();
6257 var width = rect.width;
6258 this._effect = new KeyframeEffect(node, [ {
6259 width: width + 'px'
6260 }, {
6261 width: width - width / 20 + 'px'
6262 } ], this.timingFromConfig(config));
6263 return this._effect;
6264 }
6265 });
6266
6267 Polymer({
6268 is: 'paper-menu-shrink-height-animation',
6269 behaviors: [ Polymer.NeonAnimationBehavior ],
6270 configure: function(config) {
6271 var node = config.node;
6272 var rect = node.getBoundingClientRect();
6273 var height = rect.height;
6274 var top = rect.top;
6275 this.setPrefixedProperty(node, 'transformOrigin', '0 0');
6276 this._effect = new KeyframeEffect(node, [ {
6277 height: height + 'px',
6278 transform: 'translateY(0)'
6279 }, {
6280 height: height / 2 + 'px',
6281 transform: 'translateY(-20px)'
6282 } ], this.timingFromConfig(config));
6283 return this._effect;
6284 }
6285 });
6286
6287 // Copyright 2016 The Chromium Authors. All rights reserved.
6288 // Use of this source code is governed by a BSD-style license that can be
6289 // found in the LICENSE file.
6290 var SLIDE_CUBIC_BEZIER = 'cubic-bezier(0.3, 0.95, 0.5, 1)';
6291
6292 Polymer({
6293 is: 'cr-shared-menu',
6294 behaviors: [ Polymer.IronA11yKeysBehavior ],
6295 properties: {
6296 menuOpen: {
6297 type: Boolean,
6298 observer: 'menuOpenChanged_',
6299 value: false,
6300 notify: true
6301 },
6302 itemData: {
6303 type: Object,
6304 value: null
6305 },
6306 keyEventTarget: {
6307 type: Object,
6308 value: function() {
6309 return this.$.menu;
6310 }
6311 },
6312 openAnimationConfig: {
6313 type: Object,
6314 value: function() {
6315 return [ {
6316 name: 'fade-in-animation',
6317 timing: {
6318 delay: 50,
6319 duration: 200
6320 }
6321 }, {
6322 name: 'paper-menu-grow-width-animation',
6323 timing: {
6324 delay: 50,
6325 duration: 150,
6326 easing: SLIDE_CUBIC_BEZIER
6327 }
6328 }, {
6329 name: 'paper-menu-grow-height-animation',
6330 timing: {
6331 delay: 100,
6332 duration: 275,
6333 easing: SLIDE_CUBIC_BEZIER
6334 }
6335 } ];
6336 }
6337 },
6338 closeAnimationConfig: {
6339 type: Object,
6340 value: function() {
6341 return [ {
6342 name: 'fade-out-animation',
6343 timing: {
6344 duration: 150
6345 }
6346 } ];
6347 }
6348 }
6349 },
6350 keyBindings: {
6351 tab: 'onTabPressed_'
6352 },
6353 listeners: {
6354 'dropdown.iron-overlay-canceled': 'onOverlayCanceled_'
6355 },
6356 lastAnchor_: null,
6357 firstFocus_: null,
6358 lastFocus_: null,
6359 attached: function() {
6360 window.addEventListener('resize', this.closeMenu.bind(this));
6361 },
6362 closeMenu: function() {
6363 if (this.root.activeElement == null) {
6364 this.$.dropdown.restoreFocusOnClose = false;
6365 }
6366 this.menuOpen = false;
6367 },
6368 openMenu: function(anchor, itemData) {
6369 if (this.lastAnchor_ == anchor && this.menuOpen) return;
6370 if (this.menuOpen) this.closeMenu();
6371 this.itemData = itemData;
6372 this.lastAnchor_ = anchor;
6373 this.$.dropdown.restoreFocusOnClose = true;
6374 var focusableChildren = Polymer.dom(this).querySelectorAll('[tabindex]:not([ disabled]):not([hidden]),' + 'button:not([disabled]):not([hidden])');
6375 if (focusableChildren.length > 0) {
6376 this.$.dropdown.focusTarget = focusableChildren[0];
6377 this.firstFocus_ = focusableChildren[0];
6378 this.lastFocus_ = focusableChildren[focusableChildren.length - 1];
6379 }
6380 this.$.dropdown.positionTarget = anchor;
6381 this.menuOpen = true;
6382 },
6383 toggleMenu: function(anchor, itemData) {
6384 if (anchor == this.lastAnchor_ && this.menuOpen) this.closeMenu(); else this .openMenu(anchor, itemData);
6385 },
6386 onTabPressed_: function(e) {
6387 if (!this.firstFocus_ || !this.lastFocus_) return;
6388 var toFocus;
6389 var keyEvent = e.detail.keyboardEvent;
6390 if (keyEvent.shiftKey && keyEvent.target == this.firstFocus_) toFocus = this .lastFocus_; else if (!keyEvent.shiftKey && keyEvent.target == this.lastFocus_) toFocus = this.firstFocus_;
6391 if (!toFocus) return;
6392 e.preventDefault();
6393 toFocus.focus();
6394 },
6395 menuOpenChanged_: function() {
6396 if (!this.menuOpen) {
6397 this.itemData = null;
6398 this.lastAnchor_ = null;
6399 }
6400 },
6401 onOverlayCanceled_: function(e) {
6402 if (e.detail.type == 'tap') this.$.dropdown.restoreFocusOnClose = false;
6403 }
6404 });
6405
6406 Polymer.PaperItemBehaviorImpl = {
6407 hostAttributes: {
6408 role: 'option',
6409 tabindex: '0'
6410 }
6411 };
6412
6413 Polymer.PaperItemBehavior = [ Polymer.IronButtonState, Polymer.IronControlState, Polymer.PaperItemBehaviorImpl ];
6414
6415 Polymer({
6416 is: 'paper-item',
6417 behaviors: [ Polymer.PaperItemBehavior ]
6418 });
6419
6420 // Copyright 2016 The Chromium Authors. All rights reserved.
6421 // Use of this source code is governed by a BSD-style license that can be
6422 // found in the LICENSE file.
6423 cr.define('md_history', function() { 3634 cr.define('md_history', function() {
6424 function BrowserService() { 3635 function BrowserService() {
6425 this.pendingDeleteItems_ = null; 3636 this.pendingDeleteItems_ = null;
6426 this.pendingDeletePromise_ = null; 3637 this.pendingDeletePromise_ = null;
6427 } 3638 }
6428 BrowserService.prototype = { 3639 BrowserService.prototype = {
6429 deleteItems: function(items) { 3640 deleteItems: function(items) {
6430 if (this.pendingDeleteItems_ != null) { 3641 if (this.pendingDeleteItems_ != null) {
6431 return new Promise(function(resolve, reject) { 3642 return new Promise(function(resolve, reject) {
6432 reject(items); 3643 reject(items);
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
6481 }); 3692 });
6482 3693
6483 function deleteComplete() { 3694 function deleteComplete() {
6484 md_history.BrowserService.getInstance().resolveDelete_(true); 3695 md_history.BrowserService.getInstance().resolveDelete_(true);
6485 } 3696 }
6486 3697
6487 function deleteFailed() { 3698 function deleteFailed() {
6488 md_history.BrowserService.getInstance().resolveDelete_(false); 3699 md_history.BrowserService.getInstance().resolveDelete_(false);
6489 } 3700 }
6490 3701
6491 Polymer({
6492 is: 'iron-collapse',
6493 behaviors: [ Polymer.IronResizableBehavior ],
6494 properties: {
6495 horizontal: {
6496 type: Boolean,
6497 value: false,
6498 observer: '_horizontalChanged'
6499 },
6500 opened: {
6501 type: Boolean,
6502 value: false,
6503 notify: true,
6504 observer: '_openedChanged'
6505 },
6506 noAnimation: {
6507 type: Boolean
6508 },
6509 _desiredSize: {
6510 type: String,
6511 value: ''
6512 }
6513 },
6514 get dimension() {
6515 return this.horizontal ? 'width' : 'height';
6516 },
6517 get _dimensionMax() {
6518 return this.horizontal ? 'maxWidth' : 'maxHeight';
6519 },
6520 get _dimensionMaxCss() {
6521 return this.horizontal ? 'max-width' : 'max-height';
6522 },
6523 hostAttributes: {
6524 role: 'group',
6525 'aria-hidden': 'true',
6526 'aria-expanded': 'false'
6527 },
6528 listeners: {
6529 transitionend: '_transitionEnd'
6530 },
6531 attached: function() {
6532 this._transitionEnd();
6533 },
6534 toggle: function() {
6535 this.opened = !this.opened;
6536 },
6537 show: function() {
6538 this.opened = true;
6539 },
6540 hide: function() {
6541 this.opened = false;
6542 },
6543 updateSize: function(size, animated) {
6544 size = size === 'auto' ? '' : size;
6545 if (this._desiredSize === size) {
6546 return;
6547 }
6548 this._desiredSize = size;
6549 this._updateTransition(false);
6550 var willAnimate = animated && !this.noAnimation && this._isDisplayed;
6551 if (willAnimate) {
6552 var startSize = this._calcSize();
6553 if (size === '') {
6554 this.style[this._dimensionMax] = '';
6555 size = this._calcSize();
6556 }
6557 this.style[this._dimensionMax] = startSize;
6558 this.scrollTop = this.scrollTop;
6559 this._updateTransition(true);
6560 willAnimate = size !== startSize;
6561 }
6562 this.style[this._dimensionMax] = size;
6563 if (!willAnimate) {
6564 this._transitionEnd();
6565 }
6566 },
6567 enableTransition: function(enabled) {
6568 Polymer.Base._warn('`enableTransition()` is deprecated, use `noAnimation` in stead.');
6569 this.noAnimation = !enabled;
6570 },
6571 _updateTransition: function(enabled) {
6572 this.style.transitionDuration = enabled && !this.noAnimation ? '' : '0s';
6573 },
6574 _horizontalChanged: function() {
6575 this.style.transitionProperty = this._dimensionMaxCss;
6576 var otherDimension = this._dimensionMax === 'maxWidth' ? 'maxHeight' : 'maxW idth';
6577 this.style[otherDimension] = '';
6578 this.updateSize(this.opened ? 'auto' : '0px', false);
6579 },
6580 _openedChanged: function() {
6581 this.setAttribute('aria-expanded', this.opened);
6582 this.setAttribute('aria-hidden', !this.opened);
6583 this.toggleClass('iron-collapse-closed', false);
6584 this.toggleClass('iron-collapse-opened', false);
6585 this.updateSize(this.opened ? 'auto' : '0px', true);
6586 if (this.opened) {
6587 this.focus();
6588 }
6589 },
6590 _transitionEnd: function() {
6591 this.style[this._dimensionMax] = this._desiredSize;
6592 this.toggleClass('iron-collapse-closed', !this.opened);
6593 this.toggleClass('iron-collapse-opened', this.opened);
6594 this._updateTransition(false);
6595 this.notifyResize();
6596 },
6597 get _isDisplayed() {
6598 var rect = this.getBoundingClientRect();
6599 for (var prop in rect) {
6600 if (rect[prop] !== 0) return true;
6601 }
6602 return false;
6603 },
6604 _calcSize: function() {
6605 return this.getBoundingClientRect()[this.dimension] + 'px';
6606 }
6607 });
6608
6609 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
6610 // Use of this source code is governed by a BSD-style license that can be
6611 // found in the LICENSE file.
6612 var EventTrackerEntry;
6613
6614 function EventTracker() {
6615 this.listeners_ = [];
6616 }
6617
6618 EventTracker.prototype = {
6619 add: function(target, eventType, listener, opt_capture) {
6620 var capture = !!opt_capture;
6621 var h = {
6622 target: target,
6623 eventType: eventType,
6624 listener: listener,
6625 capture: capture
6626 };
6627 this.listeners_.push(h);
6628 target.addEventListener(eventType, listener, capture);
6629 },
6630 remove: function(target, eventType) {
6631 this.listeners_ = this.listeners_.filter(function(h) {
6632 if (h.target == target && (!eventType || h.eventType == eventType)) {
6633 EventTracker.removeEventListener_(h);
6634 return false;
6635 }
6636 return true;
6637 });
6638 },
6639 removeAll: function() {
6640 this.listeners_.forEach(EventTracker.removeEventListener_);
6641 this.listeners_ = [];
6642 }
6643 };
6644
6645 EventTracker.removeEventListener_ = function(h) {
6646 h.target.removeEventListener(h.eventType, h.listener, h.capture);
6647 };
6648
6649 // Copyright 2014 The Chromium Authors. All rights reserved.
6650 // Use of this source code is governed by a BSD-style license that can be
6651 // found in the LICENSE file.
6652 cr.define('cr.ui', function() {
6653 function FocusRow(root, boundary, opt_delegate) {
6654 this.root = root;
6655 this.boundary_ = boundary || document.documentElement;
6656 this.delegate = opt_delegate;
6657 this.eventTracker = new EventTracker();
6658 }
6659 FocusRow.Delegate = function() {};
6660 FocusRow.Delegate.prototype = {
6661 onKeydown: assertNotReached,
6662 onFocus: assertNotReached
6663 };
6664 FocusRow.ACTIVE_CLASS = 'focus-row-active';
6665 FocusRow.isFocusable = function(element) {
6666 if (!element || element.disabled) return false;
6667 function isVisible(element) {
6668 assertInstanceof(element, Element);
6669 var style = window.getComputedStyle(element);
6670 if (style.visibility == 'hidden' || style.display == 'none') return false;
6671 var parent = element.parentNode;
6672 if (!parent) return false;
6673 if (parent == element.ownerDocument || parent instanceof DocumentFragment) return true;
6674 return isVisible(parent);
6675 }
6676 return isVisible(element);
6677 };
6678 FocusRow.prototype = {
6679 addItem: function(type, query) {
6680 assert(type);
6681 var element = this.root.querySelector(query);
6682 if (!element) return false;
6683 element.setAttribute('focus-type', type);
6684 element.tabIndex = this.isActive() ? 0 : -1;
6685 this.eventTracker.add(element, 'blur', this.onBlur_.bind(this));
6686 this.eventTracker.add(element, 'focus', this.onFocus_.bind(this));
6687 this.eventTracker.add(element, 'keydown', this.onKeydown_.bind(this));
6688 this.eventTracker.add(element, 'mousedown', this.onMousedown_.bind(this));
6689 return true;
6690 },
6691 destroy: function() {
6692 this.eventTracker.removeAll();
6693 },
6694 getCustomEquivalent: function(sampleElement) {
6695 return assert(this.getFirstFocusable());
6696 },
6697 getElements: function() {
6698 var elements = this.root.querySelectorAll('[focus-type]');
6699 return Array.prototype.slice.call(elements);
6700 },
6701 getEquivalentElement: function(sampleElement) {
6702 if (this.getFocusableElements().indexOf(sampleElement) >= 0) return sample Element;
6703 var sampleFocusType = this.getTypeForElement(sampleElement);
6704 if (sampleFocusType) {
6705 var sameType = this.getFirstFocusable(sampleFocusType);
6706 if (sameType) return sameType;
6707 }
6708 return this.getCustomEquivalent(sampleElement);
6709 },
6710 getFirstFocusable: function(opt_type) {
6711 var filter = opt_type ? '="' + opt_type + '"' : '';
6712 var elements = this.root.querySelectorAll('[focus-type' + filter + ']');
6713 for (var i = 0; i < elements.length; ++i) {
6714 if (cr.ui.FocusRow.isFocusable(elements[i])) return elements[i];
6715 }
6716 return null;
6717 },
6718 getFocusableElements: function() {
6719 return this.getElements().filter(cr.ui.FocusRow.isFocusable);
6720 },
6721 getTypeForElement: function(element) {
6722 return element.getAttribute('focus-type') || '';
6723 },
6724 isActive: function() {
6725 return this.root.classList.contains(FocusRow.ACTIVE_CLASS);
6726 },
6727 makeActive: function(active) {
6728 if (active == this.isActive()) return;
6729 this.getElements().forEach(function(element) {
6730 element.tabIndex = active ? 0 : -1;
6731 });
6732 this.root.classList.toggle(FocusRow.ACTIVE_CLASS, active);
6733 },
6734 onBlur_: function(e) {
6735 if (!this.boundary_.contains(e.relatedTarget)) return;
6736 var currentTarget = e.currentTarget;
6737 if (this.getFocusableElements().indexOf(currentTarget) >= 0) this.makeActi ve(false);
6738 },
6739 onFocus_: function(e) {
6740 if (this.delegate) this.delegate.onFocus(this, e);
6741 },
6742 onMousedown_: function(e) {
6743 if (e.button) return;
6744 if (!e.currentTarget.disabled) e.currentTarget.tabIndex = 0;
6745 },
6746 onKeydown_: function(e) {
6747 var elements = this.getFocusableElements();
6748 var currentElement = e.currentTarget;
6749 var elementIndex = elements.indexOf(currentElement);
6750 assert(elementIndex >= 0);
6751 if (this.delegate && this.delegate.onKeydown(this, e)) return;
6752 if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return;
6753 var index = -1;
6754 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;
6755 var elementToFocus = elements[index];
6756 if (elementToFocus) {
6757 this.getEquivalentElement(elementToFocus).focus();
6758 e.preventDefault();
6759 }
6760 }
6761 };
6762 return {
6763 FocusRow: FocusRow
6764 };
6765 });
6766
6767 // Copyright 2016 The Chromium Authors. All rights reserved.
6768 // Use of this source code is governed by a BSD-style license that can be
6769 // found in the LICENSE file.
6770 cr.define('cr.icon', function() {
6771 function getSupportedScaleFactors() {
6772 var supportedScaleFactors = [];
6773 if (!cr.isIOS) {
6774 supportedScaleFactors.push(1);
6775 }
6776 if (cr.isMac || cr.isChromeOS || cr.isWindows || cr.isLinux) {
6777 supportedScaleFactors.push(2);
6778 } else {
6779 supportedScaleFactors.push(window.devicePixelRatio);
6780 }
6781 return supportedScaleFactors;
6782 }
6783 function getImageSet(path) {
6784 var supportedScaleFactors = getSupportedScaleFactors();
6785 var replaceStartIndex = path.indexOf('scalefactor');
6786 if (replaceStartIndex < 0) return url(path);
6787 var s = '';
6788 for (var i = 0; i < supportedScaleFactors.length; ++i) {
6789 var scaleFactor = supportedScaleFactors[i];
6790 var pathWithScaleFactor = path.substr(0, replaceStartIndex) + scaleFactor + path.substr(replaceStartIndex + 'scalefactor'.length);
6791 s += url(pathWithScaleFactor) + ' ' + scaleFactor + 'x';
6792 if (i != supportedScaleFactors.length - 1) s += ', ';
6793 }
6794 return '-webkit-image-set(' + s + ')';
6795 }
6796 function getImage(path) {
6797 var chromeThemePath = 'chrome://theme';
6798 var isChromeThemeUrl = path.slice(0, chromeThemePath.length) == chromeThemeP ath;
6799 return isChromeThemeUrl ? getImageSet(path + '@scalefactorx') : url(path);
6800 }
6801 var FAVICON_URL_REGEX = /\.ico$/i;
6802 function getFavicon(url, opt_size, opt_type) {
6803 var size = opt_size || 16;
6804 var type = opt_type || 'favicon';
6805 return getImageSet('chrome://' + type + '/size/' + size + '@scalefactorx/' + (FAVICON_URL_REGEX.test(url) ? 'iconurl/' : '') + url);
6806 }
6807 return {
6808 getImage: getImage,
6809 getFavicon: getFavicon
6810 };
6811 });
6812
6813 // Copyright 2016 The Chromium Authors. All rights reserved.
6814 // Use of this source code is governed by a BSD-style license that can be
6815 // found in the LICENSE file.
6816 Polymer({
6817 is: 'history-searched-label',
6818 properties: {
6819 title: String,
6820 searchTerm: String
6821 },
6822 observers: [ 'setSearchedTextToBold_(title, searchTerm)' ],
6823 setSearchedTextToBold_: function() {
6824 var i = 0;
6825 var titleText = this.title;
6826 if (this.searchTerm == '' || this.searchTerm == null) {
6827 this.textContent = titleText;
6828 return;
6829 }
6830 var re = new RegExp(quoteString(this.searchTerm), 'gim');
6831 var match;
6832 this.textContent = '';
6833 while (match = re.exec(titleText)) {
6834 if (match.index > i) this.appendChild(document.createTextNode(titleText.sl ice(i, match.index)));
6835 i = re.lastIndex;
6836 var b = document.createElement('b');
6837 b.textContent = titleText.substring(match.index, i);
6838 this.appendChild(b);
6839 }
6840 if (i < titleText.length) this.appendChild(document.createTextNode(titleText .slice(i)));
6841 }
6842 });
6843
6844 // Copyright 2015 The Chromium Authors. All rights reserved.
6845 // Use of this source code is governed by a BSD-style license that can be
6846 // found in the LICENSE file.
6847 function HistoryFocusRow(root, boundary, delegate) {
6848 cr.ui.FocusRow.call(this, root, boundary, delegate);
6849 this.addItems();
6850 }
6851
6852 HistoryFocusRow.prototype = {
6853 __proto__: cr.ui.FocusRow.prototype,
6854 getCustomEquivalent: function(sampleElement) {
6855 var equivalent;
6856 if (this.getTypeForElement(sampleElement) == 'star') equivalent = this.getFi rstFocusable('title');
6857 return equivalent || cr.ui.FocusRow.prototype.getCustomEquivalent.call(this, sampleElement);
6858 },
6859 addItems: function() {
6860 this.destroy();
6861 assert(this.addItem('checkbox', '#checkbox'));
6862 assert(this.addItem('title', '#title'));
6863 assert(this.addItem('menu-button', '#menu-button'));
6864 this.addItem('star', '#bookmark-star');
6865 }
6866 };
6867
6868 cr.define('md_history', function() {
6869 function FocusRowDelegate(historyItemElement) {
6870 this.historyItemElement = historyItemElement;
6871 }
6872 FocusRowDelegate.prototype = {
6873 onFocus: function(row, e) {
6874 this.historyItemElement.lastFocused = e.path[0];
6875 },
6876 onKeydown: function(row, e) {
6877 if (e.key == 'Enter') e.stopPropagation();
6878 return false;
6879 }
6880 };
6881 var HistoryItem = Polymer({
6882 is: 'history-item',
6883 properties: {
6884 item: {
6885 type: Object,
6886 observer: 'showIcon_'
6887 },
6888 searchTerm: {
6889 type: String
6890 },
6891 selected: {
6892 type: Boolean,
6893 reflectToAttribute: true
6894 },
6895 isCardStart: {
6896 type: Boolean,
6897 reflectToAttribute: true
6898 },
6899 isCardEnd: {
6900 type: Boolean,
6901 reflectToAttribute: true
6902 },
6903 embedded: {
6904 type: Boolean,
6905 reflectToAttribute: true
6906 },
6907 hasTimeGap: {
6908 type: Boolean
6909 },
6910 numberOfItems: {
6911 type: Number
6912 },
6913 path: String,
6914 index: Number,
6915 lastFocused: {
6916 type: Object,
6917 notify: true
6918 },
6919 ironListTabIndex: {
6920 type: Number,
6921 observer: 'ironListTabIndexChanged_'
6922 }
6923 },
6924 row_: null,
6925 attached: function() {
6926 Polymer.RenderStatus.afterNextRender(this, function() {
6927 this.row_ = new HistoryFocusRow(this.$['sizing-container'], null, new Fo cusRowDelegate(this));
6928 this.row_.makeActive(this.ironListTabIndex == 0);
6929 this.listen(this, 'focus', 'onFocus_');
6930 this.listen(this, 'dom-change', 'onDomChange_');
6931 });
6932 },
6933 detached: function() {
6934 this.unlisten(this, 'focus', 'onFocus_');
6935 this.unlisten(this, 'dom-change', 'onDomChange_');
6936 if (this.row_) this.row_.destroy();
6937 },
6938 onFocus_: function() {
6939 if (this.lastFocused) this.row_.getEquivalentElement(this.lastFocused).foc us(); else this.row_.getFirstFocusable().focus();
6940 this.tabIndex = -1;
6941 },
6942 ironListTabIndexChanged_: function() {
6943 if (this.row_) this.row_.makeActive(this.ironListTabIndex == 0);
6944 },
6945 onDomChange_: function() {
6946 if (this.row_) this.row_.addItems();
6947 },
6948 onCheckboxSelected_: function(e) {
6949 this.fire('history-checkbox-select', {
6950 element: this,
6951 shiftKey: e.shiftKey
6952 });
6953 e.preventDefault();
6954 },
6955 onCheckboxMousedown_: function(e) {
6956 if (e.shiftKey) e.preventDefault();
6957 },
6958 getEntrySummary_: function() {
6959 var item = this.item;
6960 return loadTimeData.getStringF('entrySummary', item.dateTimeOfDay, item.st arred ? loadTimeData.getString('bookmarked') : '', item.title, item.domain);
6961 },
6962 getAriaChecked_: function(selected) {
6963 return selected ? 'true' : 'false';
6964 },
6965 onRemoveBookmarkTap_: function() {
6966 if (!this.item.starred) return;
6967 if (this.$$('#bookmark-star') == this.root.activeElement) this.$['menu-but ton'].focus();
6968 var browserService = md_history.BrowserService.getInstance();
6969 browserService.removeBookmark(this.item.url);
6970 browserService.recordAction('BookmarkStarClicked');
6971 this.fire('remove-bookmark-stars', this.item.url);
6972 },
6973 onMenuButtonTap_: function(e) {
6974 this.fire('toggle-menu', {
6975 target: Polymer.dom(e).localTarget,
6976 index: this.index,
6977 item: this.item,
6978 path: this.path
6979 });
6980 e.stopPropagation();
6981 },
6982 onLinkClick_: function() {
6983 var browserService = md_history.BrowserService.getInstance();
6984 browserService.recordAction('EntryLinkClick');
6985 if (this.searchTerm) browserService.recordAction('SearchResultClick');
6986 if (this.index == undefined) return;
6987 browserService.recordHistogram('HistoryPage.ClickPosition', this.index, UM A_MAX_BUCKET_VALUE);
6988 if (this.index <= UMA_MAX_SUBSET_BUCKET_VALUE) {
6989 browserService.recordHistogram('HistoryPage.ClickPositionSubset', this.i ndex, UMA_MAX_SUBSET_BUCKET_VALUE);
6990 }
6991 },
6992 onLinkRightClick_: function() {
6993 md_history.BrowserService.getInstance().recordAction('EntryLinkRightClick' );
6994 },
6995 showIcon_: function() {
6996 this.$.icon.style.backgroundImage = cr.icon.getFavicon(this.item.url);
6997 },
6998 selectionNotAllowed_: function() {
6999 return !loadTimeData.getBoolean('allowDeletingHistory');
7000 },
7001 cardTitle_: function(numberOfItems, historyDate, search) {
7002 if (!search) return this.item.dateRelativeDay;
7003 var resultId = numberOfItems == 1 ? 'searchResult' : 'searchResults';
7004 return loadTimeData.getStringF('foundSearchResults', numberOfItems, loadTi meData.getString(resultId), search);
7005 }
7006 });
7007 HistoryItem.needsTimeGap = function(visits, currentIndex, searchedTerm) {
7008 if (currentIndex >= visits.length - 1 || visits.length == 0) return false;
7009 var currentItem = visits[currentIndex];
7010 var nextItem = visits[currentIndex + 1];
7011 if (searchedTerm) return currentItem.dateShort != nextItem.dateShort;
7012 return currentItem.time - nextItem.time > BROWSING_GAP_TIME && currentItem.d ateRelativeDay == nextItem.dateRelativeDay;
7013 };
7014 return {
7015 HistoryItem: HistoryItem
7016 };
7017 });
7018
7019 // Copyright 2016 The Chromium Authors. All rights reserved.
7020 // Use of this source code is governed by a BSD-style license that can be
7021 // found in the LICENSE file.
7022 var SelectionTreeNode = function(currentPath) {
7023 this.currentPath = currentPath;
7024 this.leaf = false;
7025 this.indexes = [];
7026 this.children = [];
7027 };
7028
7029 SelectionTreeNode.prototype.addChild = function(index, path) {
7030 this.indexes.push(index);
7031 this.children[index] = new SelectionTreeNode(path);
7032 };
7033
7034 var HistoryListBehavior = {
7035 properties: {
7036 selectedPaths: {
7037 type: Object,
7038 value: function() {
7039 return new Set();
7040 }
7041 },
7042 lastSelectedPath: String
7043 },
7044 listeners: {
7045 'history-checkbox-select': 'itemSelected_'
7046 },
7047 hasResults: function(historyDataLength) {
7048 return historyDataLength > 0;
7049 },
7050 noResultsMessage: function(searchedTerm, isLoading) {
7051 if (isLoading) return '';
7052 var messageId = searchedTerm !== '' ? 'noSearchResults' : 'noResults';
7053 return loadTimeData.getString(messageId);
7054 },
7055 unselectAllItems: function() {
7056 this.selectedPaths.forEach(function(path) {
7057 this.set(path + '.selected', false);
7058 }.bind(this));
7059 this.selectedPaths.clear();
7060 },
7061 deleteSelected: function() {
7062 var toBeRemoved = Array.from(this.selectedPaths.values()).map(function(path) {
7063 return this.get(path);
7064 }.bind(this));
7065 md_history.BrowserService.getInstance().deleteItems(toBeRemoved).then(functi on() {
7066 this.removeItemsByPath(Array.from(this.selectedPaths));
7067 this.fire('unselect-all');
7068 }.bind(this));
7069 },
7070 removeItemsByPath: function(paths) {
7071 if (paths.length == 0) return;
7072 this.removeItemsBeneathNode_(this.buildRemovalTree_(paths));
7073 },
7074 buildRemovalTree_: function(paths) {
7075 var rootNode = new SelectionTreeNode(paths[0].split('.')[0]);
7076 paths.forEach(function(path) {
7077 var components = path.split('.');
7078 var node = rootNode;
7079 components.shift();
7080 while (components.length > 1) {
7081 var index = Number(components.shift());
7082 var arrayName = components.shift();
7083 if (!node.children[index]) node.addChild(index, [ node.currentPath, inde x, arrayName ].join('.'));
7084 node = node.children[index];
7085 }
7086 node.leaf = true;
7087 node.indexes.push(Number(components.shift()));
7088 });
7089 return rootNode;
7090 },
7091 removeItemsBeneathNode_: function(node) {
7092 var array = this.get(node.currentPath);
7093 var splices = [];
7094 node.indexes.sort(function(a, b) {
7095 return b - a;
7096 });
7097 node.indexes.forEach(function(index) {
7098 if (node.leaf || this.removeItemsBeneathNode_(node.children[index])) {
7099 var item = array.splice(index, 1)[0];
7100 splices.push({
7101 index: index,
7102 removed: [ item ],
7103 addedCount: 0,
7104 object: array,
7105 type: 'splice'
7106 });
7107 }
7108 }.bind(this));
7109 if (array.length == 0 && node.currentPath.indexOf('.') != -1) return true;
7110 this.notifySplices(node.currentPath, splices);
7111 return false;
7112 },
7113 itemSelected_: function(e) {
7114 var item = e.detail.element;
7115 var paths = [];
7116 var itemPath = item.path;
7117 if (e.detail.shiftKey && this.lastSelectedPath) {
7118 var itemPathComponents = itemPath.split('.');
7119 var itemIndex = Number(itemPathComponents.pop());
7120 var itemArrayPath = itemPathComponents.join('.');
7121 var lastItemPathComponents = this.lastSelectedPath.split('.');
7122 var lastItemIndex = Number(lastItemPathComponents.pop());
7123 if (itemArrayPath == lastItemPathComponents.join('.')) {
7124 for (var i = Math.min(itemIndex, lastItemIndex); i <= Math.max(itemIndex , lastItemIndex); i++) {
7125 paths.push(itemArrayPath + '.' + i);
7126 }
7127 }
7128 }
7129 if (paths.length == 0) paths.push(item.path);
7130 var selected = !this.selectedPaths.has(item.path);
7131 paths.forEach(function(path) {
7132 this.set(path + '.selected', selected);
7133 if (selected) {
7134 this.selectedPaths.add(path);
7135 return;
7136 }
7137 this.selectedPaths.delete(path);
7138 }.bind(this));
7139 this.lastSelectedPath = itemPath;
7140 }
7141 };
7142
7143 // Copyright 2016 The Chromium Authors. All rights reserved.
7144 // Use of this source code is governed by a BSD-style license that can be
7145 // found in the LICENSE file.
7146 var HistoryDomain;
7147
7148 var HistoryGroup;
7149
7150 Polymer({
7151 is: 'history-grouped-list',
7152 behaviors: [ HistoryListBehavior ],
7153 properties: {
7154 historyData: {
7155 type: Array
7156 },
7157 groupedHistoryData_: {
7158 type: Array
7159 },
7160 searchedTerm: {
7161 type: String,
7162 value: ''
7163 },
7164 range: {
7165 type: Number
7166 },
7167 queryStartTime: String,
7168 queryEndTime: String
7169 },
7170 observers: [ 'updateGroupedHistoryData_(range, historyData)' ],
7171 createHistoryDomains_: function(visits) {
7172 var domainIndexes = {};
7173 var domains = [];
7174 for (var i = 0, visit; visit = visits[i]; i++) {
7175 var domain = visit.domain;
7176 if (domainIndexes[domain] == undefined) {
7177 domainIndexes[domain] = domains.length;
7178 domains.push({
7179 domain: domain,
7180 visits: [],
7181 expanded: false,
7182 rendered: false
7183 });
7184 }
7185 domains[domainIndexes[domain]].visits.push(visit);
7186 }
7187 var sortByVisits = function(a, b) {
7188 return b.visits.length - a.visits.length;
7189 };
7190 domains.sort(sortByVisits);
7191 return domains;
7192 },
7193 updateGroupedHistoryData_: function() {
7194 if (this.historyData.length == 0) {
7195 this.groupedHistoryData_ = [];
7196 return;
7197 }
7198 if (this.range == HistoryRange.WEEK) {
7199 var days = [];
7200 var currentDayVisits = [ this.historyData[0] ];
7201 var pushCurrentDay = function() {
7202 days.push({
7203 title: this.searchedTerm ? currentDayVisits[0].dateShort : currentDayV isits[0].dateRelativeDay,
7204 domains: this.createHistoryDomains_(currentDayVisits)
7205 });
7206 }.bind(this);
7207 var visitsSameDay = function(a, b) {
7208 if (this.searchedTerm) return a.dateShort == b.dateShort;
7209 return a.dateRelativeDay == b.dateRelativeDay;
7210 }.bind(this);
7211 for (var i = 1; i < this.historyData.length; i++) {
7212 var visit = this.historyData[i];
7213 if (!visitsSameDay(visit, currentDayVisits[0])) {
7214 pushCurrentDay();
7215 currentDayVisits = [];
7216 }
7217 currentDayVisits.push(visit);
7218 }
7219 pushCurrentDay();
7220 this.groupedHistoryData_ = days;
7221 } else if (this.range == HistoryRange.MONTH) {
7222 this.groupedHistoryData_ = [ {
7223 title: this.queryStartTime + ' – ' + this.queryEndTime,
7224 domains: this.createHistoryDomains_(this.historyData)
7225 } ];
7226 }
7227 },
7228 toggleDomainExpanded_: function(e) {
7229 var collapse = e.currentTarget.parentNode.querySelector('iron-collapse');
7230 e.model.set('domain.rendered', true);
7231 setTimeout(function() {
7232 collapse.toggle();
7233 }, 0);
7234 },
7235 needsTimeGap_: function(groupIndex, domainIndex, itemIndex) {
7236 var visits = this.groupedHistoryData_[groupIndex].domains[domainIndex].visit s;
7237 return md_history.HistoryItem.needsTimeGap(visits, itemIndex, this.searchedT erm);
7238 },
7239 pathForItem_: function(groupIndex, domainIndex, itemIndex) {
7240 return [ 'groupedHistoryData_', groupIndex, 'domains', domainIndex, 'visits' , itemIndex ].join('.');
7241 },
7242 getWebsiteIconStyle_: function(domain) {
7243 return 'background-image: ' + cr.icon.getFavicon(domain.visits[0].url);
7244 },
7245 getDropdownIcon_: function(expanded) {
7246 return expanded ? 'cr:expand-less' : 'cr:expand-more';
7247 }
7248 });
7249
7250 (function() { 3702 (function() {
7251 var IOS = navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/); 3703 var IOS = navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/);
7252 var IOS_TOUCH_SCROLLING = IOS && IOS[1] >= 8; 3704 var IOS_TOUCH_SCROLLING = IOS && IOS[1] >= 8;
7253 var DEFAULT_PHYSICAL_COUNT = 3; 3705 var DEFAULT_PHYSICAL_COUNT = 3;
7254 var HIDDEN_Y = '-10000px'; 3706 var HIDDEN_Y = '-10000px';
7255 var DEFAULT_GRID_SIZE = 200; 3707 var DEFAULT_GRID_SIZE = 200;
7256 var SECRET_TABINDEX = -100; 3708 var SECRET_TABINDEX = -100;
7257 Polymer({ 3709 Polymer({
7258 is: 'iron-list', 3710 is: 'iron-list',
7259 properties: { 3711 properties: {
(...skipping 933 matching lines...) Expand 10 before | Expand all | Expand 10 after
8193 this._setLowerTriggered(true); 4645 this._setLowerTriggered(true);
8194 this.fire('lower-threshold'); 4646 this.fire('lower-threshold');
8195 } 4647 }
8196 }, 4648 },
8197 clearTriggers: function() { 4649 clearTriggers: function() {
8198 this._setUpperTriggered(false); 4650 this._setUpperTriggered(false);
8199 this._setLowerTriggered(false); 4651 this._setLowerTriggered(false);
8200 } 4652 }
8201 }); 4653 });
8202 4654
4655 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
4656 // Use of this source code is governed by a BSD-style license that can be
4657 // found in the LICENSE file.
4658 var EventTrackerEntry;
4659
4660 function EventTracker() {
4661 this.listeners_ = [];
4662 }
4663
4664 EventTracker.prototype = {
4665 add: function(target, eventType, listener, opt_capture) {
4666 var capture = !!opt_capture;
4667 var h = {
4668 target: target,
4669 eventType: eventType,
4670 listener: listener,
4671 capture: capture
4672 };
4673 this.listeners_.push(h);
4674 target.addEventListener(eventType, listener, capture);
4675 },
4676 remove: function(target, eventType) {
4677 this.listeners_ = this.listeners_.filter(function(h) {
4678 if (h.target == target && (!eventType || h.eventType == eventType)) {
4679 EventTracker.removeEventListener_(h);
4680 return false;
4681 }
4682 return true;
4683 });
4684 },
4685 removeAll: function() {
4686 this.listeners_.forEach(EventTracker.removeEventListener_);
4687 this.listeners_ = [];
4688 }
4689 };
4690
4691 EventTracker.removeEventListener_ = function(h) {
4692 h.target.removeEventListener(h.eventType, h.listener, h.capture);
4693 };
4694
4695 // Copyright 2014 The Chromium Authors. All rights reserved.
4696 // Use of this source code is governed by a BSD-style license that can be
4697 // found in the LICENSE file.
4698 cr.define('cr.ui', function() {
4699 function FocusRow(root, boundary, opt_delegate) {
4700 this.root = root;
4701 this.boundary_ = boundary || document.documentElement;
4702 this.delegate = opt_delegate;
4703 this.eventTracker = new EventTracker();
4704 }
4705 FocusRow.Delegate = function() {};
4706 FocusRow.Delegate.prototype = {
4707 onKeydown: assertNotReached,
4708 onFocus: assertNotReached
4709 };
4710 FocusRow.ACTIVE_CLASS = 'focus-row-active';
4711 FocusRow.isFocusable = function(element) {
4712 if (!element || element.disabled) return false;
4713 function isVisible(element) {
4714 assertInstanceof(element, Element);
4715 var style = window.getComputedStyle(element);
4716 if (style.visibility == 'hidden' || style.display == 'none') return false;
4717 var parent = element.parentNode;
4718 if (!parent) return false;
4719 if (parent == element.ownerDocument || parent instanceof DocumentFragment) return true;
4720 return isVisible(parent);
4721 }
4722 return isVisible(element);
4723 };
4724 FocusRow.prototype = {
4725 addItem: function(type, query) {
4726 assert(type);
4727 var element = this.root.querySelector(query);
4728 if (!element) return false;
4729 element.setAttribute('focus-type', type);
4730 element.tabIndex = this.isActive() ? 0 : -1;
4731 this.eventTracker.add(element, 'blur', this.onBlur_.bind(this));
4732 this.eventTracker.add(element, 'focus', this.onFocus_.bind(this));
4733 this.eventTracker.add(element, 'keydown', this.onKeydown_.bind(this));
4734 this.eventTracker.add(element, 'mousedown', this.onMousedown_.bind(this));
4735 return true;
4736 },
4737 destroy: function() {
4738 this.eventTracker.removeAll();
4739 },
4740 getCustomEquivalent: function(sampleElement) {
4741 return assert(this.getFirstFocusable());
4742 },
4743 getElements: function() {
4744 var elements = this.root.querySelectorAll('[focus-type]');
4745 return Array.prototype.slice.call(elements);
4746 },
4747 getEquivalentElement: function(sampleElement) {
4748 if (this.getFocusableElements().indexOf(sampleElement) >= 0) return sample Element;
4749 var sampleFocusType = this.getTypeForElement(sampleElement);
4750 if (sampleFocusType) {
4751 var sameType = this.getFirstFocusable(sampleFocusType);
4752 if (sameType) return sameType;
4753 }
4754 return this.getCustomEquivalent(sampleElement);
4755 },
4756 getFirstFocusable: function(opt_type) {
4757 var filter = opt_type ? '="' + opt_type + '"' : '';
4758 var elements = this.root.querySelectorAll('[focus-type' + filter + ']');
4759 for (var i = 0; i < elements.length; ++i) {
4760 if (cr.ui.FocusRow.isFocusable(elements[i])) return elements[i];
4761 }
4762 return null;
4763 },
4764 getFocusableElements: function() {
4765 return this.getElements().filter(cr.ui.FocusRow.isFocusable);
4766 },
4767 getTypeForElement: function(element) {
4768 return element.getAttribute('focus-type') || '';
4769 },
4770 isActive: function() {
4771 return this.root.classList.contains(FocusRow.ACTIVE_CLASS);
4772 },
4773 makeActive: function(active) {
4774 if (active == this.isActive()) return;
4775 this.getElements().forEach(function(element) {
4776 element.tabIndex = active ? 0 : -1;
4777 });
4778 this.root.classList.toggle(FocusRow.ACTIVE_CLASS, active);
4779 },
4780 onBlur_: function(e) {
4781 if (!this.boundary_.contains(e.relatedTarget)) return;
4782 var currentTarget = e.currentTarget;
4783 if (this.getFocusableElements().indexOf(currentTarget) >= 0) this.makeActi ve(false);
4784 },
4785 onFocus_: function(e) {
4786 if (this.delegate) this.delegate.onFocus(this, e);
4787 },
4788 onMousedown_: function(e) {
4789 if (e.button) return;
4790 if (!e.currentTarget.disabled) e.currentTarget.tabIndex = 0;
4791 },
4792 onKeydown_: function(e) {
4793 var elements = this.getFocusableElements();
4794 var currentElement = e.currentTarget;
4795 var elementIndex = elements.indexOf(currentElement);
4796 assert(elementIndex >= 0);
4797 if (this.delegate && this.delegate.onKeydown(this, e)) return;
4798 if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return;
4799 var index = -1;
4800 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;
4801 var elementToFocus = elements[index];
4802 if (elementToFocus) {
4803 this.getEquivalentElement(elementToFocus).focus();
4804 e.preventDefault();
4805 }
4806 }
4807 };
4808 return {
4809 FocusRow: FocusRow
4810 };
4811 });
4812
4813 // Copyright 2016 The Chromium Authors. All rights reserved.
4814 // Use of this source code is governed by a BSD-style license that can be
4815 // found in the LICENSE file.
4816 cr.define('cr.icon', function() {
4817 function getSupportedScaleFactors() {
4818 var supportedScaleFactors = [];
4819 if (!cr.isIOS) {
4820 supportedScaleFactors.push(1);
4821 }
4822 if (cr.isMac || cr.isChromeOS || cr.isWindows || cr.isLinux) {
4823 supportedScaleFactors.push(2);
4824 } else {
4825 supportedScaleFactors.push(window.devicePixelRatio);
4826 }
4827 return supportedScaleFactors;
4828 }
4829 function getImageSet(path) {
4830 var supportedScaleFactors = getSupportedScaleFactors();
4831 var replaceStartIndex = path.indexOf('scalefactor');
4832 if (replaceStartIndex < 0) return url(path);
4833 var s = '';
4834 for (var i = 0; i < supportedScaleFactors.length; ++i) {
4835 var scaleFactor = supportedScaleFactors[i];
4836 var pathWithScaleFactor = path.substr(0, replaceStartIndex) + scaleFactor + path.substr(replaceStartIndex + 'scalefactor'.length);
4837 s += url(pathWithScaleFactor) + ' ' + scaleFactor + 'x';
4838 if (i != supportedScaleFactors.length - 1) s += ', ';
4839 }
4840 return '-webkit-image-set(' + s + ')';
4841 }
4842 function getImage(path) {
4843 var chromeThemePath = 'chrome://theme';
4844 var isChromeThemeUrl = path.slice(0, chromeThemePath.length) == chromeThemeP ath;
4845 return isChromeThemeUrl ? getImageSet(path + '@scalefactorx') : url(path);
4846 }
4847 var FAVICON_URL_REGEX = /\.ico$/i;
4848 function getFavicon(url, opt_size, opt_type) {
4849 var size = opt_size || 16;
4850 var type = opt_type || 'favicon';
4851 return getImageSet('chrome://' + type + '/size/' + size + '@scalefactorx/' + (FAVICON_URL_REGEX.test(url) ? 'iconurl/' : '') + url);
4852 }
4853 return {
4854 getImage: getImage,
4855 getFavicon: getFavicon
4856 };
4857 });
4858
4859 // Copyright 2016 The Chromium Authors. All rights reserved.
4860 // Use of this source code is governed by a BSD-style license that can be
4861 // found in the LICENSE file.
4862 Polymer({
4863 is: 'history-searched-label',
4864 properties: {
4865 title: String,
4866 searchTerm: String
4867 },
4868 observers: [ 'setSearchedTextToBold_(title, searchTerm)' ],
4869 setSearchedTextToBold_: function() {
4870 var i = 0;
4871 var titleText = this.title;
4872 if (this.searchTerm == '' || this.searchTerm == null) {
4873 this.textContent = titleText;
4874 return;
4875 }
4876 var re = new RegExp(quoteString(this.searchTerm), 'gim');
4877 var match;
4878 this.textContent = '';
4879 while (match = re.exec(titleText)) {
4880 if (match.index > i) this.appendChild(document.createTextNode(titleText.sl ice(i, match.index)));
4881 i = re.lastIndex;
4882 var b = document.createElement('b');
4883 b.textContent = titleText.substring(match.index, i);
4884 this.appendChild(b);
4885 }
4886 if (i < titleText.length) this.appendChild(document.createTextNode(titleText .slice(i)));
4887 }
4888 });
4889
8203 // Copyright 2015 The Chromium Authors. All rights reserved. 4890 // Copyright 2015 The Chromium Authors. All rights reserved.
8204 // Use of this source code is governed by a BSD-style license that can be 4891 // Use of this source code is governed by a BSD-style license that can be
4892 // found in the LICENSE file.
4893 function HistoryFocusRow(root, boundary, delegate) {
4894 cr.ui.FocusRow.call(this, root, boundary, delegate);
4895 this.addItems();
4896 }
4897
4898 HistoryFocusRow.prototype = {
4899 __proto__: cr.ui.FocusRow.prototype,
4900 getCustomEquivalent: function(sampleElement) {
4901 var equivalent;
4902 if (this.getTypeForElement(sampleElement) == 'star') equivalent = this.getFi rstFocusable('title');
4903 return equivalent || cr.ui.FocusRow.prototype.getCustomEquivalent.call(this, sampleElement);
4904 },
4905 addItems: function() {
4906 this.destroy();
4907 assert(this.addItem('checkbox', '#checkbox'));
4908 assert(this.addItem('title', '#title'));
4909 assert(this.addItem('menu-button', '#menu-button'));
4910 this.addItem('star', '#bookmark-star');
4911 }
4912 };
4913
4914 cr.define('md_history', function() {
4915 function FocusRowDelegate(historyItemElement) {
4916 this.historyItemElement = historyItemElement;
4917 }
4918 FocusRowDelegate.prototype = {
4919 onFocus: function(row, e) {
4920 this.historyItemElement.lastFocused = e.path[0];
4921 },
4922 onKeydown: function(row, e) {
4923 if (e.key == 'Enter') e.stopPropagation();
4924 return false;
4925 }
4926 };
4927 var HistoryItem = Polymer({
4928 is: 'history-item',
4929 properties: {
4930 item: {
4931 type: Object,
4932 observer: 'showIcon_'
4933 },
4934 searchTerm: {
4935 type: String
4936 },
4937 selected: {
4938 type: Boolean,
4939 reflectToAttribute: true
4940 },
4941 isCardStart: {
4942 type: Boolean,
4943 reflectToAttribute: true
4944 },
4945 isCardEnd: {
4946 type: Boolean,
4947 reflectToAttribute: true
4948 },
4949 embedded: {
4950 type: Boolean,
4951 reflectToAttribute: true
4952 },
4953 hasTimeGap: {
4954 type: Boolean
4955 },
4956 numberOfItems: {
4957 type: Number
4958 },
4959 path: String,
4960 index: Number,
4961 lastFocused: {
4962 type: Object,
4963 notify: true
4964 },
4965 ironListTabIndex: {
4966 type: Number,
4967 observer: 'ironListTabIndexChanged_'
4968 }
4969 },
4970 row_: null,
4971 attached: function() {
4972 Polymer.RenderStatus.afterNextRender(this, function() {
4973 this.row_ = new HistoryFocusRow(this.$['sizing-container'], null, new Fo cusRowDelegate(this));
4974 this.row_.makeActive(this.ironListTabIndex == 0);
4975 this.listen(this, 'focus', 'onFocus_');
4976 this.listen(this, 'dom-change', 'onDomChange_');
4977 });
4978 },
4979 detached: function() {
4980 this.unlisten(this, 'focus', 'onFocus_');
4981 this.unlisten(this, 'dom-change', 'onDomChange_');
4982 if (this.row_) this.row_.destroy();
4983 },
4984 onFocus_: function() {
4985 if (this.lastFocused) this.row_.getEquivalentElement(this.lastFocused).foc us(); else this.row_.getFirstFocusable().focus();
4986 this.tabIndex = -1;
4987 },
4988 ironListTabIndexChanged_: function() {
4989 if (this.row_) this.row_.makeActive(this.ironListTabIndex == 0);
4990 },
4991 onDomChange_: function() {
4992 if (this.row_) this.row_.addItems();
4993 },
4994 onCheckboxSelected_: function(e) {
4995 this.fire('history-checkbox-select', {
4996 element: this,
4997 shiftKey: e.shiftKey
4998 });
4999 e.preventDefault();
5000 },
5001 onCheckboxMousedown_: function(e) {
5002 if (e.shiftKey) e.preventDefault();
5003 },
5004 getEntrySummary_: function() {
5005 var item = this.item;
5006 return loadTimeData.getStringF('entrySummary', item.dateTimeOfDay, item.st arred ? loadTimeData.getString('bookmarked') : '', item.title, item.domain);
5007 },
5008 getAriaChecked_: function(selected) {
5009 return selected ? 'true' : 'false';
5010 },
5011 onRemoveBookmarkTap_: function() {
5012 if (!this.item.starred) return;
5013 if (this.$$('#bookmark-star') == this.root.activeElement) this.$['menu-but ton'].focus();
5014 var browserService = md_history.BrowserService.getInstance();
5015 browserService.removeBookmark(this.item.url);
5016 browserService.recordAction('BookmarkStarClicked');
5017 this.fire('remove-bookmark-stars', this.item.url);
5018 },
5019 onMenuButtonTap_: function(e) {
5020 this.fire('toggle-menu', {
5021 target: Polymer.dom(e).localTarget,
5022 index: this.index,
5023 item: this.item,
5024 path: this.path
5025 });
5026 e.stopPropagation();
5027 },
5028 onLinkClick_: function() {
5029 var browserService = md_history.BrowserService.getInstance();
5030 browserService.recordAction('EntryLinkClick');
5031 if (this.searchTerm) browserService.recordAction('SearchResultClick');
5032 if (this.index == undefined) return;
5033 browserService.recordHistogram('HistoryPage.ClickPosition', this.index, UM A_MAX_BUCKET_VALUE);
5034 if (this.index <= UMA_MAX_SUBSET_BUCKET_VALUE) {
5035 browserService.recordHistogram('HistoryPage.ClickPositionSubset', this.i ndex, UMA_MAX_SUBSET_BUCKET_VALUE);
5036 }
5037 },
5038 onLinkRightClick_: function() {
5039 md_history.BrowserService.getInstance().recordAction('EntryLinkRightClick' );
5040 },
5041 showIcon_: function() {
5042 this.$.icon.style.backgroundImage = cr.icon.getFavicon(this.item.url);
5043 },
5044 selectionNotAllowed_: function() {
5045 return !loadTimeData.getBoolean('allowDeletingHistory');
5046 },
5047 cardTitle_: function(numberOfItems, historyDate, search) {
5048 if (!search) return this.item.dateRelativeDay;
5049 var resultId = numberOfItems == 1 ? 'searchResult' : 'searchResults';
5050 return loadTimeData.getStringF('foundSearchResults', numberOfItems, loadTi meData.getString(resultId), search);
5051 }
5052 });
5053 HistoryItem.needsTimeGap = function(visits, currentIndex, searchedTerm) {
5054 if (currentIndex >= visits.length - 1 || visits.length == 0) return false;
5055 var currentItem = visits[currentIndex];
5056 var nextItem = visits[currentIndex + 1];
5057 if (searchedTerm) return currentItem.dateShort != nextItem.dateShort;
5058 return currentItem.time - nextItem.time > BROWSING_GAP_TIME && currentItem.d ateRelativeDay == nextItem.dateRelativeDay;
5059 };
5060 return {
5061 HistoryItem: HistoryItem
5062 };
5063 });
5064
5065 // Copyright 2016 The Chromium Authors. All rights reserved.
5066 // Use of this source code is governed by a BSD-style license that can be
5067 // found in the LICENSE file.
5068 var SelectionTreeNode = function(currentPath) {
5069 this.currentPath = currentPath;
5070 this.leaf = false;
5071 this.indexes = [];
5072 this.children = [];
5073 };
5074
5075 SelectionTreeNode.prototype.addChild = function(index, path) {
5076 this.indexes.push(index);
5077 this.children[index] = new SelectionTreeNode(path);
5078 };
5079
5080 var HistoryListBehavior = {
5081 properties: {
5082 selectedPaths: {
5083 type: Object,
5084 value: function() {
5085 return new Set();
5086 }
5087 },
5088 lastSelectedPath: String
5089 },
5090 listeners: {
5091 'history-checkbox-select': 'itemSelected_'
5092 },
5093 hasResults: function(historyDataLength) {
5094 return historyDataLength > 0;
5095 },
5096 noResultsMessage: function(searchedTerm, isLoading) {
5097 if (isLoading) return '';
5098 var messageId = searchedTerm !== '' ? 'noSearchResults' : 'noResults';
5099 return loadTimeData.getString(messageId);
5100 },
5101 unselectAllItems: function() {
5102 this.selectedPaths.forEach(function(path) {
5103 this.set(path + '.selected', false);
5104 }.bind(this));
5105 this.selectedPaths.clear();
5106 },
5107 deleteSelected: function() {
5108 var toBeRemoved = Array.from(this.selectedPaths.values()).map(function(path) {
5109 return this.get(path);
5110 }.bind(this));
5111 md_history.BrowserService.getInstance().deleteItems(toBeRemoved).then(functi on() {
5112 this.removeItemsByPath(Array.from(this.selectedPaths));
5113 this.fire('unselect-all');
5114 }.bind(this));
5115 },
5116 removeItemsByPath: function(paths) {
5117 if (paths.length == 0) return;
5118 this.removeItemsBeneathNode_(this.buildRemovalTree_(paths));
5119 },
5120 buildRemovalTree_: function(paths) {
5121 var rootNode = new SelectionTreeNode(paths[0].split('.')[0]);
5122 paths.forEach(function(path) {
5123 var components = path.split('.');
5124 var node = rootNode;
5125 components.shift();
5126 while (components.length > 1) {
5127 var index = Number(components.shift());
5128 var arrayName = components.shift();
5129 if (!node.children[index]) node.addChild(index, [ node.currentPath, inde x, arrayName ].join('.'));
5130 node = node.children[index];
5131 }
5132 node.leaf = true;
5133 node.indexes.push(Number(components.shift()));
5134 });
5135 return rootNode;
5136 },
5137 removeItemsBeneathNode_: function(node) {
5138 var array = this.get(node.currentPath);
5139 var splices = [];
5140 node.indexes.sort(function(a, b) {
5141 return b - a;
5142 });
5143 node.indexes.forEach(function(index) {
5144 if (node.leaf || this.removeItemsBeneathNode_(node.children[index])) {
5145 var item = array.splice(index, 1)[0];
5146 splices.push({
5147 index: index,
5148 removed: [ item ],
5149 addedCount: 0,
5150 object: array,
5151 type: 'splice'
5152 });
5153 }
5154 }.bind(this));
5155 if (array.length == 0 && node.currentPath.indexOf('.') != -1) return true;
5156 this.notifySplices(node.currentPath, splices);
5157 return false;
5158 },
5159 itemSelected_: function(e) {
5160 var item = e.detail.element;
5161 var paths = [];
5162 var itemPath = item.path;
5163 if (e.detail.shiftKey && this.lastSelectedPath) {
5164 var itemPathComponents = itemPath.split('.');
5165 var itemIndex = Number(itemPathComponents.pop());
5166 var itemArrayPath = itemPathComponents.join('.');
5167 var lastItemPathComponents = this.lastSelectedPath.split('.');
5168 var lastItemIndex = Number(lastItemPathComponents.pop());
5169 if (itemArrayPath == lastItemPathComponents.join('.')) {
5170 for (var i = Math.min(itemIndex, lastItemIndex); i <= Math.max(itemIndex , lastItemIndex); i++) {
5171 paths.push(itemArrayPath + '.' + i);
5172 }
5173 }
5174 }
5175 if (paths.length == 0) paths.push(item.path);
5176 var selected = !this.selectedPaths.has(item.path);
5177 paths.forEach(function(path) {
5178 this.set(path + '.selected', selected);
5179 if (selected) {
5180 this.selectedPaths.add(path);
5181 return;
5182 }
5183 this.selectedPaths.delete(path);
5184 }.bind(this));
5185 this.lastSelectedPath = itemPath;
5186 }
5187 };
5188
5189 // Copyright 2015 The Chromium Authors. All rights reserved.
5190 // Use of this source code is governed by a BSD-style license that can be
8205 // found in the LICENSE file. 5191 // found in the LICENSE file.
8206 Polymer({ 5192 Polymer({
8207 is: 'history-list', 5193 is: 'history-list',
8208 behaviors: [ HistoryListBehavior ], 5194 behaviors: [ HistoryListBehavior ],
8209 properties: { 5195 properties: {
8210 searchedTerm: { 5196 searchedTerm: {
8211 type: String, 5197 type: String,
8212 value: '' 5198 value: ''
8213 }, 5199 },
8214 querying: Boolean, 5200 querying: Boolean,
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after
8410 browserService.recordHistogram('HistoryPage.RemoveEntryPositionSubset', index, UMA_MAX_SUBSET_BUCKET_VALUE); 5396 browserService.recordHistogram('HistoryPage.RemoveEntryPositionSubset', index, UMA_MAX_SUBSET_BUCKET_VALUE);
8411 } 5397 }
8412 }.bind(this)); 5398 }.bind(this));
8413 menu.closeMenu(); 5399 menu.closeMenu();
8414 }, 5400 },
8415 getSelectedList_: function() { 5401 getSelectedList_: function() {
8416 return this.$.content.selectedItem; 5402 return this.$.content.selectedItem;
8417 } 5403 }
8418 }); 5404 });
8419 5405
8420 // Copyright 2016 The Chromium Authors. All rights reserved. 5406 Polymer.IronMultiSelectableBehaviorImpl = {
8421 // Use of this source code is governed by a BSD-style license that can be
8422 // found in the LICENSE file.
8423 Polymer({
8424 is: 'history-synced-device-card',
8425 properties: { 5407 properties: {
8426 device: String, 5408 multi: {
8427 lastUpdateTime: String, 5409 type: Boolean,
8428 tabs: { 5410 value: false,
5411 observer: 'multiChanged'
5412 },
5413 selectedValues: {
8429 type: Array, 5414 type: Array,
8430 value: function() { 5415 notify: true
8431 return [];
8432 },
8433 observer: 'updateIcons_'
8434 }, 5416 },
8435 separatorIndexes: Array, 5417 selectedItems: {
8436 opened: Boolean, 5418 type: Array,
8437 searchTerm: String, 5419 readOnly: true,
8438 sessionTag: String 5420 notify: true
5421 }
8439 }, 5422 },
8440 openTab_: function(e) { 5423 observers: [ '_updateSelected(selectedValues.splices)' ],
8441 var tab = e.model.tab; 5424 select: function(value) {
8442 var browserService = md_history.BrowserService.getInstance(); 5425 if (this.multi) {
8443 browserService.recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogr am.LINK_CLICKED, SyncedTabsHistogram.LIMIT); 5426 if (this.selectedValues) {
8444 browserService.openForeignSessionTab(this.sessionTag, tab.windowId, tab.sess ionId, e); 5427 this._toggleSelected(value);
8445 e.preventDefault(); 5428 } else {
5429 this.selectedValues = [ value ];
5430 }
5431 } else {
5432 this.selected = value;
5433 }
8446 }, 5434 },
8447 toggleTabCard: function() { 5435 multiChanged: function(multi) {
8448 var histogramValue = this.$.collapse.opened ? SyncedTabsHistogram.COLLAPSE_S ESSION : SyncedTabsHistogram.EXPAND_SESSION; 5436 this._selection.multi = multi;
8449 md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRA M_NAME, histogramValue, SyncedTabsHistogram.LIMIT);
8450 this.$.collapse.toggle();
8451 this.$['dropdown-indicator'].icon = this.$.collapse.opened ? 'cr:expand-less ' : 'cr:expand-more';
8452 }, 5437 },
8453 updateIcons_: function() { 5438 get _shouldUpdateSelection() {
8454 this.async(function() { 5439 return this.selected != null || this.selectedValues != null && this.selected Values.length;
8455 var icons = Polymer.dom(this.root).querySelectorAll('.website-icon'); 5440 },
8456 for (var i = 0; i < this.tabs.length; i++) { 5441 _updateAttrForSelected: function() {
8457 icons[i].style.backgroundImage = cr.icon.getFavicon(this.tabs[i].url); 5442 if (!this.multi) {
5443 Polymer.IronSelectableBehavior._updateAttrForSelected.apply(this);
5444 } else if (this._shouldUpdateSelection) {
5445 this.selectedValues = this.selectedItems.map(function(selectedItem) {
5446 return this._indexToValue(this.indexOf(selectedItem));
5447 }, this).filter(function(unfilteredValue) {
5448 return unfilteredValue != null;
5449 }, this);
5450 }
5451 },
5452 _updateSelected: function() {
5453 if (this.multi) {
5454 this._selectMulti(this.selectedValues);
5455 } else {
5456 this._selectSelected(this.selected);
5457 }
5458 },
5459 _selectMulti: function(values) {
5460 if (values) {
5461 var selectedItems = this._valuesToItems(values);
5462 this._selection.clear(selectedItems);
5463 for (var i = 0; i < selectedItems.length; i++) {
5464 this._selection.setItemSelected(selectedItems[i], true);
8458 } 5465 }
8459 }); 5466 if (this.fallbackSelection && this.items.length && !this._selection.get(). length) {
8460 }, 5467 var fallback = this._valueToItem(this.fallbackSelection);
8461 isWindowSeparatorIndex_: function(index, separatorIndexes) { 5468 if (fallback) {
8462 return this.separatorIndexes.indexOf(index) != -1; 5469 this.selectedValues = [ this.fallbackSelection ];
8463 },
8464 getCollapseIcon_: function(opened) {
8465 return opened ? 'cr:expand-less' : 'cr:expand-more';
8466 },
8467 getCollapseTitle_: function(opened) {
8468 return opened ? loadTimeData.getString('collapseSessionButton') : loadTimeDa ta.getString('expandSessionButton');
8469 },
8470 onMenuButtonTap_: function(e) {
8471 this.fire('toggle-menu', {
8472 target: Polymer.dom(e).localTarget,
8473 tag: this.sessionTag
8474 });
8475 e.stopPropagation();
8476 },
8477 onLinkRightClick_: function() {
8478 md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRA M_NAME, SyncedTabsHistogram.LINK_RIGHT_CLICKED, SyncedTabsHistogram.LIMIT);
8479 }
8480 });
8481
8482 // Copyright 2016 The Chromium Authors. All rights reserved.
8483 // Use of this source code is governed by a BSD-style license that can be
8484 // found in the LICENSE file.
8485 var ForeignDeviceInternal;
8486
8487 Polymer({
8488 is: 'history-synced-device-manager',
8489 properties: {
8490 sessionList: {
8491 type: Array,
8492 observer: 'updateSyncedDevices'
8493 },
8494 searchTerm: {
8495 type: String,
8496 observer: 'searchTermChanged'
8497 },
8498 syncedDevices_: {
8499 type: Array,
8500 value: function() {
8501 return [];
8502 }
8503 },
8504 signInState: {
8505 type: Boolean,
8506 observer: 'signInStateChanged_'
8507 },
8508 guestSession_: {
8509 type: Boolean,
8510 value: loadTimeData.getBoolean('isGuestSession')
8511 },
8512 fetchingSyncedTabs_: {
8513 type: Boolean,
8514 value: false
8515 },
8516 hasSeenForeignData_: Boolean
8517 },
8518 listeners: {
8519 'toggle-menu': 'onToggleMenu_',
8520 scroll: 'onListScroll_'
8521 },
8522 attached: function() {
8523 chrome.send('otherDevicesInitialized');
8524 md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRA M_NAME, SyncedTabsHistogram.INITIALIZED, SyncedTabsHistogram.LIMIT);
8525 },
8526 getContentScrollTarget: function() {
8527 return this;
8528 },
8529 createInternalDevice_: function(session) {
8530 var tabs = [];
8531 var separatorIndexes = [];
8532 for (var i = 0; i < session.windows.length; i++) {
8533 var windowId = session.windows[i].sessionId;
8534 var newTabs = session.windows[i].tabs;
8535 if (newTabs.length == 0) continue;
8536 newTabs.forEach(function(tab) {
8537 tab.windowId = windowId;
8538 });
8539 var windowAdded = false;
8540 if (!this.searchTerm) {
8541 tabs = tabs.concat(newTabs);
8542 windowAdded = true;
8543 } else {
8544 var searchText = this.searchTerm.toLowerCase();
8545 for (var j = 0; j < newTabs.length; j++) {
8546 var tab = newTabs[j];
8547 if (tab.title.toLowerCase().indexOf(searchText) != -1) {
8548 tabs.push(tab);
8549 windowAdded = true;
8550 }
8551 } 5470 }
8552 } 5471 }
8553 if (windowAdded && i != session.windows.length - 1) separatorIndexes.push( tabs.length - 1); 5472 } else {
8554 } 5473 this._selection.clear();
8555 return {
8556 device: session.name,
8557 lastUpdateTime: '– ' + session.modifiedTime,
8558 opened: true,
8559 separatorIndexes: separatorIndexes,
8560 timestamp: session.timestamp,
8561 tabs: tabs,
8562 tag: session.tag
8563 };
8564 },
8565 onSignInTap_: function() {
8566 chrome.send('startSignInFlow');
8567 },
8568 onListScroll_: function() {
8569 var menu = this.$.menu.getIfExists();
8570 if (menu) menu.closeMenu();
8571 },
8572 onToggleMenu_: function(e) {
8573 var menu = this.$.menu.get();
8574 menu.toggleMenu(e.detail.target, e.detail.tag);
8575 if (menu.menuOpen) {
8576 md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOG RAM_NAME, SyncedTabsHistogram.SHOW_SESSION_MENU, SyncedTabsHistogram.LIMIT);
8577 } 5474 }
8578 }, 5475 },
8579 onOpenAllTap_: function() { 5476 _selectionChange: function() {
8580 var menu = assert(this.$.menu.getIfExists()); 5477 var s = this._selection.get();
8581 var browserService = md_history.BrowserService.getInstance(); 5478 if (this.multi) {
8582 browserService.recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogr am.OPEN_ALL, SyncedTabsHistogram.LIMIT); 5479 this._setSelectedItems(s);
8583 browserService.openForeignSessionAllTabs(menu.itemData);
8584 menu.closeMenu();
8585 },
8586 onDeleteSessionTap_: function() {
8587 var menu = assert(this.$.menu.getIfExists());
8588 var browserService = md_history.BrowserService.getInstance();
8589 browserService.recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogr am.HIDE_FOR_NOW, SyncedTabsHistogram.LIMIT);
8590 browserService.deleteForeignSession(menu.itemData);
8591 menu.closeMenu();
8592 },
8593 clearDisplayedSyncedDevices_: function() {
8594 this.syncedDevices_ = [];
8595 },
8596 showNoSyncedMessage: function(signInState, syncedDevicesLength, guestSession) {
8597 if (guestSession) return true;
8598 return signInState && syncedDevicesLength == 0;
8599 },
8600 showSignInGuide: function(signInState, guestSession) {
8601 var show = !signInState && !guestSession;
8602 if (show) {
8603 md_history.BrowserService.getInstance().recordAction('Signin_Impression_Fr omRecentTabs');
8604 }
8605 return show;
8606 },
8607 noSyncedTabsMessage: function(fetchingSyncedTabs) {
8608 return loadTimeData.getString(fetchingSyncedTabs ? 'loading' : 'noSyncedResu lts');
8609 },
8610 updateSyncedDevices: function(sessionList) {
8611 this.fetchingSyncedTabs_ = false;
8612 if (!sessionList) return;
8613 if (sessionList.length > 0 && !this.hasSeenForeignData_) {
8614 this.hasSeenForeignData_ = true;
8615 md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOG RAM_NAME, SyncedTabsHistogram.HAS_FOREIGN_DATA, SyncedTabsHistogram.LIMIT);
8616 }
8617 var updateCount = Math.min(sessionList.length, this.syncedDevices_.length);
8618 for (var i = 0; i < updateCount; i++) {
8619 var oldDevice = this.syncedDevices_[i];
8620 if (oldDevice.tag != sessionList[i].tag || oldDevice.timestamp != sessionL ist[i].timestamp) {
8621 this.splice('syncedDevices_', i, 1, this.createInternalDevice_(sessionLi st[i]));
8622 }
8623 }
8624 if (sessionList.length >= this.syncedDevices_.length) {
8625 for (var i = updateCount; i < sessionList.length; i++) {
8626 this.push('syncedDevices_', this.createInternalDevice_(sessionList[i]));
8627 }
8628 } else { 5480 } else {
8629 this.splice('syncedDevices_', updateCount, this.syncedDevices_.length - up dateCount); 5481 this._setSelectedItems([ s ]);
5482 this._setSelectedItem(s);
8630 } 5483 }
8631 }, 5484 },
8632 tabSyncDisabled: function() { 5485 _toggleSelected: function(value) {
8633 this.fetchingSyncedTabs_ = false; 5486 var i = this.selectedValues.indexOf(value);
8634 this.clearDisplayedSyncedDevices_(); 5487 var unselected = i < 0;
5488 if (unselected) {
5489 this.push('selectedValues', value);
5490 } else {
5491 this.splice('selectedValues', i, 1);
5492 }
8635 }, 5493 },
8636 signInStateChanged_: function() { 5494 _valuesToItems: function(values) {
8637 this.fire('history-view-changed'); 5495 return values == null ? null : values.map(function(value) {
8638 if (!this.signInState) { 5496 return this._valueToItem(value);
8639 this.clearDisplayedSyncedDevices_(); 5497 }, this);
8640 return;
8641 }
8642 this.fetchingSyncedTabs_ = true;
8643 },
8644 searchTermChanged: function(searchTerm) {
8645 this.clearDisplayedSyncedDevices_();
8646 this.updateSyncedDevices(this.sessionList);
8647 } 5498 }
8648 }); 5499 };
5500
5501 Polymer.IronMultiSelectableBehavior = [ Polymer.IronSelectableBehavior, Polymer. IronMultiSelectableBehaviorImpl ];
8649 5502
8650 Polymer({ 5503 Polymer({
8651 is: 'iron-selector', 5504 is: 'iron-selector',
8652 behaviors: [ Polymer.IronMultiSelectableBehavior ] 5505 behaviors: [ Polymer.IronMultiSelectableBehavior ]
8653 }); 5506 });
8654 5507
8655 // Copyright 2016 The Chromium Authors. All rights reserved. 5508 // Copyright 2016 The Chromium Authors. All rights reserved.
8656 // Use of this source code is governed by a BSD-style license that can be 5509 // Use of this source code is governed by a BSD-style license that can be
8657 // found in the LICENSE file. 5510 // found in the LICENSE file.
8658 Polymer({ 5511 Polymer({
(...skipping 28 matching lines...) Expand all
8687 e.preventDefault(); 5540 e.preventDefault();
8688 }, 5541 },
8689 getQueryString_: function(route) { 5542 getQueryString_: function(route) {
8690 return window.location.search; 5543 return window.location.search;
8691 } 5544 }
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.
5550 cr.define('md_history', function() {
5551 var lazyLoadPromise = null;
5552 function ensureLazyLoaded() {
5553 if (!lazyLoadPromise) {
5554 lazyLoadPromise = new Promise(function(resolve, reject) {
5555 Polymer.Base.importHref('chrome://history/lazy_load.html', resolve, reje ct, true);
5556 });
5557 }
5558 return lazyLoadPromise;
5559 }
5560 return {
5561 ensureLazyLoaded: ensureLazyLoaded
5562 };
5563 });
5564
8697 Polymer({ 5565 Polymer({
8698 is: 'history-app', 5566 is: 'history-app',
8699 behaviors: [ Polymer.IronScrollTargetBehavior ], 5567 behaviors: [ Polymer.IronScrollTargetBehavior ],
8700 properties: { 5568 properties: {
8701 showSidebarFooter: Boolean, 5569 showSidebarFooter: Boolean,
8702 hasSyncedResults: Boolean, 5570 hasSyncedResults: Boolean,
8703 selectedPage_: { 5571 selectedPage_: {
8704 type: String, 5572 type: String,
8705 observer: 'unselectAll' 5573 observer: 'unselectAll'
8706 }, 5574 },
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
8769 window.location.href = window.location.href.split('#')[0] + '?' + window.l ocation.hash.substr(1); 5637 window.location.href = window.location.href.split('#')[0] + '?' + window.l ocation.hash.substr(1);
8770 } 5638 }
8771 }, 5639 },
8772 onFirstRender: function() { 5640 onFirstRender: function() {
8773 requestAnimationFrame(function() { 5641 requestAnimationFrame(function() {
8774 chrome.send('metricsHandler:recordTime', [ 'History.ResultsRenderedTime', window.performance.now() ]); 5642 chrome.send('metricsHandler:recordTime', [ 'History.ResultsRenderedTime', window.performance.now() ]);
8775 }); 5643 });
8776 if (!this.hasDrawer_) { 5644 if (!this.hasDrawer_) {
8777 this.focusToolbarSearchField(); 5645 this.focusToolbarSearchField();
8778 } 5646 }
5647 md_history.ensureLazyLoaded();
8779 }, 5648 },
8780 _scrollHandler: function() { 5649 _scrollHandler: function() {
8781 this.toolbarShadow_ = this.scrollTarget.scrollTop != 0; 5650 this.toolbarShadow_ = this.scrollTarget.scrollTop != 0;
8782 }, 5651 },
8783 onMenuTap_: function() { 5652 onMenuTap_: function() {
8784 var drawer = this.$$('#drawer'); 5653 var drawer = this.$$('#drawer');
8785 if (drawer) drawer.toggle(); 5654 if (drawer) drawer.toggle();
8786 }, 5655 },
8787 checkboxSelected: function(e) { 5656 checkboxSelected: function(e) {
8788 var toolbar = this.$.toolbar; 5657 var toolbar = this.$.toolbar;
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
8901 5770
8902 case HistoryRange.MONTH: 5771 case HistoryRange.MONTH:
8903 histogramValue = HistoryPageViewHistogram.GROUPED_MONTH; 5772 histogramValue = HistoryPageViewHistogram.GROUPED_MONTH;
8904 break; 5773 break;
8905 } 5774 }
8906 break; 5775 break;
8907 } 5776 }
8908 md_history.BrowserService.getInstance().recordHistogram('History.HistoryPage View', histogramValue, HistoryPageViewHistogram.END); 5777 md_history.BrowserService.getInstance().recordHistogram('History.HistoryPage View', histogramValue, HistoryPageViewHistogram.END);
8909 } 5778 }
8910 }); 5779 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698