Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 // How long to wait to open submenu when mouse hovers. | 5 // How long to wait to open submenu when mouse hovers. |
| 6 var SUBMENU_OPEN_DELAY_MS = 200; | 6 var SUBMENU_OPEN_DELAY_MS = 200; |
| 7 // How long to wait to close submenu when mouse left. | 7 // How long to wait to close submenu when mouse left. |
| 8 var SUBMENU_CLOSE_DELAY_MS = 500; | 8 var SUBMENU_CLOSE_DELAY_MS = 500; |
| 9 // Scroll repeat interval. | 9 // Scroll repeat interval. |
| 10 var SCROLL_INTERVAL_MS = 20; | 10 var SCROLL_INTERVAL_MS = 20; |
| 11 // Scrolling amount in pixel. | 11 // Scrolling amount in pixel. |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 22 * 'activate_no_close'. | 22 * 'activate_no_close'. |
| 23 * TODO(oshima): change these string to enum numbers once it becomes possible | 23 * TODO(oshima): change these string to enum numbers once it becomes possible |
| 24 * to pass number to C++. | 24 * to pass number to C++. |
| 25 */ | 25 */ |
| 26 function sendActivate(index, mode) { | 26 function sendActivate(index, mode) { |
| 27 chrome.send('activate', [String(index), mode]); | 27 chrome.send('activate', [String(index), mode]); |
| 28 } | 28 } |
| 29 | 29 |
| 30 /** | 30 /** |
| 31 * MenuItem class. | 31 * MenuItem class. |
| 32 * @constructor | |
| 33 * @extends {HTMLDivElement} | |
| 32 */ | 34 */ |
| 33 var MenuItem = cr.ui.define('div'); | 35 var MenuItem = cr.ui.define('div'); |
| 34 | 36 |
| 35 MenuItem.prototype = { | 37 MenuItem.prototype = { |
| 36 __proto__ : HTMLDivElement.prototype, | 38 __proto__: HTMLDivElement.prototype, |
| 37 | 39 |
| 38 /** | 40 /** |
| 39 * Decorates the menu item element. | 41 * Decorates the menu item element. |
| 42 * @this {MenuItem} | |
| 40 */ | 43 */ |
| 41 decorate: function() { | 44 decorate: function() { |
| 42 this.className = 'menu-item'; | 45 this.className = 'menu-item'; |
| 43 }, | 46 }, |
| 44 | 47 |
| 45 /** | 48 /** |
| 46 * Initialize the MenuItem. | 49 * Initialize the MenuItem. |
| 47 * @param {Menu} menu A {@code Menu} object to which this menu item | 50 * @param {Menu} menu A {@code Menu} object to which this menu item |
| 48 * will be added to. | 51 * will be added to. |
| 49 * @param {Object} attrs JSON object that represents this menu items | 52 * @param {Object} attrs JSON object that represents this menu items |
| 50 * properties. This is created from menu model in C code. See | 53 * properties. This is created from menu model in C code. See |
| 51 * chromeos/views/native_menu_webui.cc. | 54 * chromeos/views/native_menu_webui.cc. |
| 52 * @param {Object} model The model object. | 55 * @param {Object} model The model object. |
| 56 * @this {MenuItem} | |
| 53 */ | 57 */ |
| 54 init: function(menu, attrs, model) { | 58 init: function(menu, attrs, model) { |
| 55 // The left icon's width. 0 if no icon. | 59 // The left icon's width. 0 if no icon. |
| 56 var leftIconWidth = model.maxIconWidth; | 60 var leftIconWidth = model.maxIconWidth; |
| 57 this.menu_ = menu; | 61 this.menu_ = menu; |
| 58 this.attrs = attrs; | 62 this.attrs = attrs; |
| 59 var attrs = this.attrs; | 63 var attrs = this.attrs; |
| 60 if (attrs.type == 'separator') { | 64 if (attrs.type == 'separator') { |
| 61 this.className = 'separator'; | 65 this.className = 'separator'; |
| 62 } else if (attrs.type == 'command' || | 66 } else if (attrs.type == 'command' || |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 74 menu.appendChild(this); | 78 menu.appendChild(this); |
| 75 if (!attrs.visible) { | 79 if (!attrs.visible) { |
| 76 this.classList.add('hidden'); | 80 this.classList.add('hidden'); |
| 77 } | 81 } |
| 78 }, | 82 }, |
| 79 | 83 |
| 80 /** | 84 /** |
| 81 * Changes the selection state of the menu item. | 85 * Changes the selection state of the menu item. |
| 82 * @param {boolean} selected True to set the selection, or false | 86 * @param {boolean} selected True to set the selection, or false |
| 83 * otherwise. | 87 * otherwise. |
| 88 * @this {MenuItem} | |
| 84 */ | 89 */ |
| 85 set selected(selected) { | 90 set selected(selected) { |
| 86 if (selected) { | 91 if (selected) { |
| 87 this.classList.add('selected'); | 92 this.classList.add('selected'); |
| 88 this.menu_.selectedItem = this; | 93 this.menu_.selectedItem = this; |
| 89 } else { | 94 } else { |
| 90 this.classList.remove('selected'); | 95 this.classList.remove('selected'); |
| 91 } | 96 } |
| 92 }, | 97 }, |
| 93 | 98 |
| 94 /** | 99 /** |
| 95 * Activate the menu item. | 100 * Activate the menu item. |
| 101 * @this {MenuItem} | |
| 96 */ | 102 */ |
| 97 activate: function() { | 103 activate: function() { |
| 98 if (this.attrs.type == 'submenu') { | 104 if (this.attrs.type == 'submenu') { |
| 99 this.menu_.openSubmenu(this); | 105 this.menu_.openSubmenu(this); |
| 100 } else if (this.attrs.type != 'separator' && | 106 } else if (this.attrs.type != 'separator' && |
| 101 this.className.indexOf('selected') >= 0) { | 107 this.className.indexOf('selected') >= 0) { |
| 102 sendActivate(this.menu_.getMenuItemIndexOf(this), | 108 sendActivate(this.menu_.getMenuItemIndexOf(this), |
| 103 'close_and_activate'); | 109 'close_and_activate'); |
| 104 } | 110 } |
| 105 }, | 111 }, |
| 106 | 112 |
| 107 /** | 113 /** |
| 108 * Sends open_submenu WebUI message. | 114 * Sends open_submenu WebUI message. |
| 115 * @this {MenuItem} | |
| 109 */ | 116 */ |
| 110 sendOpenSubmenuCommand: function() { | 117 sendOpenSubmenuCommand: function() { |
| 111 chrome.send('open_submenu', | 118 chrome.send('open_submenu', |
| 112 [String(this.menu_.getMenuItemIndexOf(this)), | 119 [String(this.menu_.getMenuItemIndexOf(this)), |
| 113 String(this.getBoundingClientRect().top)]); | 120 String(this.getBoundingClientRect().top)]); |
| 114 }, | 121 }, |
| 115 | 122 |
| 116 /** | 123 /** |
| 117 * Internal method to initiailze the MenuItem. | 124 * Internal method to initiailze the MenuItem. |
| 125 * @this {MenuItem} | |
| 118 * @private | 126 * @private |
| 119 */ | 127 */ |
| 120 initMenuItem_: function() { | 128 initMenuItem_: function() { |
| 121 var attrs = this.attrs; | 129 var attrs = this.attrs; |
| 122 this.className = 'menu-item ' + attrs.type; | 130 this.className = 'menu-item ' + attrs.type; |
| 123 this.menu_.addHandlers(this, this); | 131 this.menu_.addHandlers(this, this); |
| 124 var label = document.createElement('div'); | 132 var label = document.createElement('div'); |
| 125 | 133 |
| 126 label.className = 'menu-label'; | 134 label.className = 'menu-label'; |
| 127 this.menu_.addLabelTo(this, attrs.label, label, | 135 this.menu_.addLabelTo(this, attrs.label, label, |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 173 // TODO(oshima): figure out how to update left padding in rule. | 181 // TODO(oshima): figure out how to update left padding in rule. |
| 174 // 4 is the padding on left side of icon. | 182 // 4 is the padding on left side of icon. |
| 175 var padding = | 183 var padding = |
| 176 4 + leftIconWidth + this.menu_.config_.icon_to_label_padding; | 184 4 + leftIconWidth + this.menu_.config_.icon_to_label_padding; |
| 177 this.style.WebkitPaddingStart = padding + 'px'; | 185 this.style.WebkitPaddingStart = padding + 'px'; |
| 178 }, | 186 }, |
| 179 }; | 187 }; |
| 180 | 188 |
| 181 /** | 189 /** |
| 182 * Menu class. | 190 * Menu class. |
| 191 * @constructor | |
| 192 * @extends {HTMLDivElement} | |
| 183 */ | 193 */ |
| 184 var Menu = cr.ui.define('div'); | 194 var Menu = cr.ui.define('div'); |
| 185 | 195 |
| 186 Menu.prototype = { | 196 Menu.prototype = { |
| 187 __proto__: HTMLDivElement.prototype, | 197 __proto__: HTMLDivElement.prototype, |
| 188 | 198 |
| 189 /** | 199 /** |
| 190 * Configuration object. | 200 * Configuration object. |
| 191 * @type {Object} | 201 * @type {Object} |
| 192 */ | 202 */ |
| 193 config_ : null, | 203 config_: null, |
| 194 | 204 |
| 195 /** | 205 /** |
| 196 * Currently selected menu item. | 206 * Currently selected menu item. |
| 197 * @type {MenuItem} | 207 * @type {MenuItem} |
| 198 */ | 208 */ |
| 199 current_ : null, | 209 current_: null, |
| 200 | 210 |
| 201 /** | 211 /** |
| 202 * Timers for opening/closing submenu. | 212 * Timers for opening/closing submenu. |
| 203 * @type {number} | 213 * @type {number} |
| 204 */ | 214 */ |
| 205 openSubmenuTimer_ : 0, | 215 openSubmenuTimer_: 0, |
| 206 closeSubmenuTimer_ : 0, | 216 closeSubmenuTimer_: 0, |
| 207 | 217 |
| 208 /** | 218 /** |
| 209 * Auto scroll timer. | 219 * Auto scroll timer. |
| 210 * @type {number} | 220 * @type {number} |
| 211 */ | 221 */ |
| 212 scrollTimer_ : 0, | 222 scrollTimer_: 0, |
| 213 | 223 |
| 214 /** | 224 /** |
| 215 * Pointer to a submenu currently shown, if any. | 225 * Pointer to a submenu currently shown, if any. |
| 216 * @type {MenuItem} | 226 * @type {MenuItem} |
| 217 */ | 227 */ |
| 218 submenuShown_ : null, | 228 submenuShown_: null, |
| 219 | 229 |
| 220 /** | 230 /** |
| 221 * True if this menu is root. | 231 * True if this menu is root. |
| 222 * @type {boolean} | 232 * @type {boolean} |
| 223 */ | 233 */ |
| 224 isRoot_ : false, | 234 isRoot_: false, |
| 225 | 235 |
| 226 /** | 236 /** |
| 227 * Scrollable Viewport. | 237 * Scrollable Viewport. |
| 228 * @type {HTMLElement} | 238 * @type {HTMLElement} |
| 229 */ | 239 */ |
| 230 viewpotr_ : null, | 240 viewpotr_: null, |
| 231 | 241 |
| 232 /** | 242 /** |
| 233 * Total hight of scroll buttons. Used to adjust the height of | 243 * Total hight of scroll buttons. Used to adjust the height of |
| 234 * viewport in order to show scroll bottons without scrollbar. | 244 * viewport in order to show scroll bottons without scrollbar. |
| 235 * @type {number} | 245 * @type {number} |
| 236 */ | 246 */ |
| 237 buttonHeight_ : 0, | 247 buttonHeight_: 0, |
| 238 | 248 |
| 239 /** | 249 /** |
| 240 * True to enable scroll button. | 250 * True to enable scroll button. |
| 241 * @type {boolean} | 251 * @type {boolean} |
| 242 */ | 252 */ |
| 243 scrollEnabled : false, | 253 scrollEnabled: false, |
| 244 | 254 |
| 245 /** | 255 /** |
| 246 * Decorates the menu element. | 256 * Decorates the menu element. |
| 257 * @this {Menu} | |
| 247 */ | 258 */ |
| 248 decorate: function() { | 259 decorate: function() { |
| 249 this.id = 'viewport'; | 260 this.id = 'viewport'; |
| 250 }, | 261 }, |
| 251 | 262 |
| 252 /** | 263 /** |
| 253 * Initialize the menu. | 264 * Initialize the menu. |
| 254 * @param {Object} config Configuration parameters in JSON format. | 265 * @param {Object} config Configuration parameters in JSON format. |
| 255 * See chromeos/views/native_menu_webui.cc for details. | 266 * See chromeos/views/native_menu_webui.cc for details. |
| 267 * @this {Menu} | |
| 256 */ | 268 */ |
| 257 init: function(config) { | 269 init: function(config) { |
| 258 // List of menu items | 270 // List of menu items |
| 259 this.items_ = []; | 271 this.items_ = []; |
| 260 // Map from mnemonic character to item to activate | 272 // Map from mnemonic character to item to activate |
| 261 this.mnemonics_ = {}; | 273 this.mnemonics_ = {}; |
| 262 | 274 |
| 263 this.config_ = config; | 275 this.config_ = config; |
| 264 this.addEventListener('mouseout', this.onMouseout_.bind(this)); | 276 this.addEventListener('mouseout', this.onMouseout_.bind(this)); |
| 265 | 277 |
| 266 document.addEventListener('keydown', this.onKeydown_.bind(this)); | 278 document.addEventListener('keydown', this.onKeydown_.bind(this)); |
| 267 document.addEventListener('keypress', this.onKeypress_.bind(this)); | 279 document.addEventListener('keypress', this.onKeypress_.bind(this)); |
| 268 document.addEventListener('mousewheel', this.onMouseWheel_.bind(this)); | 280 document.addEventListener('mousewheel', this.onMouseWheel_.bind(this)); |
| 269 window.addEventListener('resize', this.onResize_.bind(this)); | 281 window.addEventListener('resize', this.onResize_.bind(this)); |
| 270 | 282 |
| 271 // Setup scroll events. | 283 // Setup scroll events. |
| 272 var up = document.getElementById('scroll-up'); | 284 var up = $('scroll-up'); |
| 273 var down = document.getElementById('scroll-down'); | 285 var down = $('scroll-down'); |
| 274 up.addEventListener('mouseout', this.stopScroll_.bind(this)); | 286 up.addEventListener('mouseout', this.stopScroll_.bind(this)); |
| 275 down.addEventListener('mouseout', this.stopScroll_.bind(this)); | 287 down.addEventListener('mouseout', this.stopScroll_.bind(this)); |
| 276 var menu = this; | 288 var menu = this; |
| 277 up.addEventListener('mouseover', | 289 up.addEventListener('mouseover', |
| 278 function() { | 290 function() { |
| 279 menu.autoScroll_(-SCROLL_TICK_PX); | 291 menu.autoScroll_(-SCROLL_TICK_PX); |
| 280 }); | 292 }); |
| 281 down.addEventListener('mouseover', | 293 down.addEventListener('mouseover', |
| 282 function() { | 294 function() { |
| 283 menu.autoScroll_(SCROLL_TICK_PX); | 295 menu.autoScroll_(SCROLL_TICK_PX); |
| 284 }); | 296 }); |
| 285 | 297 |
| 286 this.buttonHeight_ = | 298 this.buttonHeight_ = |
| 287 up.getBoundingClientRect().height + | 299 up.getBoundingClientRect().height + |
| 288 down.getBoundingClientRect().height; | 300 down.getBoundingClientRect().height; |
| 289 }, | 301 }, |
| 290 | 302 |
| 291 /** | 303 /** |
| 292 * Adds a label to {@code targetDiv}. A label may contain | 304 * Adds a label to {@code targetDiv}. A label may contain |
| 293 * mnemonic key, preceded by '&'. | 305 * mnemonic key, preceded by '&'. |
| 294 * @param {MenuItem} item The menu item to be activated by mnemonic | 306 * @param {MenuItem} item The menu item to be activated by mnemonic |
| 295 * key. | 307 * key. |
| 296 * @param {string} label The label string to be added to | 308 * @param {string} label The label string to be added to |
| 297 * {@code targetDiv}. | 309 * {@code targetDiv}. |
| 298 * @param {HTMLElement} div The div element the label is added to. | 310 * @param {HTMLElement} div The div element the label is added to. |
| 299 * @param {boolean} enableMnemonic True to enable mnemonic, or false | 311 * @param {boolean} enableMnemonic True to enable mnemonic, or false |
| 300 * to not to interprete mnemonic key. The function removes '&' | 312 * to not to interprete mnemonic key. The function removes '&' |
| 301 * from the label in both cases. | 313 * from the label in both cases. |
| 314 * @this {Menu} | |
| 302 */ | 315 */ |
| 303 addLabelTo: function(item, label, targetDiv, enableMnemonic) { | 316 addLabelTo: function(item, label, targetDiv, enableMnemonic) { |
| 304 var mnemonic = MNEMONIC_REGEXP.exec(label); | 317 var mnemonic = MNEMONIC_REGEXP.exec(label); |
| 305 if (mnemonic && enableMnemonic) { | 318 if (mnemonic && enableMnemonic) { |
| 306 var c = mnemonic[2].toLowerCase(); | 319 var c = mnemonic[2].toLowerCase(); |
| 307 this.mnemonics_[c] = item; | 320 this.mnemonics_[c] = item; |
| 308 } | 321 } |
| 309 if (!mnemonic) { | 322 if (!mnemonic) { |
| 310 targetDiv.textContent = label; | 323 targetDiv.textContent = label; |
| 311 } else if (enableMnemonic) { | 324 } else if (enableMnemonic) { |
| 312 targetDiv.appendChild(document.createTextNode(mnemonic[1])); | 325 targetDiv.appendChild(document.createTextNode(mnemonic[1])); |
| 313 targetDiv.appendChild(document.createElement('span')); | 326 targetDiv.appendChild(document.createElement('span')); |
| 314 targetDiv.appendChild(document.createTextNode(mnemonic[3])); | 327 targetDiv.appendChild(document.createTextNode(mnemonic[3])); |
| 315 targetDiv.childNodes[1].className = 'mnemonic'; | 328 targetDiv.childNodes[1].className = 'mnemonic'; |
| 316 targetDiv.childNodes[1].textContent = mnemonic[2]; | 329 targetDiv.childNodes[1].textContent = mnemonic[2]; |
| 317 } else { | 330 } else { |
| 318 targetDiv.textContent = mnemonic.splice(1, 3).join(''); | 331 targetDiv.textContent = mnemonic.splice(1, 3).join(''); |
| 319 } | 332 } |
| 320 }, | 333 }, |
| 321 | 334 |
| 322 /** | 335 /** |
| 323 * Returns the index of the {@code item}. | 336 * Returns the index of the {@code item}. |
| 337 * @this {Menu} | |
| 338 * @return {number} Menu item index. | |
| 324 */ | 339 */ |
| 325 getMenuItemIndexOf: function(item) { | 340 getMenuItemIndexOf: function(item) { |
| 326 return this.items_.indexOf(item); | 341 return this.items_.indexOf(item); |
| 327 }, | 342 }, |
| 328 | 343 |
| 329 /** | 344 /** |
| 330 * A template method to create an item object. It can be a subclass | 345 * A template method to create an item object. It can be a subclass |
| 331 * of MenuItem, or any HTMLElement that implements {@code init}, | 346 * of MenuItem, or any HTMLElement that implements {@code init}, |
| 332 * {@code activate} methods as well as {@code selected} attribute. | 347 * {@code activate} methods as well as {@code selected} attribute. |
| 333 * @param {Object} attrs The menu item's properties passed from C++. | 348 * @param {Object} attrs The menu item's properties passed from C++. |
| 349 * @return {Object} Menu Item instance. | |
| 334 */ | 350 */ |
| 335 createMenuItem: function(attrs) { | 351 createMenuItem: function(attrs) { |
| 336 return new MenuItem(); | 352 return new MenuItem(); |
| 337 }, | 353 }, |
| 338 | 354 |
| 339 /** | 355 /** |
| 340 * Update and display the new model. | 356 * Update and display the new model. |
| 357 * @param {Object} model New model object. | |
| 358 * @this {Menu} | |
| 341 */ | 359 */ |
| 342 updateModel: function(model) { | 360 updateModel: function(model) { |
| 343 this.isRoot = model.isRoot; | 361 this.isRoot = model.isRoot; |
| 344 this.current_ = null; | 362 this.current_ = null; |
| 345 this.items_ = []; | 363 this.items_ = []; |
| 346 this.mnemonics_ = {}; | 364 this.mnemonics_ = {}; |
| 347 this.innerHTML = ''; // remove menu items | 365 this.innerHTML = ''; // remove menu items |
| 348 | 366 |
| 349 for (var i = 0; i < model.items.length; i++) { | 367 for (var i = 0; i < model.items.length; i++) { |
| 350 var attrs = model.items[i]; | 368 var attrs = model.items[i]; |
| 351 var item = this.createMenuItem(attrs); | 369 var item = this.createMenuItem(attrs); |
| 352 item.init(this, attrs, model); | 370 item.init(this, attrs, model); |
| 353 this.items_.push(item); | 371 this.items_.push(item); |
| 354 } | 372 } |
| 355 this.onResize_(); | 373 this.onResize_(); |
| 356 }, | 374 }, |
| 357 | 375 |
| 358 /** | 376 /** |
| 359 * Highlights the currently selected item, or | 377 * Highlights the currently selected item, or |
| 360 * select the 1st selectable item if none is selected. | 378 * select the 1st selectable item if none is selected. |
| 379 * @this {Menu} | |
| 361 */ | 380 */ |
| 362 showSelection: function() { | 381 showSelection: function() { |
| 363 if (this.current_) { | 382 if (this.current_) { |
| 364 this.current_.selected = true; | 383 this.current_.selected = true; |
| 365 } else { | 384 } else { |
| 366 this.findNextEnabled_(1).selected = true; | 385 this.findNextEnabled_(1).selected = true; |
| 367 } | 386 } |
| 368 }, | 387 }, |
| 369 | 388 |
| 370 /** | 389 /** |
| 371 * Add event handlers for the item. | 390 * Add event handlers for the item. |
| 391 * @this {Menu} | |
| 372 */ | 392 */ |
| 373 addHandlers: function(item, target) { | 393 addHandlers: function(item, target) { |
| 374 var menu = this; | 394 var menu = this; |
| 375 target.addEventListener('mouseover', function(event) { | 395 target.addEventListener('mouseover', function(event) { |
| 376 menu.onMouseover_(event, item); | 396 menu.onMouseover_(event, item); |
| 377 }); | 397 }); |
| 378 if (item.attrs.enabled) { | 398 if (item.attrs.enabled) { |
| 379 target.addEventListener('mouseup', function(event) { | 399 target.addEventListener('mouseup', function(event) { |
| 380 menu.onClick_(event, item); | 400 menu.onClick_(event, item); |
| 381 }); | 401 }); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 392 * open. | 412 * open. |
| 393 * 2) If the selected menu is submenu, and that submenu is already opened, | 413 * 2) If the selected menu is submenu, and that submenu is already opened, |
| 394 * cancel both open/close timer. | 414 * cancel both open/close timer. |
| 395 * 3) If the selected menu is not submenu, cancel all timers and start | 415 * 3) If the selected menu is not submenu, cancel all timers and start |
| 396 * timer to close submenu. | 416 * timer to close submenu. |
| 397 * This prevents from opening/closing menus while you're actively | 417 * This prevents from opening/closing menus while you're actively |
| 398 * navigating menus. To open submenu, you need to wait a bit, or click | 418 * navigating menus. To open submenu, you need to wait a bit, or click |
| 399 * submenu. | 419 * submenu. |
| 400 * | 420 * |
| 401 * @param {MenuItem} item The selected item. | 421 * @param {MenuItem} item The selected item. |
| 422 * @this {Menu} | |
| 402 */ | 423 */ |
| 403 set selectedItem(item) { | 424 set selectedItem(item) { |
| 404 if (this.current_ != item) { | 425 if (this.current_ != item) { |
| 405 if (this.current_ != null) | 426 if (this.current_ != null) |
| 406 this.current_.selected = false; | 427 this.current_.selected = false; |
| 407 this.current_ = item; | 428 this.current_ = item; |
| 408 this.makeSelectedItemVisible_(); | 429 this.makeSelectedItemVisible_(); |
| 409 } | 430 } |
| 410 | 431 |
| 411 var menu = this; | 432 var menu = this; |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 428 menu.closeSubmenu_(item); | 449 menu.closeSubmenu_(item); |
| 429 }, | 450 }, |
| 430 SUBMENU_CLOSE_DELAY_MS); | 451 SUBMENU_CLOSE_DELAY_MS); |
| 431 } | 452 } |
| 432 }, | 453 }, |
| 433 | 454 |
| 434 /** | 455 /** |
| 435 * Open submenu {@code item}. It does nothing if the submenu is | 456 * Open submenu {@code item}. It does nothing if the submenu is |
| 436 * already opened. | 457 * already opened. |
| 437 * @param {MenuItem} item The submenu item to open. | 458 * @param {MenuItem} item The submenu item to open. |
| 459 * @this {Menu} | |
| 438 */ | 460 */ |
| 439 openSubmenu: function(item) { | 461 openSubmenu: function(item) { |
| 440 this.cancelSubmenuTimer_(); | 462 this.cancelSubmenuTimer_(); |
| 441 if (this.submenuShown_ != item) { | 463 if (this.submenuShown_ != item) { |
| 442 this.submenuShown_ = item; | 464 this.submenuShown_ = item; |
| 443 item.sendOpenSubmenuCommand(); | 465 item.sendOpenSubmenuCommand(); |
| 444 } | 466 } |
| 445 }, | 467 }, |
| 446 | 468 |
| 447 /** | 469 /** |
| 448 * Handle keyboard navigation and activation. | 470 * Handle keyboard navigation and activation. |
| 471 * @this {Menu} | |
| 449 * @private | 472 * @private |
| 450 */ | 473 */ |
| 451 onKeydown_: function(event) { | 474 onKeydown_: function(event) { |
| 452 switch (event.keyIdentifier) { | 475 switch (event.keyIdentifier) { |
| 453 case 'Left': | 476 case 'Left': |
| 454 this.moveToParent_(); | 477 this.moveToParent_(); |
| 455 break; | 478 break; |
| 456 case 'Right': | 479 case 'Right': |
| 457 this.moveToSubmenu_(); | 480 this.moveToSubmenu_(); |
| 458 break; | 481 break; |
| 459 case 'Up': | 482 case 'Up': |
| 460 this.classList.add('mnemonic-enabled'); | 483 this.classList.add('mnemonic-enabled'); |
| 461 this.findNextEnabled_(-1).selected = true; | 484 this.findNextEnabled_(-1).selected = true; |
| 462 break; | 485 break; |
| 463 case 'Down': | 486 case 'Down': |
| 464 this.classList.add('mnemonic-enabled'); | 487 this.classList.add('mnemonic-enabled'); |
| 465 this.findNextEnabled_(1).selected = true; | 488 this.findNextEnabled_(1).selected = true; |
| 466 break; | 489 break; |
| 467 case 'U+0009': // tab | 490 case 'U+0009': // tab |
| 468 break; | 491 break; |
| 469 case 'U+001B': // escape | 492 case 'U+001B': // escape |
| 470 chrome.send('close_all', []); | 493 chrome.send('close_all'); |
| 471 break; | 494 break; |
| 472 case 'Enter': | 495 case 'Enter': |
| 473 case 'U+0020': // space | 496 case 'U+0020': // space |
| 474 if (this.current_) { | 497 if (this.current_) { |
| 475 this.current_.activate(); | 498 this.current_.activate(); |
| 476 } | 499 } |
| 477 break; | 500 break; |
| 478 } | 501 } |
| 479 }, | 502 }, |
| 480 | 503 |
| 481 /** | 504 /** |
| 482 * Handle mnemonic keys. | 505 * Handle mnemonic keys. |
| 506 * @this {Menu} | |
| 483 * @private | 507 * @private |
| 484 */ | 508 */ |
| 485 onKeypress_: function(event) { | 509 onKeypress_: function(event) { |
| 486 // Handles mnemonic. | 510 // Handles mnemonic. |
| 487 var c = String.fromCharCode(event.keyCode); | 511 var c = String.fromCharCode(event.keyCode); |
| 488 var item = this.mnemonics_[c.toLowerCase()]; | 512 var item = this.mnemonics_[c.toLowerCase()]; |
| 489 if (item) { | 513 if (item) { |
| 490 item.selected = true; | 514 item.selected = true; |
| 491 item.activate(); | 515 item.activate(); |
| 492 } | 516 } |
| 493 }, | 517 }, |
| 494 | 518 |
| 495 // Mouse Event handlers | 519 /** |
| 520 * Mouse click event handler. | |
| 521 * @private | |
| 522 */ | |
| 496 onClick_: function(event, item) { | 523 onClick_: function(event, item) { |
| 497 item.activate(); | 524 item.activate(); |
| 498 }, | 525 }, |
| 499 | 526 |
| 527 /** | |
| 528 * Mouse over event handler. | |
| 529 * @this {Menu} | |
| 530 * @private | |
| 531 */ | |
| 500 onMouseover_: function(event, item) { | 532 onMouseover_: function(event, item) { |
| 501 this.cancelSubmenuTimer_(); | 533 this.cancelSubmenuTimer_(); |
| 502 // Ignore false mouseover event at (0,0) which is | 534 // Ignore false mouseover event at (0,0) which is |
| 503 // emitted when opening submenu. | 535 // emitted when opening submenu. |
| 504 if (item.attrs.enabled && event.clientX != 0 && event.clientY != 0) { | 536 if (item.attrs.enabled && event.clientX != 0 && event.clientY != 0) { |
| 505 item.selected = true; | 537 item.selected = true; |
| 506 } | 538 } |
| 507 }, | 539 }, |
| 508 | 540 |
| 541 /** | |
| 542 * Mouse out event handler. | |
| 543 * @this {Menu} | |
| 544 * @private | |
| 545 */ | |
| 509 onMouseout_: function(event) { | 546 onMouseout_: function(event) { |
| 510 if (this.current_) { | 547 if (this.current_) { |
| 511 this.current_.selected = false; | 548 this.current_.selected = false; |
| 512 } | 549 } |
| 513 }, | 550 }, |
| 514 | 551 |
| 552 /** | |
| 553 * Handles window resize action. | |
| 554 * @this {Menu} | |
| 555 * @private | |
| 556 */ | |
| 515 onResize_: function() { | 557 onResize_: function() { |
| 516 var up = document.getElementById('scroll-up'); | 558 var up = $('scroll-up'); |
| 517 var down = document.getElementById('scroll-down'); | 559 var down = $('scroll-down'); |
| 518 // this needs to be < 2 as empty page has height of 1. | 560 // this needs to be < 2 as empty page has height of 1. |
| 519 if (window.innerHeight < 2) { | 561 if (window.innerHeight < 2) { |
| 520 // menu window is not visible yet. just hide buttons. | 562 // menu window is not visible yet. just hide buttons. |
| 521 up.classList.add('hidden'); | 563 up.classList.add('hidden'); |
| 522 down.classList.add('hidden'); | 564 down.classList.add('hidden'); |
| 523 return; | 565 return; |
| 524 } | 566 } |
| 525 // Do not use screen width to determin if we need scroll buttons | 567 // Do not use screen width to determin if we need scroll buttons |
| 526 // as the max renderer hight can be shorter than actual screen size. | 568 // as the max renderer hight can be shorter than actual screen size. |
| 527 // TODO(oshima): Fix this when we implement transparent renderer. | 569 // TODO(oshima): Fix this when we implement transparent renderer. |
| 528 if (this.scrollHeight > window.innerHeight && this.scrollEnabled) { | 570 if (this.scrollHeight > window.innerHeight && this.scrollEnabled) { |
| 529 this.style.height = (window.innerHeight - this.buttonHeight_) + 'px'; | 571 this.style.height = (window.innerHeight - this.buttonHeight_) + 'px'; |
| 530 up.classList.remove('hidden'); | 572 up.classList.remove('hidden'); |
| 531 down.classList.remove('hidden'); | 573 down.classList.remove('hidden'); |
| 532 } else { | 574 } else { |
| 533 this.style.height = ''; | 575 this.style.height = ''; |
| 534 up.classList.add('hidden'); | 576 up.classList.add('hidden'); |
| 535 down.classList.add('hidden'); | 577 down.classList.add('hidden'); |
| 536 } | 578 } |
| 537 }, | 579 }, |
| 538 | 580 |
| 581 /** | |
| 582 * Mouse wheel scroll event. | |
| 583 * @this {Menu} | |
| 584 * @private | |
| 585 */ | |
| 539 onMouseWheel_: function(event) { | 586 onMouseWheel_: function(event) { |
| 540 var delta = event.wheelDelta / 5; | 587 var delta = event.wheelDelta / 5; |
| 541 this.scrollTop -= delta; | 588 this.scrollTop -= delta; |
| 542 }, | 589 }, |
| 543 | 590 |
| 544 /** | 591 /** |
| 545 * Closes the submenu. | 592 * Closes the submenu. |
| 546 * a submenu. | 593 * a submenu. |
| 594 * @this {Menu} | |
| 547 * @private | 595 * @private |
| 548 */ | 596 */ |
| 549 closeSubmenu_: function(item) { | 597 closeSubmenu_: function(item) { |
| 550 this.submenuShown_ = null; | 598 this.submenuShown_ = null; |
| 551 this.cancelSubmenuTimer_(); | 599 this.cancelSubmenuTimer_(); |
| 552 chrome.send('close_submenu', []); | 600 chrome.send('close_submenu'); |
| 553 }, | 601 }, |
| 554 | 602 |
| 555 /** | 603 /** |
| 556 * Move the selection to parent menu if the current menu is | 604 * Move the selection to parent menu if the current menu is |
| 557 * a submenu. | 605 * a submenu. |
| 606 * @this {Menu} | |
| 558 * @private | 607 * @private |
| 559 */ | 608 */ |
| 560 moveToParent_: function() { | 609 moveToParent_: function() { |
| 561 if (!this.isRoot) { | 610 if (!this.isRoot) { |
| 562 if (this.current_) { | 611 if (this.current_) { |
| 563 this.current_.selected = false; | 612 this.current_.selected = false; |
| 564 } | 613 } |
| 565 chrome.send('move_to_parent', []); | 614 chrome.send('move_to_parent'); |
| 566 } | 615 } |
| 567 }, | 616 }, |
| 568 | 617 |
| 569 /** | 618 /** |
| 570 * Move the selection to submenu if the currently selected | 619 * Move the selection to submenu if the currently selected |
| 571 * menu is a submenu. | 620 * menu is a submenu. |
| 621 * @this {Menu} | |
| 572 * @private | 622 * @private |
| 573 */ | 623 */ |
| 574 moveToSubmenu_: function () { | 624 moveToSubmenu_: function() { |
| 575 var current = this.current_; | 625 var current = this.current_; |
| 576 if (current && current.attrs.type == 'submenu') { | 626 if (current && current.attrs.type == 'submenu') { |
| 577 this.openSubmenu(current); | 627 this.openSubmenu(current); |
| 578 chrome.send('move_to_submenu', []); | 628 chrome.send('move_to_submenu'); |
| 579 } | 629 } |
| 580 }, | 630 }, |
| 581 | 631 |
| 582 /** | 632 /** |
| 583 * Find a next selectable item. If nothing is selected, the 1st | 633 * Find a next selectable item. If nothing is selected, the 1st |
| 584 * selectable item will be chosen. Returns null if nothing is | 634 * selectable item will be chosen. Returns null if nothing is |
| 585 * selectable. | 635 * selectable. |
| 586 * @param {number} incr Specifies the direction to search, 1 to | 636 * @param {number} incr Specifies the direction to search, 1 to |
| 587 * downwards and -1 for upwards. | 637 * downwards and -1 for upwards. |
|
Dan Beam
2012/05/07 17:43:53
nit: indent this continuation of @param +4\s
kmadhusu
2012/05/08 20:20:19
Done.
| |
| 638 * @this {Menu} | |
| 588 * @private | 639 * @private |
| 640 * | |
|
Dan Beam
2012/05/07 17:43:53
nit: remove empty comment line
kmadhusu
2012/05/08 20:20:19
Done.
| |
| 641 * @return {Object} Next enabled menu item. | |
| 589 */ | 642 */ |
| 590 findNextEnabled_: function(incr) { | 643 findNextEnabled_: function(incr) { |
| 591 var len = this.items_.length; | 644 var len = this.items_.length; |
| 592 var index; | 645 var index; |
| 593 if (this.current_) { | 646 if (this.current_) { |
| 594 index = this.getMenuItemIndexOf(this.current_); | 647 index = this.getMenuItemIndexOf(this.current_); |
| 595 } else { | 648 } else { |
| 596 index = incr > 0 ? -1 : len; | 649 index = incr > 0 ? -1 : len; |
| 597 } | 650 } |
| 598 for (var i = 0; i < len; i++) { | 651 for (var i = 0; i < len; i++) { |
| 599 index = (index + incr + len) % len; | 652 index = (index + incr + len) % len; |
| 600 var item = this.items_[index]; | 653 var item = this.items_[index]; |
| 601 if (item.attrs.enabled && item.attrs.type != 'separator' && | 654 if (item.attrs.enabled && item.attrs.type != 'separator' && |
| 602 !item.classList.contains('hidden')) | 655 !item.classList.contains('hidden')) |
| 603 return item; | 656 return item; |
| 604 } | 657 } |
| 605 return null; | 658 return null; |
| 606 }, | 659 }, |
| 607 | 660 |
| 608 /** | 661 /** |
| 609 * Cancels timers to open/close submenus. | 662 * Cancels timers to open/close submenus. |
| 663 * @this {Menu} | |
| 610 * @private | 664 * @private |
| 611 */ | 665 */ |
| 612 cancelSubmenuTimer_: function() { | 666 cancelSubmenuTimer_: function() { |
| 613 clearTimeout(this.openSubmenuTimer_); | 667 clearTimeout(this.openSubmenuTimer_); |
| 614 this.openSubmenuTimer_ = 0; | 668 this.openSubmenuTimer_ = 0; |
| 615 clearTimeout(this.closeSubmenuTimer_); | 669 clearTimeout(this.closeSubmenuTimer_); |
| 616 this.closeSubmenuTimer_ = 0; | 670 this.closeSubmenuTimer_ = 0; |
| 617 }, | 671 }, |
| 618 | 672 |
| 619 /** | 673 /** |
| 620 * Starts auto scroll. | 674 * Starts auto scroll. |
| 621 * @param {number} tick The number of pixels to scroll. | 675 * @param {number} tick The number of pixels to scroll. |
| 676 * @this {Menu} | |
| 622 * @private | 677 * @private |
| 623 */ | 678 */ |
| 624 autoScroll_: function(tick) { | 679 autoScroll_: function(tick) { |
| 625 var previous = this.scrollTop; | 680 var previous = this.scrollTop; |
| 626 this.scrollTop += tick; | 681 this.scrollTop += tick; |
| 627 var menu = this; | 682 var menu = this; |
| 628 this.scrollTimer_ = setTimeout( | 683 this.scrollTimer_ = setTimeout( |
| 629 function() { | 684 function() { |
| 630 menu.autoScroll_(tick); | 685 menu.autoScroll_(tick); |
| 631 }, | 686 }, |
| 632 SCROLL_INTERVAL_MS); | 687 SCROLL_INTERVAL_MS); |
| 633 }, | 688 }, |
| 634 | 689 |
| 635 /** | 690 /** |
| 636 * Stops auto scroll. | 691 * Stops auto scroll. |
| 692 * @this {Menu} | |
| 637 * @private | 693 * @private |
| 638 */ | 694 */ |
| 639 stopScroll_: function () { | 695 stopScroll_: function() { |
| 640 clearTimeout(this.scrollTimer_); | 696 clearTimeout(this.scrollTimer_); |
| 641 this.scrollTimer_ = 0; | 697 this.scrollTimer_ = 0; |
| 642 }, | 698 }, |
| 643 | 699 |
| 644 /** | 700 /** |
| 645 * Scrolls the viewport to make the selected item visible. | 701 * Scrolls the viewport to make the selected item visible. |
| 702 * @this {Menu} | |
| 646 * @private | 703 * @private |
| 647 */ | 704 */ |
| 648 makeSelectedItemVisible_: function(){ | 705 makeSelectedItemVisible_: function() { |
| 649 this.current_.scrollIntoViewIfNeeded(false); | 706 this.current_.scrollIntoViewIfNeeded(false); |
| 650 }, | 707 }, |
| 651 }; | 708 }; |
| 652 | 709 |
| 653 /** | 710 /** |
| 654 * functions to be called from C++. | 711 * functions to be called from C++. |
| 655 */ | 712 */ |
| 656 function init(config) { | 713 function modelUpdated() { |
| 657 document.getElementById('viewport').init(config); | 714 chrome.send('model_updated'); |
| 658 } | 715 } |
| 659 | 716 |
| 660 function selectItem() { | 717 function selectItem() { |
| 661 document.getElementById('viewport').showSelection(); | 718 $('viewport').showSelection(); |
| 662 } | 719 } |
| 663 | 720 |
| 664 function updateModel(model) { | 721 /** |
| 665 document.getElementById('viewport').updateModel(model); | 722 * Function called from C++ to initialize the menu item. |
| 723 * @param {Object} config Configuration parameters in JSON format. | |
| 724 * See chromeos/views/native_menu_webui.cc for details. | |
|
Dan Beam
2012/05/07 17:43:53
nit: remove extra \s or add 3\s, additionally ther
kmadhusu
2012/05/08 20:20:19
Done.
| |
| 725 */ | |
| 726 function init(config) { | |
| 727 $('viewport').init(config); | |
| 666 } | 728 } |
| 667 | 729 |
| 668 function modelUpdated() { | 730 /** |
| 669 chrome.send('model_updated', []); | 731 * Function called from C++ to update menu item model. |
| 732 * @param {Object} model New model object. | |
| 733 */ | |
| 734 function updateModel(model) { | |
| 735 $('viewport').updateModel(model); | |
| 670 } | 736 } |
| 671 | 737 |
| 738 /** | |
| 739 * Function called from C++ to enable scroll on menu item. | |
| 740 * @param {boolean} enabled True if scroll should be enabled on menu item. | |
| 741 */ | |
| 672 function enableScroll(enabled) { | 742 function enableScroll(enabled) { |
| 673 document.getElementById('viewport').scrollEnabled = enabled; | 743 $('viewport').scrollEnabled = enabled; |
| 674 } | 744 } |
| OLD | NEW |