| 27 | | // _numSeps: number |
| 28 | | // The number of separator we have added (to ensure uniqueness) |
| 29 | | _numSeps: 0, |
| 30 | | |
| 31 | | _addMenuItem: function(/* item */ item){ |
| 32 | | // summary: |
| 33 | | // For the given datastore item, add a menu item to our dropdown |
| 34 | | // If the item doesn't have a label (or if the label is an empty |
| 35 | | // string), then a separator is added in that place. |
| 36 | | var store = this.store, menu = this.dropDown; |
| 37 | | |
| 38 | | // Check that our item is loaded |
| 39 | | if(!store.isItemLoaded(item)){ |
| 40 | | store.loadItem({item: item, |
| 41 | | onComplete: function(i){ |
| 42 | | this._addMenuItem(i); |
| 43 | | }, |
| 44 | | onError: function(e){throw e;}, |
| 45 | | scope: this}); |
| 46 | | return; |
| 47 | | } |
| 48 | | if(!store.getLabel(item)){ |
| | 39 | _addMenuItem: function(/* dojox.form.__SelectOption */ option){ |
| | 40 | // summary: |
| | 41 | // For the given option, add a menu item to our dropdown |
| | 42 | // If the option doesn't have a value, then a separator is added |
| | 43 | // in that place. |
| | 44 | var menu = this.dropDown; |
| | 45 | |
| | 46 | if(!option.value){ |
| 70 | | }, |
| 71 | | |
| 72 | | _initializeDropdown: function(/* item or string, optional */ selected){ |
| 73 | | // summary: |
| 74 | | // Initializes the dropdown after a store has been set (or on |
| 75 | | // postcreate) |
| 76 | | this._setValue(selected); |
| 77 | | this.store.fetch({onComplete: function(items){ |
| 78 | | var len = items.length; |
| 79 | | this.setAttribute("readOnly", (len === 1)); |
| 80 | | this.setAttribute("disabled", (len === 0)); |
| 81 | | }, |
| 82 | | scope: this}); |
| 83 | | }, |
| 84 | | |
| | 71 | |
| | 72 | // Set our length attribute and our value |
| | 73 | this.setAttribute("readOnly", (len === 1)); |
| | 74 | this.setAttribute("disabled", (len === 0)); |
| | 75 | this.setAttribute("value", this.value); |
| | 76 | }, |
| | 77 | |
| 98 | | addOption: function(/* string? */ value, /* string? */ label){ |
| 99 | | // summary: |
| 100 | | // Adds an option to the end of the select. If either value or |
| 101 | | // label are empty or missing, a separator is created instead. |
| 102 | | var store = this.store; |
| 103 | | if(!store.getFeatures()["dojo.data.api.Write"]){ |
| 104 | | throw new Error("Cannot add or remove options from a non-writeable store"); |
| 105 | | } |
| 106 | | if(!value || !label){ |
| 107 | | // create a separator |
| 108 | | this._numSeps++; |
| 109 | | store.newItem({value: ("_separator-" + this._numSeps), name: ""}); |
| 110 | | }else{ |
| 111 | | store.newItem({value: value, name: label}); |
| 112 | | } |
| 113 | | }, |
| 114 | | |
| 115 | | removeOption: function(/* string or number */ valueOrIdx){ |
| 116 | | // summary: |
| 117 | | // Removes an option at the given value (if valueOrIndex is a |
| 118 | | // string) or at the given index in the menu (if valueOrIndex is |
| 119 | | // a number) |
| 120 | | var store = this.store; |
| 121 | | if(!store.getFeatures()["dojo.data.api.Write"]){ |
| 122 | | throw new Error("Cannot add or remove options from a non-writeable store"); |
| 123 | | } |
| 124 | | var allItems = function(items){ |
| 125 | | if(items[valueOrIdx]){ |
| 126 | | store.deleteItem(items[valueOrIdx]); |
| 127 | | } |
| 128 | | }; |
| 129 | | if(typeof valueOrIdx === "number"){ |
| 130 | | // Remove by index |
| 131 | | store.fetch({onComplete: allItems}); |
| 132 | | }else if(typeof valueOrIdx === "string") { |
| 133 | | // Remove by id |
| 134 | | store.fetchItemByIdentity({identity: valueOrIdx, |
| 135 | | onItem: store.deleteItem, |
| 136 | | scope: store}); |
| 137 | | }else{ |
| 138 | | // Try to just remove it (in case we happened to be passed an |
| 139 | | // item |
| 140 | | store.deleteItem(valueOrIdx); |
| 141 | | } |
| 142 | | }, |
| 143 | | |
| 144 | | _setValue: function(/* item or string, optional */ value){ |
| 145 | | // summary: |
| 146 | | var store = this.store; |
| 147 | | |
| 148 | | // If a string is passed, then we set our value from looking it up |
| 149 | | // as the identity |
| 150 | | if(typeof value == "string" && value){ |
| 151 | | store.fetchItemByIdentity({identity: value, |
| 152 | | onItem: this._setValue, |
| 153 | | scope: this}); |
| 154 | | return; |
| 155 | | } |
| 156 | | |
| 157 | | // If we don't have a value, try to show the first item |
| 158 | | if(!value){ |
| 159 | | var cb = function(items){ |
| 160 | | if(items.length){ |
| 161 | | this._setValue(items[0]); |
| 162 | | }else{ |
| 163 | | this.value = ""; |
| 164 | | this._handleOnChange(this.value); |
| 165 | | this.setLabel(this.emptyLabel || " "); |
| 166 | | } |
| 167 | | }; |
| 168 | | store.fetch({onComplete: cb, scope: this}); |
| 169 | | return; |
| 170 | | } |
| 171 | | |
| 172 | | // We have a value, and we're an item - so load it and set from |
| 173 | | // that. |
| 174 | | var onItem = dojo.hitch(this, function(i){ |
| 175 | | this.value = store.getIdentity(i); |
| 176 | | this._handleOnChange(this.value); |
| 177 | | this.setLabel(store.getLabel(i)); |
| | 91 | addOption: function(/* dojox.form.__SelectOption or string, optional */ value, /* string? */ label){ |
| | 92 | // summary: |
| | 93 | // Adds an option to the end of the select. If value is empty or |
| | 94 | // missing, a separator is created instead. |
| | 95 | |
| | 96 | this.options.push(value.value ? value : {value:value, label:label}); |
| | 97 | }, |
| | 98 | |
| | 99 | removeOption: function(/* string, dojox.form.__SelectOption or number */ valueOrIdx){ |
| | 100 | // summary: |
| | 101 | // Removes the given option |
| | 102 | this.options = dojo.filter(this.options, function(i, idx){ |
| | 103 | return !((typeof valueOrIdx === "number" && idx === valueOrIdx) || |
| | 104 | (typeof valueOrIdx === "string" && i.value === valueOrIdx) || |
| | 105 | (valueOrIdx.value && i.value === valueOrIdx.value)); |
| 179 | | if(store.isItem(value) && store.isItemLoaded(value)){ |
| 180 | | onItem(value); |
| 181 | | }else if(store.isItem(value)) { |
| 182 | | store.loadItem({item: value, onItem: onItem}); |
| 183 | | } |
| 184 | | }, |
| 185 | | |
| 186 | | setAttribute: function(attr, value){ |
| | 107 | }, |
| | 108 | |
| | 109 | destroy: function(){ |
| | 110 | // summary: |
| | 111 | // Clear out an outstanding hack handle |
| | 112 | if(this._labelHackHandle){ |
| | 113 | clearTimeout(this._labelHackHandle); |
| | 114 | } |
| | 115 | this.inherited(arguments); |
| | 116 | }, |
| | 117 | |
| | 118 | setLabel: function(/* string */ content){ |
| | 119 | // summary: |
| | 120 | // Wraps our label in a div - that way, our rich text can work |
| | 121 | // correctly. |
| | 122 | |
| | 123 | content = '<div class=" ' + this.baseClass + 'Label">' + |
| | 124 | content + |
| | 125 | '</div>'; |
| | 126 | // Because FF2 has a problem with layout, we need to delay this |
| | 127 | // call for it. |
| | 128 | if(this._labelHackHandle){ |
| | 129 | clearTimeout(this._labelHackHandle); |
| | 130 | } |
| | 131 | if(dojo.isFF === 2){ |
| | 132 | this._labelHackHandle = setTimeout(dojo.hitch(this, function(){ |
| | 133 | this._labelHackHandle = null; |
| | 134 | dijit.form.DropDownButton.prototype.setLabel.call(this, content); |
| | 135 | }), 0); |
| | 136 | }else{ |
| | 137 | this.inherited(arguments); |
| | 138 | } |
| | 139 | }, |
| | 140 | |
| | 141 | setAttribute: function(/*string*/ attr, /* anything */ value){ |
| 191 | | this._setValue(value); |
| 192 | | return; |
| 193 | | } |
| 194 | | this.inherited(arguments); |
| 195 | | }, |
| 196 | | |
| 197 | | postMixInProperties: function(){ |
| 198 | | // summary: Loads our store and sets up our dropdown correctly |
| 199 | | |
| 200 | | if(!this.store){ |
| 201 | | var items = this.srcNodeRef ? dojo.query(">", |
| | 146 | // If a string is passed, then we set our value from looking it up. |
| | 147 | if(typeof value === "string"){ |
| | 148 | value = dojo.filter(this.options, function(i){ |
| | 149 | return i.value === value; |
| | 150 | })[0]; |
| | 151 | } |
| | 152 | |
| | 153 | // If we don't have a value, try to show the first item |
| | 154 | if(!value){ |
| | 155 | value = this.options[0] || {value: "", label: ""}; |
| | 156 | } |
| | 157 | this.value = value.value; |
| | 158 | if(this._started) |
| | 159 | this.setLabel(value.label||this.emptyLabel||" "); |
| | 160 | this._handleOnChange(value.value); |
| | 161 | value = this.value; |
| | 162 | }else{ |
| | 163 | this.inherited(arguments); |
| | 164 | } |
| | 165 | }, |
| | 166 | |
| | 167 | _fillContent: function(){ |
| | 168 | // summary: |
| | 169 | // Loads our options and sets up our dropdown correctly. We |
| | 170 | // don't want any content, so we don't call any inherit chain |
| | 171 | // function. |
| | 172 | var opts = this.options; |
| | 173 | if(!opts){ |
| | 174 | opts = this.options = this.srcNodeRef ? dojo.query(">", |
| 211 | | this.store = new dojo.data.ItemFileWriteStore({data: { |
| 212 | | identifier: "value", |
| 213 | | label: "name", |
| 214 | | items: items}}); |
| 215 | | |
| 216 | | // Set the value to be the first, or the selected index |
| 217 | | if(items && items.length && !this.value){ |
| 218 | | var si = this.srcNodeRef.selectedIndex; |
| 219 | | this.value = items[si != -1 ? si : 0].value; |
| 220 | | } |
| 221 | | } |
| 222 | | this.inherited(arguments); |
| 223 | | dojo.place(dojo.doc.createElement("span"), this.srcNodeRef, "first"); |
| | 182 | } |
| | 183 | |
| | 184 | // Set the value to be the first, or the selected index |
| | 185 | if(opts.length && !this.value){ |
| | 186 | var si = this.srcNodeRef.selectedIndex; |
| | 187 | this.value = opts[si != -1 ? si : 0].value; |
| | 188 | } |
| | 189 | |
| | 190 | // Create the dropDown widget |
| | 191 | this.dropDown = new dijit.Menu(); |
| 260 | | // Re-fetch (or fetch) our items, and create MenuItems for them |
| 261 | | this.store.fetch({ |
| 262 | | onItem: this._addMenuItem, |
| 263 | | onComplete: function(){ |
| 264 | | // Flag as populated and call the callback (if needed) |
| 265 | | this._updateSelectedState(); |
| 266 | | dojo.addClass(this.dropDown.domNode, this.baseClass + "Menu"); |
| 267 | | this._isPopulated = true; |
| 268 | | if(callback){ callback.call(this); } |
| 269 | | }, |
| 270 | | scope: this |
| 271 | | }); |
| 272 | | }, |
| 273 | | |
| 274 | | _onNewItem: function(/* item */ item, /* Object? */ parentInfo){ |
| 275 | | // summary: Called when a new item is added to our store |
| 276 | | this._resetMenu(); |
| 277 | | this._initializeDropdown(this.value); |
| 278 | | }, |
| 279 | | |
| 280 | | _onSetItem: function(/* item */ item){ |
| 281 | | // summary: Called when an item has been set |
| 282 | | this._resetMenu(); |
| 283 | | if(this.store.getIdentity(item) === this.value){ |
| 284 | | this.setLabel(this.store.getLabel(item)); |
| 285 | | } |
| 286 | | }, |
| 287 | | |
| 288 | | _onDeleteItem: function(/* item */ item){ |
| 289 | | // summary: Called when an item has been deleted from our store |
| 290 | | this._resetMenu(); |
| 291 | | if(this.store.getIdentity(item) === this.value){ |
| 292 | | this._initializeDropdown(""); |
| 293 | | } |
| | 230 | // Add each menu item |
| | 231 | dojo.forEach(this.options, this._addMenuItem, this); |
| | 232 | |
| | 233 | // Update states |
| | 234 | this._updateSelectedState(); |
| | 235 | dojo.addClass(this.dropDown.domNode, this.baseClass + "Menu"); |
| | 236 | this._isPopulated = true; |
| | 237 | if(callback){ callback.call(this); } |