| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 /** Same as paper-menu-button's custom easing cubic-bezier param. */ | |
| 6 var SLIDE_CUBIC_BEZIER = 'cubic-bezier(0.3, 0.95, 0.5, 1)'; | |
| 7 | |
| 8 Polymer({ | |
| 9 is: 'cr-shared-menu', | |
| 10 | |
| 11 properties: { | |
| 12 menuOpen: { | |
| 13 type: Boolean, | |
| 14 observer: 'menuOpenChanged_', | |
| 15 value: false, | |
| 16 notify: true, | |
| 17 }, | |
| 18 | |
| 19 /** | |
| 20 * The contextual item that this menu was clicked for, e.g. the data used to | |
| 21 * render an item in an <iron-list> or <dom-repeat>. | |
| 22 * @type {?Object} | |
| 23 */ | |
| 24 itemData: { | |
| 25 type: Object, | |
| 26 value: null, | |
| 27 }, | |
| 28 | |
| 29 openAnimationConfig: { | |
| 30 type: Object, | |
| 31 value: function() { | |
| 32 return [{ | |
| 33 name: 'fade-in-animation', | |
| 34 timing: { | |
| 35 delay: 50, | |
| 36 duration: 200 | |
| 37 } | |
| 38 }, { | |
| 39 name: 'paper-menu-grow-width-animation', | |
| 40 timing: { | |
| 41 delay: 50, | |
| 42 duration: 150, | |
| 43 easing: SLIDE_CUBIC_BEZIER | |
| 44 } | |
| 45 }, { | |
| 46 name: 'paper-menu-grow-height-animation', | |
| 47 timing: { | |
| 48 delay: 100, | |
| 49 duration: 275, | |
| 50 easing: SLIDE_CUBIC_BEZIER | |
| 51 } | |
| 52 }]; | |
| 53 } | |
| 54 }, | |
| 55 | |
| 56 closeAnimationConfig: { | |
| 57 type: Object, | |
| 58 value: function() { | |
| 59 return [{ | |
| 60 name: 'fade-out-animation', | |
| 61 timing: { | |
| 62 duration: 150 | |
| 63 } | |
| 64 }]; | |
| 65 } | |
| 66 } | |
| 67 }, | |
| 68 | |
| 69 listeners: { | |
| 70 'dropdown.iron-overlay-canceled': 'onOverlayCanceled_', | |
| 71 }, | |
| 72 | |
| 73 /** | |
| 74 * The last anchor that was used to open a menu. It's necessary for toggling. | |
| 75 * @private {?Element} | |
| 76 */ | |
| 77 lastAnchor_: null, | |
| 78 | |
| 79 /** @private {?function(!Event)} */ | |
| 80 keyHandler_: null, | |
| 81 | |
| 82 /** @override */ | |
| 83 attached: function() { | |
| 84 window.addEventListener('resize', this.closeMenu.bind(this)); | |
| 85 this.keyHandler_ = this.onCaptureKeyDown_.bind(this); | |
| 86 this.$.menu.addEventListener('keydown', this.keyHandler_, true); | |
| 87 }, | |
| 88 | |
| 89 /** @override */ | |
| 90 detached: function() { | |
| 91 this.$.menu.removeEventListener('keydown', this.keyHandler_, true); | |
| 92 }, | |
| 93 | |
| 94 /** Closes the menu. */ | |
| 95 closeMenu: function() { | |
| 96 if (this.root.activeElement == null) { | |
| 97 // Something else has taken focus away from the menu. Do not attempt to | |
| 98 // restore focus to the button which opened the menu. | |
| 99 this.$.dropdown.restoreFocusOnClose = false; | |
| 100 } | |
| 101 this.menuOpen = false; | |
| 102 }, | |
| 103 | |
| 104 /** | |
| 105 * Opens the menu at the anchor location. | |
| 106 * @param {!Element} anchor The location to display the menu. | |
| 107 * @param {!Object=} opt_itemData The contextual item's data. | |
| 108 */ | |
| 109 openMenu: function(anchor, opt_itemData) { | |
| 110 if (this.lastAnchor_ == anchor && this.menuOpen) | |
| 111 return; | |
| 112 | |
| 113 if (this.menuOpen) | |
| 114 this.closeMenu(); | |
| 115 | |
| 116 this.itemData = opt_itemData || null; | |
| 117 this.lastAnchor_ = anchor; | |
| 118 this.$.dropdown.restoreFocusOnClose = true; | |
| 119 this.$.menu.selected = -1; | |
| 120 | |
| 121 // Move the menu to the anchor. | |
| 122 this.$.dropdown.positionTarget = anchor; | |
| 123 this.menuOpen = true; | |
| 124 }, | |
| 125 | |
| 126 /** | |
| 127 * Toggles the menu for the anchor that is passed in. | |
| 128 * @param {!Element} anchor The location to display the menu. | |
| 129 * @param {!Object=} opt_itemData The contextual item's data. | |
| 130 */ | |
| 131 toggleMenu: function(anchor, opt_itemData) { | |
| 132 if (anchor == this.lastAnchor_ && this.menuOpen) | |
| 133 this.closeMenu(); | |
| 134 else | |
| 135 this.openMenu(anchor, opt_itemData); | |
| 136 }, | |
| 137 | |
| 138 /** | |
| 139 * Close the menu when tab is pressed. Note that we must | |
| 140 * explicitly add a capture event listener to do this as iron-menu-behavior | |
| 141 * eats all key events during bubbling. See | |
| 142 * https://github.com/PolymerElements/iron-menu-behavior/issues/56. | |
| 143 * This will move focus to the next focusable element before/after the | |
| 144 * anchor. | |
| 145 * @private | |
| 146 */ | |
| 147 onCaptureKeyDown_: function(e) { | |
| 148 if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(e, 'tab')) { | |
| 149 // Need to refocus the anchor synchronously so that the tab event takes | |
| 150 // effect on it. | |
| 151 this.$.dropdown.restoreFocusOnClose = false; | |
| 152 this.lastAnchor_.focus(); | |
| 153 this.closeMenu(); | |
| 154 } | |
| 155 }, | |
| 156 | |
| 157 /** | |
| 158 * Ensure the menu is reset properly when it is closed by the dropdown (eg, | |
| 159 * clicking outside). | |
| 160 * @private | |
| 161 */ | |
| 162 menuOpenChanged_: function() { | |
| 163 if (!this.menuOpen) { | |
| 164 this.itemData = null; | |
| 165 this.lastAnchor_ = null; | |
| 166 } | |
| 167 }, | |
| 168 | |
| 169 /** | |
| 170 * Prevent focus restoring when tapping outside the menu. This stops the | |
| 171 * focus moving around unexpectedly when closing the menu with the mouse. | |
| 172 * @param {CustomEvent} e | |
| 173 * @private | |
| 174 */ | |
| 175 onOverlayCanceled_: function(e) { | |
| 176 if (e.detail.type == 'tap') | |
| 177 this.$.dropdown.restoreFocusOnClose = false; | |
| 178 }, | |
| 179 }); | |
| OLD | NEW |