123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- define("dojox/form/_SelectStackMixin", [
- "dojo/_base/lang",
- "dojo/_base/array",
- "dijit/_base/manager",
- "dojo/_base/connect",
- "dojo/_base/declare"
- ], function(lang, array, manager, connect, declare){
- return declare("dojox.form._SelectStackMixin", null, {
- // summary:
- // Mix this class in to a dijit.form._FormSelectWidget in order to
- // provide support for "selectable" multiforms. The widget is pointed
- // to a dijit.layout.StackContainer and will handle displaying and
- // submitting the values of only the appropriate pane.
- //
- // The options for this widget will be automatically set - based on
- // the panes that are in the stack container. The "title" attribute of
- // the pane will be used for the display of the option. The "id" attribute
- // of the pane will be used as the value of the option. In order to
- // avoid running into unique ID constraint issues, a stackPrefix mechanism
- // is provided.
- // stackId: string
- // The id of the stack that this widget is supposed to control
- stackId: "",
- // stackPrefix: string
- // A prefix to remove from our stack pane ids when setting our options.
- // This exists so that we won't run into unique ID constraints. For
- // example, if stackPrefix is set to "foo_", and there are three panes
- // in our stack with ids of "foo_a", "foo_b", and "foo_c", then the values
- // of the options created for the stack controller widget will be "a",
- // "b", and "c". This allows you to have multiple select stack widgets
- // with the same values - without having to have the panes require the
- // same ids.
- stackPrefix: "",
- _paneIdFromOption: function(/*String*/ oVal){
- // summary: Gets the pane ID given an option value
- return (this.stackPrefix || "") + oVal; // String
- },
- _optionValFromPane: function(/*String*/ id){
- // summary: Gets the option value given a pane ID
- var sp = this.stackPrefix;
- if(sp && id.indexOf(sp) === 0){
- return id.substring(sp.length); // String
- }
- return id; // String
- },
- _togglePane: function(/*dijit._Widget*/ pane, /*Boolean*/ shown){
- // summary: called when a pane is either shown or hidden (so that
- // we can toggle the widgets on it)
- if(pane._shown != undefined && pane._shown == shown){ return; }
- var widgets = array.filter(pane.getDescendants(), "return item.name;");
- if(!shown){
- // We are hiding - save the current state and then disable them
- savedStates = {};
- array.forEach(widgets, function(w){
- savedStates[w.id] = w.disabled;
- w.set("disabled", true);
- });
- pane._savedStates = savedStates;
- }else{
- // We are showing - restore our saved states
- var savedStates = pane._savedStates||{};
- array.forEach(widgets, function(w){
- var state = savedStates[w.id];
- if(state == undefined){
- state = false;
- }
- w.set("disabled", state);
- });
- delete pane._savedStates;
- }
- pane._shown = shown;
- },
- _connectTitle: function(/*dijit._Widget*/ pane, /*String*/ value){
- var fx = lang.hitch(this, function(title){
- this.updateOption({value: value, label: title});
- });
- if(pane._setTitleAttr){
- this.connect(pane, "_setTitleAttr", fx);
- }else{
- this.connect(pane, "attr", function(attr, val){
- if(attr == "title" && arguments.length > 1){
- fx(val);
- }
- });
- }
- },
- onAddChild: function(/*dijit._Widget*/ pane, /*Integer?*/ insertIndex){
- // summary: Called when the stack container adds a new pane
- if(!this._panes[pane.id]){
- this._panes[pane.id] = pane;
- var v = this._optionValFromPane(pane.id);
- this.addOption({value: v, label: pane.title});
- this._connectTitle(pane, v);
- }
- if(!pane.onShow || !pane.onHide || pane._shown == undefined){
- pane.onShow = lang.hitch(this, "_togglePane", pane, true);
- pane.onHide = lang.hitch(this, "_togglePane", pane, false);
- pane.onHide();
- }
- },
- _setValueAttr: function(v){
- if("_savedValue" in this){
- return;
- }
- this.inherited(arguments);
- },
- attr: function(/*String|Object*/name, /*Object?*/value){
- if(name == "value" && arguments.length == 2 && "_savedValue" in this){
- this._savedValue = value;
- }
- return this.inherited(arguments);
- },
- onRemoveChild: function(/*dijit._Widget*/ pane){
- // summary: Called when the stack container removes a pane
- if(this._panes[pane.id]){
- delete this._panes[pane.id];
- this.removeOption(this._optionValFromPane(pane.id));
- }
- },
- onSelectChild: function(/*dijit._Widget*/ pane){
- // summary: Called when the stack container selects a new pane
- this._setValueAttr(this._optionValFromPane(pane.id));
- },
- onStartup: function(/*Object*/ info){
- // summary: Called when the stack container is started up
- var selPane = info.selected;
- this.addOption(array.filter(array.map(info.children, function(c){
- var v = this._optionValFromPane(c.id);
- this._connectTitle(c, v);
- var toAdd = null;
- if(!this._panes[c.id]){
- this._panes[c.id] = c;
- toAdd = {value: v, label: c.title};
- }
- if(!c.onShow || !c.onHide || c._shown == undefined){
- c.onShow = lang.hitch(this, "_togglePane", c, true);
- c.onHide = lang.hitch(this, "_togglePane", c, false);
- c.onHide();
- }
- if("_savedValue" in this && v === this._savedValue){
- selPane = c;
- }
- return toAdd;
- }, this), function(i){ return i;}));
- var _this = this;
- var fx = function(){
- // This stuff needs to be run after we show our child, if
- // the stack is going to show a different child than is
- // selected - see trac #9396
- delete _this._savedValue;
- _this.onSelectChild(selPane);
- if(!selPane._shown){
- _this._togglePane(selPane, true);
- }
- };
- if(selPane !== info.selected){
- var stack = manager.byId(this.stackId);
- var c = this.connect(stack, "_showChild", function(sel){
- this.disconnect(c);
- fx();
- });
- }else{
- fx();
- }
- },
- postMixInProperties: function(){
- this._savedValue = this.value;
- this.inherited(arguments);
- this.connect(this, "onChange", "_handleSelfOnChange");
- },
- postCreate: function(){
- this.inherited(arguments);
- this._panes = {};
- this._subscriptions = [
- connect.subscribe(this.stackId + "-startup", this, "onStartup"),
- connect.subscribe(this.stackId + "-addChild", this, "onAddChild"),
- connect.subscribe(this.stackId + "-removeChild", this, "onRemoveChild"),
- connect.subscribe(this.stackId + "-selectChild", this, "onSelectChild")
- ];
- var stack = manager.byId(this.stackId);
- if(stack && stack._started){
- // If we have a stack, and it's already started, call our onStartup now
- this.onStartup({children: stack.getChildren(), selected: stack.selectedChildWidget});
- }
- },
- destroy: function(){
- array.forEach(this._subscriptions, connect.unsubscribe);
- delete this._panes; // Fixes memory leak in IE
- this.inherited("destroy", arguments);
- },
- _handleSelfOnChange: function(/*String*/ val){
- // summary: Called when form select widget's value has changed
- var pane = this._panes[this._paneIdFromOption(val)];
- if(pane){
- var s = manager.byId(this.stackId);
- if(pane == s.selectedChildWidget){
- s._transition(pane);
- }else{
- s.selectChild(pane);
- }
- }
- }
- });
- });
|