/*
Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
Available via Academic Free License >= 2.1 OR the modified BSD license.
see: http://dojotoolkit.org/license for details
*/
if(!dojo._hasResource["dojox.form._SelectStackMixin"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.form._SelectStackMixin"] = true;
dojo.provide("dojox.form._SelectStackMixin");
dojo.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 = dojo.filter(pane.getDescendants(), "return item.name;");
if(!shown){
// We are hiding - save the current state and then disable them
savedStates = {};
dojo.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||{};
dojo.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 = dojo.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 = dojo.hitch(this, "_togglePane", pane, true);
pane.onHide = dojo.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(dojo.filter(dojo.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 = dojo.hitch(this, "_togglePane", c, true);
c.onHide = dojo.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 = dijit.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 = [
dojo.subscribe(this.stackId + "-startup", this, "onStartup"),
dojo.subscribe(this.stackId + "-addChild", this, "onAddChild"),
dojo.subscribe(this.stackId + "-removeChild", this, "onRemoveChild"),
dojo.subscribe(this.stackId + "-selectChild", this, "onSelectChild")
];
var stack = dijit.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(){
dojo.forEach(this._subscriptions, dojo.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 = dijit.byId(this.stackId);
if(pane == s.selectedChildWidget){
s._transition(pane);
}else{
s.selectChild(pane);
}
}
}
});
}