| OLD | NEW |
| 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 | 4 |
| 5 Polymer({ | 5 Polymer({ |
| 6 is: 'cr-action-menu', | 6 is: 'cr-action-menu', |
| 7 extends: 'dialog', | 7 extends: 'dialog', |
| 8 | 8 |
| 9 /** | 9 /** |
| 10 * List of all options in this action menu. | 10 * List of all options in this action menu. |
| 11 * @private {?NodeList<!Element>} | 11 * @private {?NodeList<!Element>} |
| 12 */ | 12 */ |
| 13 options_: null, | 13 options_: null, |
| 14 | 14 |
| 15 /** | 15 /** |
| 16 * The element which the action menu will be anchored to. Also the element | 16 * The element which the action menu will be anchored to. Also the element |
| 17 * where focus will be returned after the menu is closed. | 17 * where focus will be returned after the menu is closed. |
| 18 * @private {?Element} | 18 * @private {?Element} |
| 19 */ | 19 */ |
| 20 anchorElement_: null, | 20 anchorElement_: null, |
| 21 | 21 |
| 22 /** | 22 /** |
| 23 * Reference to the bound window's resize listener, such that it can be | 23 * Bound reference to an event listener function such that it can be removed |
| 24 * removed on detach. | 24 * on detach. |
| 25 * @private {?Function} | 25 * @private {?Function} |
| 26 */ | 26 */ |
| 27 onWindowResize_: null, | 27 boundClose_: null, |
| 28 | 28 |
| 29 hostAttributes: { | 29 hostAttributes: { |
| 30 tabindex: 0, | 30 tabindex: 0, |
| 31 }, | 31 }, |
| 32 | 32 |
| 33 listeners: { | 33 listeners: { |
| 34 'keydown': 'onKeyDown_', | 34 'keydown': 'onKeyDown_', |
| 35 'tap': 'onTap_', | 35 'tap': 'onTap_', |
| 36 }, | 36 }, |
| 37 | 37 |
| 38 /** override */ | 38 /** override */ |
| 39 attached: function() { | 39 attached: function() { |
| 40 this.options_ = this.querySelectorAll('.dropdown-item'); | 40 this.options_ = this.querySelectorAll('.dropdown-item'); |
| 41 }, | 41 }, |
| 42 | 42 |
| 43 /** override */ | 43 /** override */ |
| 44 detached: function() { | 44 detached: function() { |
| 45 this.removeResizeListener_(); | 45 this.removeListeners_(); |
| 46 }, | 46 }, |
| 47 | 47 |
| 48 /** @private */ | 48 /** @private */ |
| 49 removeResizeListener_: function() { | 49 removeListeners_: function() { |
| 50 window.removeEventListener('resize', this.onWindowResize_); | 50 window.removeEventListener('resize', this.boundClose_); |
| 51 window.removeEventListener('popstate', this.boundClose_); |
| 51 }, | 52 }, |
| 52 | 53 |
| 53 /** | 54 /** |
| 54 * @param {!Event} e | 55 * @param {!Event} e |
| 55 * @private | 56 * @private |
| 56 */ | 57 */ |
| 57 onTap_: function(e) { | 58 onTap_: function(e) { |
| 58 if (e.target == this) { | 59 if (e.target == this) { |
| 59 this.close(); | 60 this.close(); |
| 60 e.stopPropagation(); | 61 e.stopPropagation(); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 104 if (nextOption.disabled || nextOption.hidden) | 105 if (nextOption.disabled || nextOption.hidden) |
| 105 nextOption = null; | 106 nextOption = null; |
| 106 counter++; | 107 counter++; |
| 107 } while (!nextOption && counter < numOptions); | 108 } while (!nextOption && counter < numOptions); |
| 108 | 109 |
| 109 return nextOption; | 110 return nextOption; |
| 110 }, | 111 }, |
| 111 | 112 |
| 112 /** @override */ | 113 /** @override */ |
| 113 close: function() { | 114 close: function() { |
| 114 // Removing 'resize' listener when dialog is closed. | 115 // Removing 'resize' and 'popstate' listeners when dialog is closed. |
| 115 this.removeResizeListener_(); | 116 this.removeListeners_(); |
| 116 HTMLDialogElement.prototype.close.call(this); | 117 HTMLDialogElement.prototype.close.call(this); |
| 117 this.anchorElement_.focus(); | 118 this.anchorElement_.focus(); |
| 118 this.anchorElement_ = null; | 119 this.anchorElement_ = null; |
| 119 }, | 120 }, |
| 120 | 121 |
| 121 /** | 122 /** |
| 122 * Shows the menu anchored to the given element. | 123 * Shows the menu anchored to the given element. |
| 123 * @param {!Element} anchorElement | 124 * @param {!Element} anchorElement |
| 124 */ | 125 */ |
| 125 showAt: function(anchorElement) { | 126 showAt: function(anchorElement) { |
| 126 this.anchorElement_ = anchorElement; | 127 this.anchorElement_ = anchorElement; |
| 127 this.onWindowResize_ = this.onWindowResize_ || function() { | 128 this.boundClose_ = this.boundClose_ || function() { |
| 128 if (this.open) | 129 if (this.open) |
| 129 this.close(); | 130 this.close(); |
| 130 }.bind(this); | 131 }.bind(this); |
| 131 window.addEventListener('resize', this.onWindowResize_); | 132 window.addEventListener('resize', this.boundClose_); |
| 133 window.addEventListener('popstate', this.boundClose_); |
| 132 | 134 |
| 133 // Reset position to prevent previous values from affecting layout. | 135 // Reset position to prevent previous values from affecting layout. |
| 134 this.style.left = ''; | 136 this.style.left = ''; |
| 135 this.style.right = ''; | 137 this.style.right = ''; |
| 136 this.style.top = ''; | 138 this.style.top = ''; |
| 137 | 139 |
| 138 this.showModal(); | 140 this.showModal(); |
| 139 | 141 |
| 140 var rect = this.anchorElement_.getBoundingClientRect(); | 142 var rect = this.anchorElement_.getBoundingClientRect(); |
| 141 if (getComputedStyle(this.anchorElement_).direction == 'rtl') { | 143 if (getComputedStyle(this.anchorElement_).direction == 'rtl') { |
| 142 var right = window.innerWidth - rect.left - this.offsetWidth; | 144 var right = window.innerWidth - rect.left - this.offsetWidth; |
| 143 this.style.right = right + 'px'; | 145 this.style.right = right + 'px'; |
| 144 } else { | 146 } else { |
| 145 var left = rect.right - this.offsetWidth; | 147 var left = rect.right - this.offsetWidth; |
| 146 this.style.left = left + 'px'; | 148 this.style.left = left + 'px'; |
| 147 } | 149 } |
| 148 | 150 |
| 149 // Attempt to show the menu starting from the top of the rectangle and | 151 // Attempt to show the menu starting from the top of the rectangle and |
| 150 // extending downwards. If that does not fit within the window, fallback to | 152 // extending downwards. If that does not fit within the window, fallback to |
| 151 // starting from the bottom and extending upwards. | 153 // starting from the bottom and extending upwards. |
| 152 var top = rect.top + this.offsetHeight <= window.innerHeight ? rect.top : | 154 var top = rect.top + this.offsetHeight <= window.innerHeight ? rect.top : |
| 153 rect.bottom - | 155 rect.bottom - |
| 154 this.offsetHeight - Math.max(rect.bottom - window.innerHeight, 0); | 156 this.offsetHeight - Math.max(rect.bottom - window.innerHeight, 0); |
| 155 | 157 |
| 156 this.style.top = top + 'px'; | 158 this.style.top = top + 'px'; |
| 157 }, | 159 }, |
| 158 }); | 160 }); |
| OLD | NEW |