1 if(!dojo._hasResource["dojox.form.DropDownSelect"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2 dojo._hasResource["dojox.form.DropDownSelect"] = true;
3 dojo.provide("dojox.form.DropDownSelect");
5 dojo.require("dijit.form.Button");
6 dojo.require("dijit.Menu");
8 dojo.require("dojo.data.ItemFileWriteStore");
10 dojo.declare("dojox.form.DropDownSelect", dijit.form.DropDownButton, {
12 // This is a "Styleable" select box - it is basically a DropDownButton which
13 // can take as its input a <select>.
15 baseClass: "dojoxDropDownSelect",
18 dojox.form.__SelectOption = function(){
20 // The value of the option. Setting to empty (or missing) will
21 // place a separator at that location
23 // The label for our option. It can contain html tags.
29 // options: dojox.form.__SelectOption[]
34 // What to display in an "empty" dropdown
37 // _isPopulated: boolean
38 // Whether or not we have been populated
41 _addMenuItem: function(/* dojox.form.__SelectOption */ option){
43 // For the given option, add a menu item to our dropdown
44 // If the option doesn't have a value, then a separator is added
46 var menu = this.dropDown;
49 // We are a separator (no label set for it)
50 menu.addChild(new dijit.MenuSeparator());
52 // Just a regular menu option
53 var click = dojo.hitch(this, "setAttribute","value",option);
54 var mi = new dijit.MenuItem({
55 id: this.id + "_item_" + option.value,
64 _resetButtonState: function(){
66 // Resets the menu and the length attribute of the button - and
67 // ensures that the label is appropriately set.
68 var len = this.options.length;
70 // reset the menu to make it "populatable on the next click
71 var dropDown = this.dropDown;
72 dojo.forEach(dropDown.getChildren(), function(child){
73 child.destroyRecursive();
75 this._isPopulated = false;
77 // Set our length attribute and our value
78 this.setAttribute("readOnly", (len === 1));
79 this.setAttribute("disabled", (len === 0));
80 this.setAttribute("value", this.value);
83 _updateSelectedState: function(){
85 // Sets the "selected" class on the item for styling purposes
88 var testId = this.id + "_item_" + val;
89 dojo.forEach(this.dropDown.getChildren(), function(child){
90 dojo[child.id === testId ? "addClass" : "removeClass"](child.domNode,
91 this.baseClass + "SelectedOption");
96 addOption: function(/* dojox.form.__SelectOption or string, optional */ value, /* string? */ label){
98 // Adds an option to the end of the select. If value is empty or
99 // missing, a separator is created instead.
101 this.options.push(value.value ? value : { value:value, label:label });
104 removeOption: function(/* string, dojox.form.__SelectOption or number */ valueOrIdx){
106 // Removes the given option
107 this.options = dojo.filter(this.options, function(node, idx){
108 return !((typeof valueOrIdx === "number" && idx === valueOrIdx) ||
109 (typeof valueOrIdx === "string" && node.value === valueOrIdx) ||
110 (valueOrIdx.value && node.value === valueOrIdx.value));
114 setOptionLabel: function(/*string*/ value, /*string*/ label){
115 dojo.forEach(this.options, function(node){
116 if(node.value === value){
124 // Clear out an outstanding hack handle
125 if(this._labelHackHandle){
126 clearTimeout(this._labelHackHandle);
128 this.inherited(arguments);
131 setLabel: function(/* string */ content){
133 // Wraps our label in a div - that way, our rich text can work
136 content = '<div class=" ' + this.baseClass + 'Label">' +
139 // Because FF2 has a problem with layout, we need to delay this
141 if(this._labelHackHandle){
142 clearTimeout(this._labelHackHandle);
145 this._labelHackHandle = setTimeout(dojo.hitch(this, function(){
146 this._labelHackHandle = null;
147 dijit.form.DropDownButton.prototype.setLabel.call(this, content);
150 this.inherited(arguments);
154 setAttribute: function(/*string*/ attr, /* anything */ value){
155 // summary: sometime we get called to set our value - we need to
156 // make sure and route those requests through _setValue()
158 if(attr === "value"){
159 // If a string is passed, then we set our value from looking it up.
160 if(typeof value === "string"){
161 value = dojo.filter(this.options, function(node){
162 return node.value === value;
166 // If we don't have a value, try to show the first item
168 value = this.options[0] || { value: "", label: "" };
170 this.value = value.value;
172 this.setLabel(value.label || this.emptyLabel || " ");
174 this._handleOnChange(value.value);
177 this.inherited(arguments);
181 _fillContent: function(){
183 // Loads our options and sets up our dropdown correctly. We
184 // don't want any content, so we don't call any inherit chain
186 var opts = this.options;
188 opts = this.options = this.srcNodeRef ? dojo.query(">",
189 this.srcNodeRef).map(function(node){
190 if(node.getAttribute("type") === "separator"){
191 return { value: "", label: "" };
193 return { value: node.getAttribute("value"),
194 label: String(node.innerHTML) };
198 // Set the value to be the first, or the selected index
199 if(opts.length && !this.value){
200 var si = this.srcNodeRef.selectedIndex;
201 this.value = opts[si != -1 ? si : 0].value;
204 // Create the dropDown widget
205 this.dropDown = new dijit.Menu();
208 postCreate: function(){
209 // summary: sets up our event handling that we need for functioning
212 this.inherited(arguments);
214 // Make our event connections for updating state
216 dojo[this._opened ? "addClass" : "removeClass"](this.focusNode,
217 this.baseClass + "ButtonOpened");
219 this.connect(this, "_openDropDown", fx);
220 this.connect(this, "_closeDropDown", fx);
221 this.connect(this, "onChange", "_updateSelectedState");
222 this.connect(this, "addOption", "_resetButtonState");
223 this.connect(this, "removeOption", "_resetButtonState");
224 this.connect(this, "setOptionLabel", "_resetButtonState");
229 // FF2 has layout problems if the reset call isn't done on a
231 this.inherited(arguments);
233 setTimeout(dojo.hitch(this, this._resetButtonState), 0);
235 this._resetButtonState();
239 _populate: function(/* function */ callback){
241 // populates the menu (and does the callback, if passed)
243 var dropDown = this.dropDown;
245 // Add each menu item
246 dojo.forEach(this.options, this._addMenuItem, this);
249 this._updateSelectedState();
250 dojo.addClass(this.dropDown.domNode, this.baseClass + "Menu");
251 this._isPopulated = true;
252 if(callback){ callback.call(this); }
255 _toggleDropDown: function(){
256 // summary: Overrides DropDownButton's toggle function to make sure
257 // that the values are correctly populated.
258 var dropDown = this.dropDown;
259 if(dropDown && !dropDown.isShowingNow && !this._isPopulated){
260 this._populate(dojox.form.DropDownSelect.superclass._toggleDropDown);
262 this.inherited(arguments);