| 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. |
| (...skipping 23 matching lines...) Expand all Loading... |
| 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() { this.removeResizeListener_(); }, |
| 45 this.removeResizeListener_(); | |
| 46 }, | |
| 47 | 45 |
| 48 /** @private */ | 46 /** @private */ |
| 49 removeResizeListener_: function() { | 47 removeResizeListener_: function() { |
| 50 window.removeEventListener('resize', this.onWindowResize_); | 48 window.removeEventListener('resize', this.onWindowResize_); |
| 51 }, | 49 }, |
| 52 | 50 |
| 53 /** | 51 /** |
| 54 * @param {!Event} e | 52 * @param {!Event} e |
| 55 * @private | 53 * @private |
| 56 */ | 54 */ |
| (...skipping 11 matching lines...) Expand all Loading... |
| 68 onKeyDown_: function(e) { | 66 onKeyDown_: function(e) { |
| 69 if (e.key == 'Tab' || e.key == 'Escape') { | 67 if (e.key == 'Tab' || e.key == 'Escape') { |
| 70 this.close(); | 68 this.close(); |
| 71 e.preventDefault(); | 69 e.preventDefault(); |
| 72 return; | 70 return; |
| 73 } | 71 } |
| 74 | 72 |
| 75 if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp') | 73 if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp') |
| 76 return; | 74 return; |
| 77 | 75 |
| 78 var nextOption = this.getNextOption_(e.key == 'ArrowDown' ? 1 : - 1); | 76 var nextOption = this.getNextOption_(e.key == 'ArrowDown' ? 1 : -1); |
| 79 if (nextOption) | 77 if (nextOption) |
| 80 nextOption.focus(); | 78 nextOption.focus(); |
| 81 | 79 |
| 82 e.preventDefault(); | 80 e.preventDefault(); |
| 83 }, | 81 }, |
| 84 | 82 |
| 85 /** | 83 /** |
| 86 * @param {number} step -1 for getting previous option (up), 1 for getting | 84 * @param {number} step -1 for getting previous option (up), 1 for getting |
| 87 * next option (down). | 85 * next option (down). |
| 88 * @return {?Element} The next focusable option, taking into account | 86 * @return {?Element} The next focusable option, taking into account |
| 89 * disabled/hidden attributes, or null if no focusable option exists. | 87 * disabled/hidden attributes, or null if no focusable option exists. |
| 90 * @private | 88 * @private |
| 91 */ | 89 */ |
| 92 getNextOption_: function(step) { | 90 getNextOption_: function(step) { |
| 93 // Using a counter to ensure no infinite loop occurs if all elements are | 91 // Using a counter to ensure no infinite loop occurs if all elements are |
| 94 // hidden/disabled. | 92 // hidden/disabled. |
| 95 var counter = 0; | 93 var counter = 0; |
| 96 var nextOption = null; | 94 var nextOption = null; |
| 97 var numOptions = this.options_.length; | 95 var numOptions = this.options_.length; |
| 98 var focusedIndex = Array.prototype.indexOf.call( | 96 var focusedIndex = |
| 99 this.options_, this.root.activeElement); | 97 Array.prototype.indexOf.call(this.options_, this.root.activeElement); |
| 100 | 98 |
| 101 do { | 99 do { |
| 102 focusedIndex = (numOptions + focusedIndex + step) % numOptions; | 100 focusedIndex = (numOptions + focusedIndex + step) % numOptions; |
| 103 nextOption = this.options_[focusedIndex]; | 101 nextOption = this.options_[focusedIndex]; |
| 104 if (nextOption.disabled || nextOption.hidden) | 102 if (nextOption.disabled || nextOption.hidden) |
| 105 nextOption = null; | 103 nextOption = null; |
| 106 counter++; | 104 counter++; |
| 107 } while (!nextOption && counter < numOptions); | 105 } while (!nextOption && counter < numOptions); |
| 108 | 106 |
| 109 return nextOption; | 107 return nextOption; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 137 var right = window.innerWidth - rect.left - this.offsetWidth; | 135 var right = window.innerWidth - rect.left - this.offsetWidth; |
| 138 this.style.right = right + 'px'; | 136 this.style.right = right + 'px'; |
| 139 } else { | 137 } else { |
| 140 var left = rect.right - this.offsetWidth; | 138 var left = rect.right - this.offsetWidth; |
| 141 this.style.left = left + 'px'; | 139 this.style.left = left + 'px'; |
| 142 } | 140 } |
| 143 | 141 |
| 144 // Attempt to show the menu starting from the top of the rectangle and | 142 // Attempt to show the menu starting from the top of the rectangle and |
| 145 // extending downwards. If that does not fit within the window, fallback to | 143 // extending downwards. If that does not fit within the window, fallback to |
| 146 // starting from the bottom and extending upwards. | 144 // starting from the bottom and extending upwards. |
| 147 var top = rect.top + this.offsetHeight <= window.innerHeight ? | 145 var top = rect.top + this.offsetHeight <= window.innerHeight ? rect.top : |
| 148 rect.top : | 146 rect.bottom - |
| 149 rect.bottom - this.offsetHeight - Math.max( | 147 this.offsetHeight - Math.max(rect.bottom - window.innerHeight, 0); |
| 150 rect.bottom - window.innerHeight, 0); | |
| 151 | 148 |
| 152 this.style.top = top + 'px'; | 149 this.style.top = top + 'px'; |
| 153 }, | 150 }, |
| 154 }); | 151 }); |
| OLD | NEW |