source: Dev/trunk/src/client/dijit/form/_FormSelectWidget.js

Last change on this file was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 24.5 KB
Line 
1define([
2        "dojo/_base/array", // array.filter array.forEach array.map array.some
3        "dojo/_base/Deferred",
4        "dojo/aspect", // aspect.after
5        "dojo/data/util/sorter", // util.sorter.createSortFunction
6        "dojo/_base/declare", // declare
7        "dojo/dom", // dom.setSelectable
8        "dojo/dom-class", // domClass.toggle
9        "dojo/_base/kernel",    // _scopeName
10        "dojo/_base/lang", // lang.delegate lang.isArray lang.isObject lang.hitch
11        "dojo/query", // query
12        "dojo/when",
13        "dojo/store/util/QueryResults",
14        "./_FormValueWidget"
15], function(array, Deferred, aspect, sorter, declare, dom, domClass, kernel, lang, query, when,
16                        QueryResults, _FormValueWidget){
17
18        // module:
19        //              dijit/form/_FormSelectWidget
20
21        /*=====
22        var __SelectOption = {
23                // value: String
24                //              The value of the option.  Setting to empty (or missing) will
25                //              place a separator at that location
26                // label: String
27                //              The label for our option.  It can contain html tags.
28                // selected: Boolean
29                //              Whether or not we are a selected option
30                // disabled: Boolean
31                //              Whether or not this specific option is disabled
32        };
33        =====*/
34
35        var _FormSelectWidget = declare("dijit.form._FormSelectWidget", _FormValueWidget, {
36                // summary:
37                //              Extends _FormValueWidget in order to provide "select-specific"
38                //              values - i.e., those values that are unique to `<select>` elements.
39                //              This also provides the mechanism for reading the elements from
40                //              a store, if desired.
41
42                // multiple: [const] Boolean
43                //              Whether or not we are multi-valued
44                multiple: false,
45
46                // options: __SelectOption[]
47                //              The set of options for our select item.  Roughly corresponds to
48                //              the html `<option>` tag.
49                options: null,
50
51                // store: dojo/store/api/Store
52                //              A store to use for getting our list of options - rather than reading them
53                //              from the `<option>` html tags.   Should support getIdentity().
54                //              For back-compat store can also be a dojo/data/api/Identity.
55                store: null,
56
57                // query: object
58                //              A query to use when fetching items from our store
59                query: null,
60
61                // queryOptions: object
62                //              Query options to use when fetching from the store
63                queryOptions: null,
64
65                // labelAttr: String?
66                //              The entries in the drop down list come from this attribute in the dojo.store items.
67                //              If ``store`` is set, labelAttr must be set too, unless store is an old-style
68                //              dojo.data store rather than a new dojo/store.
69                labelAttr: "",
70
71                // onFetch: Function
72                //              A callback to do with an onFetch - but before any items are actually
73                //              iterated over (i.e. to filter even further what you want to add)
74                onFetch: null,
75
76                // sortByLabel: Boolean
77                //              Flag to sort the options returned from a store by the label of
78                //              the store.
79                sortByLabel: true,
80
81
82                // loadChildrenOnOpen: Boolean
83                //              By default loadChildren is called when the items are fetched from the
84                //              store.  This property allows delaying loadChildren (and the creation
85                //              of the options/menuitems) until the user clicks the button to open the
86                //              dropdown.
87                loadChildrenOnOpen: false,
88
89                // onLoadDeferred: [readonly] dojo.Deferred
90                //              This is the `dojo.Deferred` returned by setStore().
91                //              Calling onLoadDeferred.then() registers your
92                //              callback to be called only once, when the prior setStore completes.
93                onLoadDeferred: null,
94
95                getOptions: function(/*anything*/ valueOrIdx){
96                        // summary:
97                        //              Returns a given option (or options).
98                        // valueOrIdx:
99                        //              If passed in as a string, that string is used to look up the option
100                        //              in the array of options - based on the value property.
101                        //              (See dijit/form/_FormSelectWidget.__SelectOption).
102                        //
103                        //              If passed in a number, then the option with the given index (0-based)
104                        //              within this select will be returned.
105                        //
106                        //              If passed in a dijit/form/_FormSelectWidget.__SelectOption, the same option will be
107                        //              returned if and only if it exists within this select.
108                        //
109                        //              If passed an array, then an array will be returned with each element
110                        //              in the array being looked up.
111                        //
112                        //              If not passed a value, then all options will be returned
113                        //
114                        // returns:
115                        //              The option corresponding with the given value or index.
116                        //              null is returned if any of the following are true:
117                        //
118                        //              - A string value is passed in which doesn't exist
119                        //              - An index is passed in which is outside the bounds of the array of options
120                        //              - A dijit/form/_FormSelectWidget.__SelectOption is passed in which is not a part of the select
121
122                        // NOTE: the compare for passing in a dijit/form/_FormSelectWidget.__SelectOption checks
123                        //              if the value property matches - NOT if the exact option exists
124                        // NOTE: if passing in an array, null elements will be placed in the returned
125                        //              array when a value is not found.
126                        var opts = this.options || [];
127
128                        if(valueOrIdx == null){
129                                return opts; // __SelectOption[]
130                        }
131                        if(lang.isArray(valueOrIdx)){
132                                return array.map(valueOrIdx, "return this.getOptions(item);", this); // __SelectOption[]
133                        }
134                        if(lang.isString(valueOrIdx)){
135                                valueOrIdx = { value: valueOrIdx };
136                        }
137                        if(lang.isObject(valueOrIdx)){
138                                // We were passed an option - so see if it's in our array (directly),
139                                // and if it's not, try and find it by value.
140
141                                if(!array.some(opts, function(option, idx){
142                                        for(var a in valueOrIdx){
143                                                if(!(a in option) || option[a] != valueOrIdx[a]){ // == and not === so that 100 matches '100'
144                                                        return false;
145                                                }
146                                        }
147                                        valueOrIdx = idx;
148                                        return true; // stops iteration through opts
149                                })){
150                                        valueOrIdx = -1;
151                                }
152                        }
153                        if(valueOrIdx >= 0 && valueOrIdx < opts.length){
154                                return opts[valueOrIdx]; // __SelectOption
155                        }
156                        return null; // null
157                },
158
159                addOption: function(/*__SelectOption|__SelectOption[]*/ option){
160                        // summary:
161                        //              Adds an option or options to the end of the select.  If value
162                        //              of the option is empty or missing, a separator is created instead.
163                        //              Passing in an array of options will yield slightly better performance
164                        //              since the children are only loaded once.
165                        array.forEach(lang.isArray(option) ? option : [option], function(i){
166                                if(i && lang.isObject(i)){
167                                        this.options.push(i);
168                                }
169                        }, this);
170                        this._loadChildren();
171                },
172
173                removeOption: function(/*String|__SelectOption|Number|Array*/ valueOrIdx){
174                        // summary:
175                        //              Removes the given option or options.  You can remove by string
176                        //              (in which case the value is removed), number (in which case the
177                        //              index in the options array is removed), or select option (in
178                        //              which case, the select option with a matching value is removed).
179                        //              You can also pass in an array of those values for a slightly
180                        //              better performance since the children are only loaded once.
181                        //              For numeric option values, specify {value: number} as the argument.
182                        var oldOpts = this.getOptions(lang.isArray(valueOrIdx) ? valueOrIdx : [valueOrIdx]);
183                        array.forEach(oldOpts, function(option){
184                                // We can get null back in our array - if our option was not found.  In
185                                // that case, we don't want to blow up...
186                                if(option){
187                                        this.options = array.filter(this.options, function(node){
188                                                return (node.value !== option.value || node.label !== option.label);
189                                        });
190                                        this._removeOptionItem(option);
191                                }
192                        }, this);
193                        this._loadChildren();
194                },
195
196                updateOption: function(/*__SelectOption|__SelectOption[]*/ newOption){
197                        // summary:
198                        //              Updates the values of the given option.  The option to update
199                        //              is matched based on the value of the entered option.  Passing
200                        //              in an array of new options will yield better performance since
201                        //              the children will only be loaded once.
202                        array.forEach(lang.isArray(newOption) ? newOption : [newOption], function(i){
203                                var oldOpt = this.getOptions({ value: i.value }), k;
204                                if(oldOpt){
205                                        for(k in i){
206                                                oldOpt[k] = i[k];
207                                        }
208                                }
209                        }, this);
210                        this._loadChildren();
211                },
212
213                setStore: function(store, selectedValue, fetchArgs){
214                        // summary:
215                        //              Sets the store you would like to use with this select widget.
216                        //              The selected value is the value of the new store to set.  This
217                        //              function returns the original store, in case you want to reuse
218                        //              it or something.
219                        // store: dojo/store/api/Store
220                        //              The dojo.store you would like to use - it MUST implement getIdentity()
221                        //              and MAY implement observe().
222                        //              For backwards-compatibility this can also be a data.data store, in which case
223                        //              it MUST implement dojo/data/api/Identity,
224                        //              and MAY implement dojo/data/api/Notification.
225                        // selectedValue: anything?
226                        //              The value that this widget should set itself to *after* the store
227                        //              has been loaded
228                        // fetchArgs: Object?
229                        //              Hash of parameters to set filter on store, etc.
230                        //
231                        //              - query: new value for Select.query,
232                        //              - queryOptions: new value for Select.queryOptions,
233                        //              - onFetch: callback function for each item in data (Deprecated)
234                        var oStore = this.store;
235                        fetchArgs = fetchArgs || {};
236
237                        if(oStore !== store){
238                                // Our store has changed, so cancel any listeners on old store (remove for 2.0)
239                                var h;
240                                while((h = this._notifyConnections.pop())){
241                                        h.remove();
242                                }
243
244                                // For backwards-compatibility, accept dojo.data store in addition to dojo.store.store.  Remove in 2.0.
245                                if(!store.get){
246                                        lang.mixin(store, {
247                                                _oldAPI: true,
248                                                get: function(id){
249                                                        // summary:
250                                                        //              Retrieves an object by it's identity. This will trigger a fetchItemByIdentity.
251                                                        //              Like dojo.store.DataStore.get() except returns native item.
252                                                        var deferred = new Deferred();
253                                                        this.fetchItemByIdentity({
254                                                                identity: id,
255                                                                onItem: function(object){
256                                                                        deferred.resolve(object);
257                                                                },
258                                                                onError: function(error){
259                                                                        deferred.reject(error);
260                                                                }
261                                                        });
262                                                        return deferred.promise;
263                                                },
264                                                query: function(query, options){
265                                                        // summary:
266                                                        //              Queries the store for objects.   Like dojo/store/DataStore.query()
267                                                        //              except returned Deferred contains array of native items.
268                                                        var deferred = new Deferred(function(){
269                                                                if(fetchHandle.abort){
270                                                                        fetchHandle.abort();
271                                                                }
272                                                        });
273                                                        deferred.total = new Deferred();
274                                                        var fetchHandle = this.fetch(lang.mixin({
275                                                                query: query,
276                                                                onBegin: function(count){
277                                                                        deferred.total.resolve(count);
278                                                                },
279                                                                onComplete: function(results){
280                                                                        deferred.resolve(results);
281                                                                },
282                                                                onError: function(error){
283                                                                        deferred.reject(error);
284                                                                }
285                                                        }, options));
286                                                        return new QueryResults(deferred);
287                                                }
288                                        });
289
290                                        if(store.getFeatures()["dojo.data.api.Notification"]){
291                                                this._notifyConnections = [
292                                                        aspect.after(store, "onNew", lang.hitch(this, "_onNewItem"), true),
293                                                        aspect.after(store, "onDelete", lang.hitch(this, "_onDeleteItem"), true),
294                                                        aspect.after(store, "onSet", lang.hitch(this, "_onSetItem"), true)
295                                                ];
296                                        }
297                                }
298                                this._set("store", store);                      // Our store has changed, so update our notifications
299                        }
300
301                        // Remove existing options (if there are any)
302                        if(this.options && this.options.length){
303                                this.removeOption(this.options);
304                        }
305
306                        // Cancel listener for updates to old (dojo.data) store
307                        if(this._queryRes && this._queryRes.close){
308                                this._queryRes.close();
309                        }
310                       
311                        // Cancel listener for updates to new (dojo.store) store
312                        if(this._observeHandle && this._observeHandle.remove){
313                                this._observeHandle.remove();
314                                this._observeHandle = null;
315                        }
316
317                        // If user has specified new query and query options along with this new store, then use them.
318                        if(fetchArgs.query){
319                                this._set("query", fetchArgs.query);
320                                this._set("queryOptions", fetchArgs.queryOptions);
321                        }
322
323                        // Add our new options
324                        if(store){
325                                this._loadingStore = true;
326                                this.onLoadDeferred = new Deferred();
327
328                                // Run query
329                                // Save result in this._queryRes so we can cancel the listeners we register below
330                                this._queryRes = store.query(this.query, this.queryOptions);
331                                when(this._queryRes, lang.hitch(this, function(items){
332
333                                        if(this.sortByLabel && !fetchArgs.sort && items.length){
334                                                if(store.getValue){
335                                                        // Old dojo.data API to access items, remove for 2.0
336                                                        items.sort(sorter.createSortFunction([
337                                                                {
338                                                                        attribute: store.getLabelAttributes(items[0])[0]
339                                                                }
340                                                        ], store));
341                                                }else{
342                                                        // TODO: remove sortByLabel completely for 2.0?  It can be handled by queryOptions: {sort: ... }.
343                                                        var labelAttr = this.labelAttr;
344                                                        items.sort(function(a, b){
345                                                                return a[labelAttr] > b[labelAttr] ? 1 : b[labelAttr] > a[labelAttr] ? -1 : 0;
346                                                        });
347                                                }
348                                        }
349
350                                        if(fetchArgs.onFetch){
351                                                items = fetchArgs.onFetch.call(this, items, fetchArgs);
352                                        }
353
354                                        // TODO: Add these guys as a batch, instead of separately
355                                        array.forEach(items, function(i){
356                                                this._addOptionForItem(i);
357                                        }, this);
358
359                                        // Register listener for store updates
360                                        if(this._queryRes.observe){
361                                                // observe returns yet another handle that needs its own explicit gc
362                                                this._observeHandle = this._queryRes.observe(lang.hitch(this, function(object, deletedFrom, insertedInto){
363                                                        if(deletedFrom == insertedInto){
364                                                                this._onSetItem(object);
365                                                        }else{
366                                                                if(deletedFrom != -1){
367                                                                        this._onDeleteItem(object);
368                                                                }
369                                                                if(insertedInto != -1){
370                                                                        this._onNewItem(object);
371                                                                }
372                                                        }
373                                                }), true);
374                                        }
375
376                                        // Set our value (which might be undefined), and then tweak
377                                        // it to send a change event with the real value
378                                        this._loadingStore = false;
379                                        this.set("value", "_pendingValue" in this ? this._pendingValue : selectedValue);
380                                        delete this._pendingValue;
381
382                                        if(!this.loadChildrenOnOpen){
383                                                this._loadChildren();
384                                        }else{
385                                                this._pseudoLoadChildren(items);
386                                        }
387                                        this.onLoadDeferred.resolve(true);
388                                        this.onSetStore();
389                                }), function(err){
390                                        console.error('dijit.form.Select: ' + err.toString());
391                                        this.onLoadDeferred.reject(err);
392                                });
393                        }
394                        return oStore;  // dojo/data/api/Identity
395                },
396
397                // TODO: implement set() and watch() for store and query, although not sure how to handle
398                // setting them individually rather than together (as in setStore() above)
399
400                _setValueAttr: function(/*anything*/ newValue, /*Boolean?*/ priorityChange){
401                        // summary:
402                        //              set the value of the widget.
403                        //              If a string is passed, then we set our value from looking it up.
404                        if(!this._onChangeActive){
405                                priorityChange = null;
406                        }
407                        if(this._loadingStore){
408                                // Our store is loading - so save our value, and we'll set it when
409                                // we're done
410                                this._pendingValue = newValue;
411                                return;
412                        }
413                        if(newValue == null){
414                                return;
415                        }
416                        if(lang.isArray(newValue)){
417                                newValue = array.map(newValue, function(value){
418                                        return lang.isObject(value) ? value : { value: value };
419                                }); // __SelectOption[]
420                        }else if(lang.isObject(newValue)){
421                                newValue = [newValue];
422                        }else{
423                                newValue = [
424                                        { value: newValue }
425                                ];
426                        }
427                        newValue = array.filter(this.getOptions(newValue), function(i){
428                                return i && i.value;
429                        });
430                        var opts = this.getOptions() || [];
431                        if(!this.multiple && (!newValue[0] || !newValue[0].value) && !!opts.length){
432                                newValue[0] = opts[0];
433                        }
434                        array.forEach(opts, function(opt){
435                                opt.selected = array.some(newValue, function(v){
436                                        return v.value === opt.value;
437                                });
438                        });
439                        var val = array.map(newValue, function(opt){
440                                return opt.value;
441                        });
442
443                        if(typeof val == "undefined" || typeof val[0] == "undefined"){
444                                return;
445                        } // not fully initialized yet or a failed value lookup
446                        var disp = array.map(newValue, function(opt){
447                                return opt.label;
448                        });
449                        this._setDisplay(this.multiple ? disp : disp[0]);
450                        this.inherited(arguments, [ this.multiple ? val : val[0], priorityChange ]);
451                        this._updateSelection();
452                },
453
454                _getDisplayedValueAttr: function(){
455                        // summary:
456                        //              returns the displayed value of the widget
457                        var ret = array.map([].concat(this.get('selectedOptions')), function(v){
458                                if(v && "label" in v){
459                                        return v.label;
460                                }else if(v){
461                                        return v.value;
462                                }
463                                return null;
464                        }, this);
465                        return this.multiple ? ret : ret[0];
466                },
467
468                _setDisplayedValueAttr: function(label){
469                        // summary:
470                        //              Sets the displayed value of the widget
471                        this.set('value', this.getOptions(typeof label == "string" ? { label: label } : label));
472                },
473
474                _loadChildren: function(){
475                        // summary:
476                        //              Loads the children represented by this widget's options.
477                        //              reset the menu to make it populatable on the next click
478                        if(this._loadingStore){
479                                return;
480                        }
481                        array.forEach(this._getChildren(), function(child){
482                                child.destroyRecursive();
483                        });
484                        // Add each menu item
485                        array.forEach(this.options, this._addOptionItem, this);
486
487                        // Update states
488                        this._updateSelection();
489                },
490
491                _updateSelection: function(){
492                        // summary:
493                        //              Sets the "selected" class on the item for styling purposes
494                        this.focusedChild = null;
495                        this._set("value", this._getValueFromOpts());
496                        var val = [].concat(this.value);
497                        if(val && val[0]){
498                                var self = this;
499                                array.forEach(this._getChildren(), function(child){
500                                        var isSelected = array.some(val, function(v){
501                                                return child.option && (v === child.option.value);
502                                        });
503                                        if(isSelected && !self.multiple){
504                                                self.focusedChild = child;
505                                        }
506                                        domClass.toggle(child.domNode, this.baseClass.replace(/\s+|$/g, "SelectedOption "), isSelected);
507                                        child.domNode.setAttribute("aria-selected", isSelected ? "true" : "false");
508                                }, this);
509                        }
510                },
511
512                _getValueFromOpts: function(){
513                        // summary:
514                        //              Returns the value of the widget by reading the options for
515                        //              the selected flag
516                        var opts = this.getOptions() || [];
517                        if(!this.multiple && opts.length){
518                                // Mirror what a select does - choose the first one
519                                var opt = array.filter(opts, function(i){
520                                        return i.selected;
521                                })[0];
522                                if(opt && opt.value){
523                                        return opt.value;
524                                }else{
525                                        opts[0].selected = true;
526                                        return opts[0].value;
527                                }
528                        }else if(this.multiple){
529                                // Set value to be the sum of all selected
530                                return array.map(array.filter(opts, function(i){
531                                        return i.selected;
532                                }), function(i){
533                                        return i.value;
534                                }) || [];
535                        }
536                        return "";
537                },
538
539                // Internal functions to call when we have store notifications come in
540                _onNewItem: function(/*item*/ item, /*Object?*/ parentInfo){
541                        if(!parentInfo || !parentInfo.parent){
542                                // Only add it if we are top-level
543                                this._addOptionForItem(item);
544                        }
545                },
546                _onDeleteItem: function(/*item*/ item){
547                        var store = this.store;
548                        this.removeOption({value: store.getIdentity(item) });
549                },
550                _onSetItem: function(/*item*/ item){
551                        this.updateOption(this._getOptionObjForItem(item));
552                },
553
554                _getOptionObjForItem: function(item){
555                        // summary:
556                        //              Returns an option object based off the given item.  The "value"
557                        //              of the option item will be the identity of the item, the "label"
558                        //              of the option will be the label of the item.
559
560                        // remove getLabel() call for 2.0 (it's to support the old dojo.data API)
561                        var store = this.store,
562                                label = (this.labelAttr && this.labelAttr in item) ? item[this.labelAttr] : store.getLabel(item),
563                                value = (label ? store.getIdentity(item) : null);
564                        return {value: value, label: label, item: item}; // __SelectOption
565                },
566
567                _addOptionForItem: function(/*item*/ item){
568                        // summary:
569                        //              Creates (and adds) the option for the given item
570                        var store = this.store;
571                        if(store.isItemLoaded && !store.isItemLoaded(item)){
572                                // We are not loaded - so let's load it and add later.
573                                // Remove for 2.0 (it's the old dojo.data API)
574                                store.loadItem({item: item, onItem: function(i){
575                                        this._addOptionForItem(i);
576                                },
577                                        scope: this});
578                                return;
579                        }
580                        var newOpt = this._getOptionObjForItem(item);
581                        this.addOption(newOpt);
582                },
583
584                constructor: function(params /*===== , srcNodeRef =====*/){
585                        // summary:
586                        //              Create the widget.
587                        // params: Object|null
588                        //              Hash of initialization parameters for widget, including scalar values (like title, duration etc.)
589                        //              and functions, typically callbacks like onClick.
590                        //              The hash can contain any of the widget's properties, excluding read-only properties.
591                        // srcNodeRef: DOMNode|String?
592                        //              If a srcNodeRef (DOM node) is specified, replace srcNodeRef with my generated DOM tree
593
594                        //              Saves off our value, if we have an initial one set so we
595                        //              can use it if we have a store as well (see startup())
596                        this._oValue = (params || {}).value || null;
597                        this._notifyConnections = [];   // remove for 2.0
598                },
599
600                buildRendering: function(){
601                        this.inherited(arguments);
602                        dom.setSelectable(this.focusNode, false);
603                },
604
605                _fillContent: function(){
606                        // summary:
607                        //              Loads our options and sets up our dropdown correctly.  We
608                        //              don't want any content, so we don't call any inherit chain
609                        //              function.
610                        if(!this.options){
611                                this.options =
612                                        this.srcNodeRef
613                                                ? query("> *", this.srcNodeRef).map(
614                                                function(node){
615                                                        if(node.getAttribute("type") === "separator"){
616                                                                return { value: "", label: "", selected: false, disabled: false };
617                                                        }
618                                                        return {
619                                                                value: (node.getAttribute("data-" + kernel._scopeName + "-value") || node.getAttribute("value")),
620                                                                label: String(node.innerHTML),
621                                                                // FIXME: disabled and selected are not valid on complex markup children (which is why we're
622                                                                // looking for data-dojo-value above.  perhaps we should data-dojo-props="" this whole thing?)
623                                                                // decide before 1.6
624                                                                selected: node.getAttribute("selected") || false,
625                                                                disabled: node.getAttribute("disabled") || false
626                                                        };
627                                                },
628                                                this)
629                                                : [];
630                        }
631                        if(!this.value){
632                                this._set("value", this._getValueFromOpts());
633                        }else if(this.multiple && typeof this.value == "string"){
634                                this._set("value", this.value.split(","));
635                        }
636                },
637
638                postCreate: function(){
639                        // summary:
640                        //              sets up our event handling that we need for functioning
641                        //              as a select
642                        this.inherited(arguments);
643
644                        // Make our event connections for updating state
645                        aspect.after(this, "onChange", lang.hitch(this, "_updateSelection"));
646
647                        // moved from startup
648                        //              Connects in our store, if we have one defined
649                        var store = this.store;
650                        if(store && (store.getIdentity || store.getFeatures()["dojo.data.api.Identity"])){
651                                // Temporarily set our store to null so that it will get set
652                                // and connected appropriately
653                                this.store = null;
654                                this.setStore(store, this._oValue);
655                        }
656                },
657
658                startup: function(){
659                        // summary:
660                        this._loadChildren();
661                        this.inherited(arguments);
662                },
663
664                destroy: function(){
665                        // summary:
666                        //              Clean up our connections
667
668                        var h;
669                        while((h = this._notifyConnections.pop())){
670                                h.remove();
671                        }
672
673                        // Cancel listener for store updates
674                        if(this._queryRes && this._queryRes.close){
675                                this._queryRes.close();
676                        }
677
678                        // Cancel listener for updates to new (dojo.store) store
679                        if(this._observeHandle && this._observeHandle.remove){
680                                this._observeHandle.remove();
681                                this._observeHandle = null;
682                        }
683
684                        this.inherited(arguments);
685                },
686
687                _addOptionItem: function(/*__SelectOption*/ /*===== option =====*/){
688                        // summary:
689                        //              User-overridable function which, for the given option, adds an
690                        //              item to the select.  If the option doesn't have a value, then a
691                        //              separator is added in that place.  Make sure to store the option
692                        //              in the created option widget.
693                },
694
695                _removeOptionItem: function(/*__SelectOption*/ /*===== option =====*/){
696                        // summary:
697                        //              User-overridable function which, for the given option, removes
698                        //              its item from the select.
699                },
700
701                _setDisplay: function(/*String or String[]*/ /*===== newDisplay =====*/){
702                        // summary:
703                        //              Overridable function which will set the display for the
704                        //              widget.  newDisplay is either a string (in the case of
705                        //              single selects) or array of strings (in the case of multi-selects)
706                },
707
708                _getChildren: function(){
709                        // summary:
710                        //              Overridable function to return the children that this widget contains.
711                        return [];
712                },
713
714                _getSelectedOptionsAttr: function(){
715                        // summary:
716                        //              hooks into this.attr to provide a mechanism for getting the
717                        //              option items for the current value of the widget.
718                        return this.getOptions({ selected: true });
719                },
720
721                _pseudoLoadChildren: function(/*item[]*/ /*===== items =====*/){
722                        // summary:
723                        //              a function that will "fake" loading children, if needed, and
724                        //              if we have set to not load children until the widget opens.
725                        // items:
726                        //              An array of items that will be loaded, when needed
727                },
728
729                onSetStore: function(){
730                        // summary:
731                        //              a function that can be connected to in order to receive a
732                        //              notification that the store has finished loading and all options
733                        //              from that store are available
734                }
735        });
736
737        /*=====
738        _FormSelectWidget.__SelectOption = __SelectOption;
739        =====*/
740
741        return _FormSelectWidget;
742});
Note: See TracBrowser for help on using the repository browser.