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 3 // found in the LICENSE file. 4 5 cr.define('cr.ui', function() { 6 /** @const */ var Command = cr.ui.Command; 7 8 /** 9 * Creates a new menu item element. 10 * @param {Object=} opt_propertyBag Optional properties. 11 * @constructor 12 * @extends {HTMLDivElement} 13 */ 14 var MenuItem = cr.ui.define('div'); 15 16 /** 17 * Creates a new menu separator element. 18 * @return {cr.ui.MenuItem} The new separator element. 19 */ 20 MenuItem.createSeparator = function() { 21 var el = cr.doc.createElement('hr'); 22 MenuItem.decorate(el); 23 return el; 24 }; 25 26 MenuItem.prototype = { 27 __proto__: HTMLButtonElement.prototype, 28 29 /** 30 * Initializes the menu item. 31 */ 32 decorate: function() { 33 var commandId; 34 if ((commandId = this.getAttribute('command'))) 35 this.command = commandId; 36 37 this.addEventListener('mouseup', this.handleMouseUp_); 38 39 // Adding the 'custom-appearance' class prevents widgets.css from changing 40 // the appearance of this element. 41 this.classList.add('custom-appearance'); 42 }, 43 44 /** 45 * The command associated with this menu item. If this is set to a string 46 * of the form "#element-id" then the element is looked up in the document 47 * of the command. 48 * @type {cr.ui.Command} 49 */ 50 command_: null, 51 get command() { 52 return this.command_; 53 }, 54 set command(command) { 55 if (this.command_) { 56 this.command_.removeEventListener('labelChange', this); 57 this.command_.removeEventListener('disabledChange', this); 58 this.command_.removeEventListener('hiddenChange', this); 59 this.command_.removeEventListener('checkedChange', this); 60 } 61 62 if (typeof command == 'string' && command[0] == '#') { 63 command = this.ownerDocument.getElementById(command.slice(1)); 64 cr.ui.decorate(command, Command); 65 } 66 67 this.command_ = command; 68 if (command) { 69 if (command.id) 70 this.setAttribute('command', '#' + command.id); 71 72 this.label = command.label; 73 this.disabled = command.disabled; 74 this.hidden = command.hidden; 75 76 this.command_.addEventListener('labelChange', this); 77 this.command_.addEventListener('disabledChange', this); 78 this.command_.addEventListener('hiddenChange', this); 79 this.command_.addEventListener('checkedChange', this); 80 } 81 }, 82 83 /** 84 * The text label. 85 * @type {string} 86 */ 87 get label() { 88 return this.textContent; 89 }, 90 set label(label) { 91 this.textContent = label; 92 }, 93 94 /** 95 * @return {boolean} Whether the menu item is a separator. 96 */ 97 isSeparator: function() { 98 return this.tagName == 'HR'; 99 }, 100 101 /** 102 * Handles mouseup events. This dispatches an active event and if there 103 * is an assiciated command then that is executed. 104 * @param {Event} The mouseup event object. 105 * @private 106 */ 107 handleMouseUp_: function(e) { 108 if (!this.disabled && !this.isSeparator() && this.selected) { 109 // Dispatch command event followed by executing the command object. 110 if (cr.dispatchSimpleEvent(this, 'activate', true, true)) { 111 var command = this.command; 112 if (command) 113 command.execute(); 114 } 115 } 116 }, 117 118 /** 119 * Handles changes to the associated command. 120 * @param {Event} e The event object. 121 */ 122 handleEvent: function(e) { 123 switch (e.type) { 124 case 'disabledChange': 125 this.disabled = this.command.disabled; 126 break; 127 case 'hiddenChange': 128 this.hidden = this.command.hidden; 129 break; 130 case 'labelChange': 131 this.label = this.command.label; 132 break; 133 case 'checkedChange': 134 this.checked = this.command.checked; 135 break; 136 } 137 } 138 }; 139 140 /** 141 * Whether the menu item is disabled or not. 142 * @type {boolean} 143 */ 144 cr.defineProperty(MenuItem, 'disabled', cr.PropertyKind.BOOL_ATTR); 145 146 /** 147 * Whether the menu item is hidden or not. 148 * @type {boolean} 149 */ 150 cr.defineProperty(MenuItem, 'hidden', cr.PropertyKind.BOOL_ATTR); 151 152 /** 153 * Whether the menu item is selected or not. 154 * @type {boolean} 155 */ 156 cr.defineProperty(MenuItem, 'selected', cr.PropertyKind.BOOL_ATTR); 157 158 /** 159 * Whether the menu item is checked or not. 160 * @type {boolean} 161 */ 162 cr.defineProperty(MenuItem, 'checked', cr.PropertyKind.BOOL_ATTR); 163 164 // Export 165 return { 166 MenuItem: MenuItem 167 }; 168 }); 169