source: Dev/trunk/src/client/dojox/form/_SelectStackMixin.js

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

Added Dojo 1.9.3 release.

File size: 7.0 KB
Line 
1define([
2        "dojo/_base/lang",
3        "dojo/_base/array",
4        "dijit/_base/manager",
5        "dojo/_base/connect",
6        "dojo/_base/declare"
7], function(lang, array, manager, connect, declare){
8
9return declare("dojox.form._SelectStackMixin", null, {
10        // summary:
11        //              Mix this class in to a dijit.form._FormSelectWidget in order to
12        //              provide support for "selectable" multiforms.  The widget is pointed
13        //              to a dijit.layout.StackContainer and will handle displaying and
14        //              submitting the values of only the appropriate pane.
15        //
16        //              The options for this widget will be automatically set - based on
17        //              the panes that are in the stack container.  The "title" attribute of
18        //              the pane will be used for the display of the option.  The "id" attribute
19        //              of the pane will be used as the value of the option.  In order to
20        //              avoid running into unique ID constraint issues, a stackPrefix mechanism
21        //              is provided.
22
23        // stackId: String
24        //              The id of the stack that this widget is supposed to control
25        stackId: "",
26
27        // stackPrefix: String
28        //              A prefix to remove from our stack pane ids when setting our options.
29        //              This exists so that we won't run into unique ID constraints.  For
30        //              example, if stackPrefix is set to "foo_", and there are three panes
31        //              in our stack with ids of "foo_a", "foo_b", and "foo_c", then the values
32        //              of the options created for the stack controller widget will be "a",
33        //              "b", and "c".  This allows you to have multiple select stack widgets
34        //              with the same values - without having to have the panes require the
35        //              same ids.
36        stackPrefix: "",
37
38        _paneIdFromOption: function(/*String*/ oVal){
39                // summary:
40                //              Gets the pane ID given an option value
41                return (this.stackPrefix || "") + oVal; // String
42        },
43
44        _optionValFromPane: function(/*String*/ id){
45                // summary:
46                //              Gets the option value given a pane ID
47                var sp = this.stackPrefix;
48                if(sp && id.indexOf(sp) === 0){
49                        return id.substring(sp.length); // String
50                }
51                return id; // String
52        },
53
54        _togglePane: function(/*dijit._Widget*/ pane, /*Boolean*/ shown){
55                // summary:
56                //              called when a pane is either shown or hidden (so that
57                //              we can toggle the widgets on it)
58
59                if(pane._shown != undefined && pane._shown == shown){ return; }
60                var widgets = array.filter(pane.getDescendants(), "return item.name;");
61                if(!shown){
62                        // We are hiding - save the current state and then disable them
63                        savedStates = {};
64                        array.forEach(widgets, function(w){
65                                savedStates[w.id] = w.disabled;
66                                w.set("disabled", true);
67                        });
68                        pane._savedStates = savedStates;
69                }else{
70                        // We are showing - restore our saved states
71                        var savedStates = pane._savedStates||{};
72                        array.forEach(widgets, function(w){
73                                var state = savedStates[w.id];
74                                if(state == undefined){
75                                        state = false;
76                                }
77                                w.set("disabled", state);
78                        });
79                        delete pane._savedStates;
80                }
81                pane._shown = shown;
82        },
83
84        _connectTitle: function(/*dijit._Widget*/ pane, /*String*/ value){
85                var fx = lang.hitch(this, function(title){
86                        this.updateOption({value: value, label: title});
87                });
88                if(pane._setTitleAttr){
89                        this.connect(pane, "_setTitleAttr", fx);
90                }else{
91                        this.connect(pane, "attr", function(attr, val){
92                                if(attr == "title" && arguments.length > 1){
93                                        fx(val);
94                                }
95                        });
96                }
97        },
98
99        onAddChild: function(/*dijit._Widget*/ pane, /*Integer?*/ insertIndex){
100                // summary:
101                //              Called when the stack container adds a new pane
102                if(!this._panes[pane.id]){
103                        this._panes[pane.id] = pane;
104                        var v = this._optionValFromPane(pane.id);
105                        this.addOption({value: v, label: pane.title});
106                        this._connectTitle(pane, v);
107                }
108                if(!pane.onShow || !pane.onHide || pane._shown == undefined){
109                        pane.onShow = lang.hitch(this, "_togglePane", pane, true);
110                        pane.onHide = lang.hitch(this, "_togglePane", pane, false);
111                        pane.onHide();
112                }
113        },
114
115        _setValueAttr: function(v){
116                if("_savedValue" in this){
117                        return;
118                }
119                this.inherited(arguments);
120        },
121        attr: function(/*String|Object*/ name, /*Object?*/ value){
122                if(name == "value" && arguments.length == 2 && "_savedValue" in this){
123                        this._savedValue = value;
124                }
125                return this.inherited(arguments);
126        },
127
128        onRemoveChild: function(/*dijit._Widget*/ pane){
129                // summary:
130                //              Called when the stack container removes a pane
131                if(this._panes[pane.id]){
132                        delete this._panes[pane.id];
133                        this.removeOption(this._optionValFromPane(pane.id));
134                }
135        },
136
137        onSelectChild: function(/*dijit._Widget*/ pane){
138                // summary:
139                //              Called when the stack container selects a new pane
140                this._setValueAttr(this._optionValFromPane(pane.id));
141        },
142
143        onStartup: function(/*Object*/ info){
144                // summary:
145                //              Called when the stack container is started up
146                var selPane = info.selected;
147                this.addOption(array.filter(array.map(info.children, function(c){
148                        var v = this._optionValFromPane(c.id);
149                        this._connectTitle(c, v);
150                        var toAdd = null;
151                        if(!this._panes[c.id]){
152                                this._panes[c.id] = c;
153                                toAdd = {value: v, label: c.title};
154                        }
155                        if(!c.onShow || !c.onHide || c._shown == undefined){
156                                c.onShow = lang.hitch(this, "_togglePane", c, true);
157                                c.onHide = lang.hitch(this, "_togglePane", c, false);
158                                c.onHide();
159                        }
160                        if("_savedValue" in this && v === this._savedValue){
161                                selPane = c;
162                        }
163                        return toAdd;
164                }, this), function(i){ return i;}));
165                var _this = this;
166                var fx = function(){
167                        // This stuff needs to be run after we show our child, if
168                        // the stack is going to show a different child than is
169                        // selected - see trac #9396
170                        delete _this._savedValue;
171                        _this.onSelectChild(selPane);
172                        if(!selPane._shown){
173                                _this._togglePane(selPane, true);
174                        }
175                };
176                if(selPane !== info.selected){
177                        var stack = manager.byId(this.stackId);
178                        var c = this.connect(stack, "_showChild", function(sel){
179                                this.disconnect(c);
180                                fx();
181                        });
182                }else{
183                        fx();
184                }
185        },
186
187        postMixInProperties: function(){
188                this._savedValue = this.value;
189                this.inherited(arguments);
190                this.connect(this, "onChange", "_handleSelfOnChange");
191        },
192
193        postCreate: function(){
194                this.inherited(arguments);
195                this._panes = {};
196                this._subscriptions = [
197                        connect.subscribe(this.stackId + "-startup", this, "onStartup"),
198                        connect.subscribe(this.stackId + "-addChild", this, "onAddChild"),
199                        connect.subscribe(this.stackId + "-removeChild", this, "onRemoveChild"),
200                        connect.subscribe(this.stackId + "-selectChild", this, "onSelectChild")
201                ];
202                var stack = manager.byId(this.stackId);
203                if(stack && stack._started){
204                        // If we have a stack, and it's already started, call our onStartup now
205                        this.onStartup({children: stack.getChildren(), selected: stack.selectedChildWidget});
206                }
207        },
208
209        destroy: function(){
210                array.forEach(this._subscriptions, connect.unsubscribe);
211                delete this._panes; // Fixes memory leak in IE
212                this.inherited("destroy", arguments);
213        },
214
215        _handleSelfOnChange: function(/*String*/ val){
216                // summary:
217                //              Called when form select widget's value has changed
218                var pane = this._panes[this._paneIdFromOption(val)];
219                if(pane){
220                        var s = manager.byId(this.stackId);
221                        if(pane == s.selectedChildWidget){
222                                s._transition(pane);
223                        }else{
224                                s.selectChild(pane);
225                        }
226                }
227        }
228});
229});
Note: See TracBrowser for help on using the repository browser.