1 /** 2 * @author Gillis Haasnoot <gillis.haasnoot@gmail.com> 3 * @package Banana.Controls 4 * @summary Dropdown control 5 */ 6 7 goog.provide('Banana.Controls.DataControls.ListControls.DropDown'); 8 9 goog.require('Banana.Controls.DataControls.ListControls.ListControl'); 10 /** 11 * @author Gillis Haasnoot <gillis.haasnoot@gmail.com> 12 * @link www.vivesta.com 13 * @copyright Copyright © 2010 14 * @license xxx 15 * @version 0.0.1 16 * @package Banana.Controls 17 * 18 * Dropdown component 19 * 20 * use setDataSource() to create a a list 21 * use setData() to select indices 22 * 23 */ 24 25 /** @namespace Banana.Controls.DropDown */ 26 namespace('Banana.Controls').DropDown = Banana.Controls.ListControl.extend( 27 /** @lends Banana.Controls.DropDown.prototype */ 28 { 29 /** 30 * Creates a Dropdown 31 * 32 * Example: 33 34 var dropdown = new Banana.Controls.DropDown(); 35 36 this.addControl(dropdown); 37 38 dropdown.setDataSource([1,2,3,4,5,6,7,8,9]); 39 dropdown.setData(4); 40 41 ///another way top populate datasource is with complex objects. 42 //by default complex objects should have a dataKeyField and dataValueField. 43 //where dataKeyField = key and dataValueField = value; 44 //To change this use setDataKeyField and setDataValueField. 45 46 dropdown.setDataSource([{key:1,value:'one'},{key:2,value:'two'}]); 47 dropdown.setData(2); 48 49 * @constructs 50 * @extends Banana.Controls.ListControl 51 */ 52 init : function() 53 { 54 this._super(); 55 56 this.addCssClass('BDropDown'); 57 58 this.optGroupField = "group"; 59 60 this.bind('change',this.getProxy(function(e) 61 { 62 this.setData(Banana.Util.DomHelper.getData(this) || []); 63 this.isChanged = true; 64 this.triggerEvent('selectionChanged'); 65 })); 66 67 // Prevent propagation of event, because parent controls, e.g. 68 // a datagrid row, can capture this event in Chrome and prevent 69 // it from functioning. 70 this.bind('mousedown', function(e) { 71 e.stopPropagation(); 72 }); 73 }, 74 75 /** 76 * @override 77 * @ignore 78 */ 79 updateDisplay: function() 80 { 81 this._super(); 82 83 // This is a Chrome Fix 84 // Chrome can set the DropDown selected index to -1 showing an empty 85 // option in the browser. When found reset the index to 0. only when prompt text is set 86 if (!this.getPromptText()) return; 87 88 if (this.isRendered) { 89 var obj = jQuery('#' + this.getClientId())[0]; 90 if (obj && obj.selectedIndex == -1) 91 obj.selectedIndex = 0; 92 } 93 }, 94 95 /** 96 * @return {mixed} 97 */ 98 getData : function() 99 { 100 return (this._super() == '__prompt__' ? undefined : this._super()) 101 }, 102 103 /** 104 * Set the data of the Control 105 * 106 * @param {mixed} data Data to set 107 * @return {this} 108 */ 109 setData: function(data) 110 { 111 // When data is not available and prompttext is set select 112 // the prompttext in the dropdown 113 if ((data === null || data === undefined) && this.getPromptText()) { 114 data = '__prompt__'; 115 } 116 return this._super(data); 117 }, 118 119 /** 120 * Sets the data by index. 121 * If your datasource is ["foo","apple","me"] you can use setDataByIndex(1) to 122 * set apple as the data. 123 * 124 * @param {int} index 125 * @return {this} 126 */ 127 setDataByIndex : function(index) 128 { 129 var i = 0; 130 for(var prop in this.datasource) 131 { 132 if (typeof(this.datasource[prop]) == 'function') continue; 133 134 if (i==index) 135 { 136 if (this.datasource[prop][this.dataKeyField]) 137 { 138 this.setData(this.datasource[prop][this.dataKeyField]); 139 } 140 else 141 { 142 this.setData(prop); 143 } 144 break; 145 } 146 i++; 147 } 148 149 return this; 150 } 151 }); 152 153 /** 154 * @return {String} 155 */ 156 Banana.Controls.DropDown.prototype.getTagName = function() 157 { 158 return 'select'; 159 }; 160 161 /** 162 * we override the get html function to manualy render the <option> tags 163 * instead of this method we can create an <option> class, but it will cause some 164 * overhead in very large lists. So for optimal result we handle this way 165 * 166 * @ignore 167 */ 168 Banana.Controls.DropDown.prototype.getHtml = function() 169 { 170 var html = []; 171 172 html.push('<'+this.getTagName()+' '); 173 html.push(this.getHtmlAttributes()); 174 html.push('>') 175 176 var datasource = this.datasource; 177 178 if (this.getPromptText()) 179 { 180 html.push(this.getOption('__prompt__',this.getPromptText())); 181 } 182 183 var prevOptGroup = null; 184 var add = false; 185 186 for(var prop in datasource) 187 { 188 //stupid prototype adds functions to array prototype 189 if (typeof(datasource[prop]) == 'function') continue; 190 191 if (typeof(datasource[prop]) == 'object') 192 { 193 if (!datasource[prop]) {continue;} 194 195 var optGroup = datasource[prop]['group']; 196 var key = datasource[prop][this.dataKeyField]; 197 var value = datasource[prop][this.dataValueField]; 198 199 for (var x = 0; x < datasource[prop][this.dataDepthField]; x++) { 200 value = " " + value; 201 } 202 203 if (optGroup != prevOptGroup) 204 { 205 html.push('<optgroup label="'+optGroup+'">'); 206 add = true; 207 } 208 209 html.push(this.getOption(key,value)); 210 211 if (!add && optGroup != prevOptGroup) 212 { 213 html.push('</optgroup>'); 214 add = false; 215 } 216 217 prevOptGroup = optGroup; 218 } 219 else 220 { 221 var value = prop; 222 223 if (datasource instanceof Array) 224 { 225 value = datasource[prop]; 226 } 227 228 html.push(this.getOption(value,datasource[prop])); 229 } 230 231 } 232 233 html.push('</'+this.getTagName()+'>'); 234 return html.join(''); 235 }; 236 237 /** 238 * Sets the prompt text. This text is visible as first option in the dropdown. 239 * Note that a prompt text doesnt have a value. calling getData() while prompttext is selected 240 * results in undefined 241 * 242 * @param {String} text 243 * @return {this} 244 */ 245 Banana.Controls.DropDown.prototype.setPromptText = function(text) 246 { 247 this.promptText = text; 248 return this; 249 }; 250 251 /** 252 * @return {String} 253 */ 254 Banana.Controls.DropDown.prototype.getPromptText = function() 255 { 256 return this.promptText; 257 }; 258 259 /** 260 * Sets the optgroup 261 * @param {String} value 262 * @return {this} 263 */ 264 Banana.Controls.DropDown.prototype.setOptGroupField = function(value) 265 { 266 this.optGroupField = value; 267 return this; 268 }; 269 270 /** 271 * @return {String} 272 */ 273 Banana.Controls.DropDown.prototype.getOptGroupField = function() 274 { 275 return this.optGroupField; 276 }; 277 278 /** 279 * When called we use opt grouping. By default the optgroup field is "group" 280 * @return {this} 281 */ 282 Banana.Controls.DropDown.useOptGrouping = function() 283 { 284 this.optGrouping = true; 285 return this; 286 }, 287 288 /** 289 * used to render a option line 290 * 291 * @param {String} value 292 * @param {String} key 293 * @ignore 294 * @return {String} 295 */ 296 Banana.Controls.DropDown.prototype.getOption = function(value,key) 297 { 298 var selected = ''; 299 300 if (this.data == value || (value == '__prompt__' && this.data == undefined)) 301 { 302 selected = 'selected=selected'; 303 } 304 return '<option '+selected+' class="BDropDownOption" value="'+value+'">'+key+'</option>'; 305 }; 306 307 /** 308 * used to render a option line with optgrouping enabled 309 * @param {String} value 310 * @param {String} key 311 * @ignore 312 * @return {this} 313 */ 314 Banana.Controls.DropDown.prototype.getOptGroup = function(value,key) 315 { 316 var selected = ''; 317 318 if (this.getData() == value) 319 { 320 selected = 'selected=selected'; 321 } 322 return '<option '+selected+' class="BDropDownOption" value="'+value+'">'+key+'</option>'; 323 };