1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch/** 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @fileoverview A command is an abstraction of an action a user can do in the 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * UI. 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * When the focus changes in the document for each command a canExecute event 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * is dispatched on the active element. By listening to this event you can 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * enable and disable the command by setting the event.canExecute property. 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * When a command is executed a command event is dispatched on the active 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * element. Note that you should stop the propagation after you have handled the 15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * command if there might be other command listeners higher up in the DOM tree. 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochcr.define('cr.ui', function() { 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * This is used to identify keyboard shortcuts. 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {string} shortcut The text used to describe the keys for this 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * keyboard shortcut. 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @constructor 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch function KeyboardShortcut(shortcut) { 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var mods = {}; 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var ident = ''; 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut.split('-').forEach(function(part) { 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var partLc = part.toLowerCase(); 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switch (partLc) { 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case 'alt': 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case 'ctrl': 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case 'meta': 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case 'shift': 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch mods[partLc + 'Key'] = true; 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default: 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (ident) 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch throw Error('Invalid shortcut'); 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ident = part; 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }); 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.ident_ = ident; 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.mods_ = mods; 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch KeyboardShortcut.prototype = { 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Wether the keyboard shortcut object mathes a keyboard event. 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {!Event} e The keyboard event object. 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @return {boolean} Whether we found a match or not. 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch matchesEvent: function(e) { 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (e.keyIdentifier == this.ident_) { 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // All keyboard modifiers needs to match. 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var mods = this.mods_; 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return ['altKey', 'ctrlKey', 'metaKey', 'shiftKey'].every(function(k) { 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return e[k] == !!mods[k]; 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }); 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }; 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Creates a new command element. 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @constructor 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @extends {HTMLElement} 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var Command = cr.ui.define('command'); 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Command.prototype = { 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch __proto__: HTMLElement.prototype, 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Initializes the command. 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch decorate: function() { 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CommandManager.init(this.ownerDocument); 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Executes the command. This dispatches a command event on the active 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * element. If the command is {@code disabled} this does nothing. 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch execute: function() { 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (this.disabled) 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var doc = this.ownerDocument; 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (doc.activeElement) { 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var e = new cr.Event('command', true, false); 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch e.command = this; 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch doc.activeElement.dispatchEvent(e); 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Call this when there have been changes that might change whether the 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * command can be executed or not. 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch canExecuteChange: function() { 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch dispatchCanExecuteEvent(this, this.ownerDocument.activeElement); 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * The keyboard shortcut that triggers the command. This is a string 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * consisting of a keyIdentifier (as reported by WebKit in keydown) as 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * well as optional key modifiers joinded with a '-'. 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Multiple keyboard shortcuts can be provided by separating them by 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * whitespace. 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * For example: 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * "F1" 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * "U+0008-Meta" for Apple command backspace. 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * "U+0041-Ctrl" for Control A 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * "U+007F U+0008-Meta" for Delete and Command Backspace 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @type {string} 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_: '', 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch get shortcut() { 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return this.shortcut_; 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch set shortcut(shortcut) { 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var oldShortcut = this.shortcut_; 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (shortcut !== oldShortcut) { 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.keyboardShortcuts_ = shortcut.split(/\s+/).map(function(shortcut) { 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return new KeyboardShortcut(shortcut); 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }); 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Set this after the keyboardShortcuts_ since that might throw. 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.shortcut_ = shortcut; 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cr.dispatchPropertyChange(this, 'shortcut', this.shortcut_, 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch oldShortcut); 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Whether the event object matches the shortcut for this command. 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {!Event} e The key event object. 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @return {boolean} Whether it matched or not. 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch matchesEvent: function(e) { 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!this.keyboardShortcuts_) 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return this.keyboardShortcuts_.some(function(keyboardShortcut) { 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return keyboardShortcut.matchesEvent(e); 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }); 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }; 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * The label of the command. 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @type {string} 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cr.defineProperty(Command, 'label', cr.PropertyKind.ATTR); 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Whether the command is disabled or not. 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @type {boolean} 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cr.defineProperty(Command, 'disabled', cr.PropertyKind.BOOL_ATTR); 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Whether the command is hidden or not. 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @type {boolean} 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cr.defineProperty(Command, 'hidden', cr.PropertyKind.BOOL_ATTR); 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 1753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick * Whether the command is checked or not. 1763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick * @type {boolean} 1773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick */ 1783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick cr.defineProperty(Command, 'checked', cr.PropertyKind.BOOL_ATTR); 1793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick /** 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Dispatches a canExecute event on the target. 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {cr.ui.Command} command The command that we are testing for. 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {Element} target The target element to dispatch the event on. 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch function dispatchCanExecuteEvent(command, target) { 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var e = new CanExecuteEvent(command, true) 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch target.dispatchEvent(e); 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch command.disabled = !e.canExecute; 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * The command managers for different documents. 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var commandManagers = {}; 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Keeps track of the focused element and updates the commands when the focus 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * changes. 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {!Document} doc The document that we are managing the commands for. 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @constructor 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch function CommandManager(doc) { 2033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick doc.addEventListener('focus', this.handleFocus_.bind(this), true); 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make sure we add the listener to the bubbling phase so that elements can 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // prevent the command. 2063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick doc.addEventListener('keydown', this.handleKeyDown_.bind(this), false); 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Initializes a command manager for the document as needed. 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {!Document} doc The document to manage the commands for. 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CommandManager.init = function(doc) { 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var uid = cr.getUid(doc); 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!(uid in commandManagers)) { 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch commandManagers[uid] = new CommandManager(doc); 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CommandManager.prototype = { 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Handles focus changes on the document. 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {Event} e The focus event object. 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @private 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch handleFocus_: function(e) { 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var target = e.target; 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var commands = Array.prototype.slice.call( 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch target.ownerDocument.querySelectorAll('command')); 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch commands.forEach(function(command) { 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch dispatchCanExecuteEvent(command, target); 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }); 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Handles the keydown event and routes it to the right command. 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {!Event} e The keydown event. 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch handleKeyDown_: function(e) { 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var target = e.target; 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var commands = Array.prototype.slice.call( 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch target.ownerDocument.querySelectorAll('command')); 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (var i = 0, command; command = commands[i]; i++) { 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!command.disabled && command.matchesEvent(e)) { 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch e.preventDefault(); 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We do not want any other element to handle this. 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch e.stopPropagation(); 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch command.execute(); 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }; 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * The event type used for canExecute events. 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {!cr.ui.Command} command The command that we are evaluating. 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @extends {Event} 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch function CanExecuteEvent(command) { 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var e = command.ownerDocument.createEvent('Event'); 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch e.initEvent('canExecute', true, false); 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch e.__proto__ = CanExecuteEvent.prototype; 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch e.command = command; 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return e; 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CanExecuteEvent.prototype = { 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch __proto__: Event.prototype, 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * The current command 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @type {cr.ui.Command} 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch command: null, 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Whether the target can execute the command. Setting this also stops the 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * propagation. 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @type {boolean} 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch canExecute_: false, 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch get canExecute() { 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return this.canExecute_; 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch set canExecute(canExecute) { 2913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick this.canExecute_ = !!canExecute; 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.stopPropagation(); 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }; 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Export 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return { 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Command: Command, 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CanExecuteEvent: CanExecuteEvent 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }; 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}); 302