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 'use strict'; 6 7 /** 8 * @fileoverview This implements a combobutton control. 9 */ 10 11 cr.define('cr.ui', function() { 12 /** 13 * Creates a new combobutton element. 14 * @param {Object=} opt_propertyBag Optional properties. 15 * @constructor 16 * @extends {HTMLUListElement} 17 */ 18 var ComboButton = cr.ui.define(cr.ui.MenuButton); 19 20 21 ComboButton.prototype = { 22 __proto__: cr.ui.MenuButton.prototype, 23 24 defaultItem_: null, 25 26 /** 27 * Truncates drop-down list. 28 */ 29 clear: function() { 30 this.menu.clear(); 31 this.multiple = false; 32 }, 33 34 addDropDownItem: function(item) { 35 this.multiple = true; 36 var menuitem = this.menu.addMenuItem(item); 37 menuitem.data = item; 38 if (item.iconType) { 39 menuitem.style.backgroundImage = ''; 40 menuitem.setAttribute('file-type-icon', item.iconType); 41 } 42 if (item.bold) { 43 menuitem.style.fontWeight = 'bold'; 44 } 45 return menuitem; 46 }, 47 48 /** 49 * Adds separator to drop-down list. 50 */ 51 addSeparator: function() { 52 this.menu.addSeparator(); 53 }, 54 55 /** 56 * Default item to fire on combobox click 57 */ 58 get defaultItem() { 59 return this.defaultItem_; 60 }, 61 set defaultItem(defaultItem) { 62 this.defaultItem_ = defaultItem; 63 64 this.actionNode_.textContent = defaultItem.label || ''; 65 66 if (defaultItem.iconType) { 67 this.actionNode_.style.backgroundImage = ''; 68 this.actionNode_.setAttribute('file-type-icon', defaultItem.iconType); 69 } else if (defaultItem.iconUrl) { 70 this.actionNode_.style.backgroundImage = 71 'url(' + defaultItem.iconUrl + ')'; 72 } else { 73 this.actionNode_.style.backgroundImage = ''; 74 } 75 }, 76 77 /** 78 * Initializes the element. 79 */ 80 decorate: function() { 81 cr.ui.MenuButton.prototype.decorate.call(this); 82 83 this.classList.add('combobutton'); 84 85 this.actionNode_ = this.ownerDocument.createElement('div'); 86 this.actionNode_.classList.add('action'); 87 this.appendChild(this.actionNode_); 88 89 var triggerIcon = this.ownerDocument.createElement('span'); 90 triggerIcon.className = 'disclosureindicator'; 91 this.trigger_ = this.ownerDocument.createElement('div'); 92 this.trigger_.classList.add('trigger'); 93 this.trigger_.appendChild(triggerIcon); 94 95 this.appendChild(this.trigger_); 96 97 this.addEventListener('click', this.handleButtonClick_.bind(this)); 98 99 this.trigger_.addEventListener('click', 100 this.handleTriggerClicked_.bind(this)); 101 102 this.menu.addEventListener('activate', 103 this.handleMenuActivate_.bind(this)); 104 105 // Remove mousedown event listener created by MenuButton::decorate, 106 // and move it down to trigger_. 107 this.removeEventListener('mousedown', this); 108 this.trigger_.addEventListener('mousedown', this); 109 }, 110 111 /** 112 * Handles the keydown event for the menu button. 113 */ 114 handleKeyDown: function(e) { 115 switch (e.keyIdentifier) { 116 case 'Down': 117 case 'Up': 118 if (!this.isMenuShown()) 119 this.showMenu(); 120 e.preventDefault(); 121 break; 122 case 'Esc': 123 case 'U+001B': // Maybe this is remote desktop playing a prank? 124 this.hideMenu(); 125 break; 126 } 127 }, 128 129 handleTriggerClicked_: function(event) { 130 event.stopPropagation(); 131 }, 132 133 handleMenuActivate_: function(event) { 134 this.dispatchSelectEvent(event.target.data); 135 }, 136 137 handleButtonClick_: function() { 138 this.dispatchSelectEvent(this.defaultItem_); 139 }, 140 141 dispatchSelectEvent: function(item) { 142 var selectEvent = new Event('select'); 143 selectEvent.item = item; 144 this.dispatchEvent(selectEvent); 145 } 146 }; 147 148 cr.defineProperty(ComboButton, 'disabled', cr.PropertyKind.BOOL_ATTR); 149 cr.defineProperty(ComboButton, 'multiple', cr.PropertyKind.BOOL_ATTR); 150 151 return { 152 ComboButton: ComboButton 153 }; 154 }); 155