OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2010 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 cr.define('cr.ui', function() { |
| 6 const Menu = cr.ui.Menu; |
| 7 |
| 8 /** |
| 9 * Creates a new menu button element. |
| 10 * @param {Object=} opt_propertyBag Optional properties. |
| 11 * @constructor |
| 12 * @extends {HTMLButtonElement} |
| 13 */ |
| 14 var MenuButton = cr.ui.define('button'); |
| 15 |
| 16 MenuButton.prototype = { |
| 17 __proto__: HTMLButtonElement.prototype, |
| 18 |
| 19 /** |
| 20 * Initializes the menu button. |
| 21 */ |
| 22 decorate: function() { |
| 23 this.addEventListener('mousedown', this); |
| 24 this.addEventListener('keydown', this); |
| 25 |
| 26 var menu; |
| 27 if ((menu = this.getAttribute('menu'))) |
| 28 this.menu = menu; |
| 29 }, |
| 30 |
| 31 /** |
| 32 * The menu associated with the menu button. |
| 33 * @type {cr.ui.Menu} |
| 34 */ |
| 35 get menu() { |
| 36 return this.menu_; |
| 37 }, |
| 38 set menu(menu) { |
| 39 if (typeof menu == 'string' && menu[0] == '#') { |
| 40 menu = this.ownerDocument.getElementById(menu.slice(1)); |
| 41 cr.ui.decorate(menu, Menu); |
| 42 } |
| 43 |
| 44 this.menu_ = menu; |
| 45 if (menu) { |
| 46 if (menu.id) |
| 47 this.setAttribute('menu', '#' + menu.id); |
| 48 } |
| 49 }, |
| 50 |
| 51 /** |
| 52 * Handles event callbacks. |
| 53 * @param {Event} e The event object. |
| 54 */ |
| 55 handleEvent: function(e) { |
| 56 if (!this.menu) |
| 57 return; |
| 58 |
| 59 switch (e.type) { |
| 60 case 'mousedown': |
| 61 if (e.currentTarget == this.ownerDocument) { |
| 62 if (!this.contains(e.target) && !this.menu.contains(e.target)) |
| 63 this.hideMenu(); |
| 64 else |
| 65 e.preventDefault(); |
| 66 } else { |
| 67 if (this.isMenuShown()) { |
| 68 this.hideMenu(); |
| 69 } else { |
| 70 this.showMenu(); |
| 71 // Prevent the button from stealing focus on mousedown. |
| 72 e.preventDefault(); |
| 73 } |
| 74 } |
| 75 break; |
| 76 case 'keydown': |
| 77 this.handleKeyDown(e); |
| 78 // If the menu is visible we let it handle all the keyboard events. |
| 79 if (this.isMenuShown() && e.currentTarget == this.ownerDocument) { |
| 80 this.menu.handleKeyDown(e); |
| 81 e.preventDefault(); |
| 82 e.stopPropagation(); |
| 83 } |
| 84 break; |
| 85 |
| 86 case 'activate': |
| 87 case 'blur': |
| 88 this.hideMenu(); |
| 89 break; |
| 90 } |
| 91 }, |
| 92 |
| 93 /** |
| 94 * Shows the menu. |
| 95 */ |
| 96 showMenu: function() { |
| 97 this.menu.style.display = 'block'; |
| 98 // when the menu is shown we steal all keyboard events. |
| 99 this.ownerDocument.addEventListener('keydown', this, true); |
| 100 this.ownerDocument.addEventListener('mousedown', this, true); |
| 101 this.ownerDocument.addEventListener('blur', this, true); |
| 102 this.menu.addEventListener('activate', this); |
| 103 this.positionMenu_(); |
| 104 }, |
| 105 |
| 106 /** |
| 107 * Hides the menu. |
| 108 */ |
| 109 hideMenu: function() { |
| 110 this.menu.style.display = 'none'; |
| 111 this.ownerDocument.removeEventListener('keydown', this, true); |
| 112 this.ownerDocument.removeEventListener('mousedown', this, true); |
| 113 this.ownerDocument.removeEventListener('blur', this, true); |
| 114 this.menu.removeEventListener('activate', this); |
| 115 this.menu.selectedIndex = -1; |
| 116 }, |
| 117 |
| 118 /** |
| 119 * Whether the menu is shown. |
| 120 */ |
| 121 isMenuShown: function() { |
| 122 return window.getComputedStyle(this.menu).display != 'none'; |
| 123 }, |
| 124 |
| 125 /** |
| 126 * Positions the menu below the menu button. At this point we do not use any |
| 127 * advanced positioning logic to ensure the menu fits in the viewport. |
| 128 * @private |
| 129 */ |
| 130 positionMenu_: function() { |
| 131 var buttonRect = this.getBoundingClientRect(); |
| 132 this.menu.style.top = buttonRect.bottom + 'px'; |
| 133 if (getComputedStyle(this).direction == 'rtl') { |
| 134 var menuRect = this.menu.getBoundingClientRect(); |
| 135 this.menu.style.left = buttonRect.right - menuRect.width + 'px'; |
| 136 } else { |
| 137 this.menu.style.left = buttonRect.left + 'px'; |
| 138 } |
| 139 }, |
| 140 |
| 141 /** |
| 142 * Handles the keydown event for the menu button. |
| 143 */ |
| 144 handleKeyDown: function(e) { |
| 145 switch (e.keyIdentifier) { |
| 146 case 'Down': |
| 147 case 'Up': |
| 148 case 'Enter': |
| 149 case 'U+0020': // Space |
| 150 if (!this.isMenuShown()) |
| 151 this.showMenu(); |
| 152 e.preventDefault(); |
| 153 break; |
| 154 case 'Esc': |
| 155 case 'U+001B': // Maybe this is remote desktop playing a prank? |
| 156 this.hideMenu(); |
| 157 break; |
| 158 } |
| 159 } |
| 160 }; |
| 161 |
| 162 // Export |
| 163 return { |
| 164 MenuButton: MenuButton |
| 165 }; |
| 166 }); |
OLD | NEW |