Chromium Code Reviews| 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: 'settings-action-menu', | 6 is: 'settings-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 * Index of the currently focused item. | |
| 17 * @private {number} | |
| 18 */ | |
| 19 focusedIndex_: -1, | |
| 20 | |
| 21 /** | |
| 22 * Reference to the bound window's resize listener, such that it can be | 16 * Reference to the bound window's resize listener, such that it can be |
| 23 * removed on detach. | 17 * removed on detach. |
| 24 * @private {?Function} | 18 * @private {?Function} |
| 25 */ | 19 */ |
| 26 onWindowResize_: null, | 20 onWindowResize_: null, |
| 27 | 21 |
| 28 hostAttributes: { | 22 hostAttributes: { |
| 29 tabindex: 0, | 23 tabindex: 0, |
| 30 }, | 24 }, |
| 31 | 25 |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 87 * disabled/hidden attributes, or null if no focusable option exists. | 81 * disabled/hidden attributes, or null if no focusable option exists. |
| 88 * @private | 82 * @private |
| 89 */ | 83 */ |
| 90 getNextOption_: function(step) { | 84 getNextOption_: function(step) { |
| 91 // Using a counter to ensure no infinite loop occurs if all elements are | 85 // Using a counter to ensure no infinite loop occurs if all elements are |
| 92 // hidden/disabled. | 86 // hidden/disabled. |
| 93 var counter = 0; | 87 var counter = 0; |
| 94 var nextOption = null; | 88 var nextOption = null; |
| 95 var numOptions = this.options_.length; | 89 var numOptions = this.options_.length; |
| 96 | 90 |
| 91 // Using |call| to call indexOf on a NodeList, without converting it to an | |
| 92 // Array. | |
|
Dan Beam
2016/10/25 00:56:10
don't really think this is a useful comment
dpapad
2016/10/25 01:27:51
Removed.
| |
| 93 var focusedIndex = Array.prototype.indexOf.call( | |
| 94 this.options_, this.root.activeElement); | |
| 95 | |
| 97 do { | 96 do { |
| 98 this.focusedIndex_ = | 97 focusedIndex = (numOptions + focusedIndex + step) % numOptions; |
| 99 (numOptions + this.focusedIndex_ + step) % numOptions; | 98 nextOption = this.options_[focusedIndex]; |
| 100 nextOption = this.options_[this.focusedIndex_]; | |
| 101 if (nextOption.disabled || nextOption.hidden) | 99 if (nextOption.disabled || nextOption.hidden) |
| 102 nextOption = null; | 100 nextOption = null; |
| 103 counter++; | 101 counter++; |
| 104 } while (!nextOption && counter < numOptions); | 102 } while (!nextOption && counter < numOptions); |
| 105 | 103 |
| 106 return nextOption; | 104 return nextOption; |
| 107 }, | 105 }, |
| 108 | 106 |
| 109 /** @override */ | 107 /** @override */ |
| 110 close: function() { | 108 close: function() { |
| 111 // Removing 'resize' listener when dialog is closed. | 109 // Removing 'resize' listener when dialog is closed. |
| 112 this.removeResizeListener_(); | 110 this.removeResizeListener_(); |
| 113 HTMLDialogElement.prototype.close.call(this); | 111 HTMLDialogElement.prototype.close.call(this); |
| 114 window.dispatchEvent(new CustomEvent('resize')); | 112 window.dispatchEvent(new CustomEvent('resize')); |
| 115 }, | 113 }, |
| 116 | 114 |
| 117 /** | 115 /** |
| 118 * Shows the menu anchored to the given element. | 116 * Shows the menu anchored to the given element. |
| 119 * @param {!Element} anchorElement | 117 * @param {!Element} anchorElement |
| 120 */ | 118 */ |
| 121 showAt: function(anchorElement) { | 119 showAt: function(anchorElement) { |
| 122 var rect = anchorElement.getBoundingClientRect(); | |
| 123 | |
| 124 // Ensure that the correct item is focused when the dialog is shown, by | |
| 125 // setting the 'autofocus' attribute. | |
| 126 this.focusedIndex_ = -1; | |
| 127 var nextOption = this.getNextOption_(1); | |
| 128 | |
| 129 /** @suppress {checkTypes} */ | |
| 130 (function(options) { | |
| 131 options.forEach(function(option) { | |
| 132 option.removeAttribute('autofocus'); | |
| 133 }); | |
| 134 })(this.options_); | |
| 135 | |
| 136 if (nextOption) | |
| 137 nextOption.setAttribute('autofocus', true); | |
| 138 | |
| 139 this.onWindowResize_ = this.onWindowResize_ || function() { | 120 this.onWindowResize_ = this.onWindowResize_ || function() { |
| 140 if (this.open) | 121 if (this.open) |
| 141 this.close(); | 122 this.close(); |
| 142 }.bind(this); | 123 }.bind(this); |
| 143 window.addEventListener('resize', this.onWindowResize_); | 124 window.addEventListener('resize', this.onWindowResize_); |
| 144 | 125 |
| 145 this.showModal(); | 126 this.showModal(); |
| 146 | 127 |
| 128 var rect = anchorElement.getBoundingClientRect(); | |
| 147 if (new settings.DirectionDelegateImpl().isRtl()) { | 129 if (new settings.DirectionDelegateImpl().isRtl()) { |
| 148 var right = window.innerWidth - rect.left - this.offsetWidth; | 130 var right = window.innerWidth - rect.left - this.offsetWidth; |
| 149 this.style.right = right + 'px'; | 131 this.style.right = right + 'px'; |
| 150 } else { | 132 } else { |
| 151 var left = rect.right - this.offsetWidth; | 133 var left = rect.right - this.offsetWidth; |
| 152 this.style.left = left + 'px'; | 134 this.style.left = left + 'px'; |
| 153 } | 135 } |
| 154 | 136 |
| 155 // Attempt to show the menu starting from the top of the rectangle and | 137 // Attempt to show the menu starting from the top of the rectangle and |
| 156 // extending downwards. If that does not fit within the window, fallback to | 138 // extending downwards. If that does not fit within the window, fallback to |
| 157 // starting from the bottom and extending upwards. | 139 // starting from the bottom and extending upwards. |
| 158 var top = rect.top + this.offsetHeight <= window.innerHeight ? | 140 var top = rect.top + this.offsetHeight <= window.innerHeight ? |
| 159 rect.top : | 141 rect.top : |
| 160 rect.bottom - this.offsetHeight - Math.max( | 142 rect.bottom - this.offsetHeight - Math.max( |
| 161 rect.bottom - window.innerHeight, 0); | 143 rect.bottom - window.innerHeight, 0); |
| 162 | 144 |
| 163 this.style.top = top + 'px'; | 145 this.style.top = top + 'px'; |
| 164 }, | 146 }, |
| 165 }); | 147 }); |
| OLD | NEW |