define("dojox/layout/RotatorContainer", ["dojo/_base/declare","dojo/_base/html","dojo/_base/connect","dojo/_base/lang","dojo/_base/array",
"dojo/_base/fx","dojo/fx","dijit/_base/manager","dijit/layout/StackContainer","dijit/layout/StackController","dijit/_Widget",
"dijit/_Templated","dijit/_Contained"
],function(declare,html,connect,lang,array,baseFx,coreFx,manager,
StackContainer,StackController,Widget,Templated,Contained){
var RotatorContainer = declare("dojox.layout.RotatorContainer",[StackContainer, Templated], {
// summary:
// Extends a StackContainer to automatically transition between children
// and display navigation in the form of tabs or a pager.
//
// description:
// The RotatorContainer cycles through the children with a transition.
//
// ####published topics:
//
// [widgetId]-update - Notifies pager(s) that a child has changed.
// Parameters:
//
// - /*boolean*/ playing - true if playing, false if paused
// - /*int*/ current - current selected child
// - /*int*/ total - total number of children
//
// example:
// |
// |
// | Pane 1!
// |
// |
// | Pane 2!
// |
// |
// | Pane 3 with overrided transitionDelay!
// |
// |
templateString: '
',
// showTabs: Boolean
// Sets the display of the tabs. The tabs are actually a StackController.
// The child's title is used for the tab's label.
showTabs: true,
// transitionDelay: int
// The delay in milliseconds before transitioning to the next child.
transitionDelay: 5000,
// transition: String
// The type of transition to perform when switching children.
// A null transition will transition instantly.
transition: "fade",
// transitionDuration: int
// The duration of the transition in milliseconds.
transitionDuration: 1000,
// autoStart: Boolean
// Starts the timer to transition children upon creation.
autoStart: true,
// suspendOnHover: Boolean
// Pause the rotator when the mouse hovers over it.
suspendOnHover: false,
// pauseOnManualChange: Boolean
// Pause the rotator when the tab is changed or the pager's next/previous
// buttons are clicked.
pauseOnManualChange: null,
// reverse: Boolean
// Causes the rotator to rotate in reverse order.
reverse: false,
// pagerId: String
// ID the pager widget.
pagerId: "",
// cycles: int
// Number of cycles before pausing.
cycles: -1,
// pagerClass: String
// The declared Class of the Pager used for this Widget
pagerClass: "dojox.layout.RotatorPager",
postCreate: function(){
// summary:
// Initializes the DOM nodes, tabs, and transition stuff.
this.inherited(arguments);
// force this DOM node to a relative position and make sure the children are absolute positioned
html.style(this.domNode, "position", "relative");
// validate the cycles counter
if(this.cycles-0 == this.cycles && this.cycles != -1){
// we need to add 1 because we decrement cycles before the animation starts
this.cycles++;
}else{
this.cycles = -1;
}
// if they didn't specify the pauseOnManualChange, then we want it to be the opposite of
// the suspendOnHover since it doesn't make sense to do both, unless you really want to
if(this.pauseOnManualChange === null){
this.pauseOnManualChange = !this.suspendOnHover;
}
// create the stack controller if we are using tabs
var id = this.id || "rotator"+(new Date()).getTime(),
sc = new StackController({ containerId:id }, this.tabNode);
this.tabNode = sc.domNode;
this._stackController = sc;
html.style(this.tabNode, "display", this.showTabs ? "" : "none");
// if the controller's tabs are clicked, check if we should pause and reset the cycle counter
this.connect(sc, "onButtonClick","_manualChange");
// set up our topic listeners
this._subscriptions = [
connect.subscribe(this.id+"-cycle", this, "_cycle"),
connect.subscribe(this.id+"-state", this, "_state")
];
// make sure the transition duration isn't less than the transition delay
var d = Math.round(this.transitionDelay * 0.75);
if(d < this.transitionDuration){
this.transitionDuration = d;
}
// wire up the mouse hover events
if(this.suspendOnHover){
this.connect(this.domNode, "onmouseover", "_onMouseOver");
this.connect(this.domNode, "onmouseout", "_onMouseOut");
}
},
startup: function(){
// summary:
// Initializes the pagers.
if(this._started){ return; }
// check if the pager is defined within the rotator container
var c = this.getChildren();
for(var i=0, len=c.length; i0){
this.cycles--;
}
if(this.cycles==0){
this._pause();
}else if((!this.suspendOnHover || !this._over) && this.transitionDelay){
// check if current pane has a delay
this._timer = setTimeout(lang.hitch(this, "_cycle"), this.selectedChildWidget.domNode.getAttribute("transitionDelay") || this.transitionDelay);
}
this._updatePager();
},
_pause: function(){
// summary:
// Clears the transition timer and pauses the rotator.
this._playing = false;
this._resetTimer();
},
_state: function(playing){
// summary:
// Fired when the play/pause pager button is toggled.
if(playing){
// since we were manually changed, disable the cycle counter
this.cycles = -1;
this._play();
}else{
this._pause();
}
},
_transition: function(/*dijit._Widget*/ next, /*dijit._Widget*/ prev){
// summary:
// Dispatches the appropriate transition.
this._resetTimer();
// check if we have anything to transition
if(prev && this.transitionDuration){
switch(this.transition){
case "fade": this._fade(next, prev); return;
}
}
this._transitionEnd();
this.inherited(arguments);
},
_transitionEnd: function(){
if(this._playing){
this._play();
}else{
this._updatePager();
}
},
_fade: function(/*dijit._Widget*/ next, /*dijit._Widget*/ prev){
// summary:
// Crossfades two children.
this._styleNode(prev.domNode, 1, 1);
this._styleNode(next.domNode, 0, 2);
// show the next child and make sure it's sized properly
this._showChild(next);
if(this.doLayout && next.resize){
next.resize(this._containerContentBox || this._contentBox);
}
// create the crossfade animation
var args = { duration:this.transitionDuration },
anim = coreFx.combine([
baseFx["fadeOut"](lang.mixin({node:prev.domNode}, args)),
baseFx["fadeIn"](lang.mixin({node:next.domNode}, args))
]);
this.connect(anim, "onEnd", lang.hitch(this,function(){
this._hideChild(prev);
this._transitionEnd();
}));
anim.play();
},
_styleNode: function(/*DomNode*/node, /*number*/opacity, /*int*/zIndex){
// summary:
// Helper function to style the children.
html.style(node, "opacity", opacity);
html.style(node, "zIndex", zIndex);
html.style(node, "position", "absolute");
}
});
declare("dojox.layout.RotatorPager", [Widget, Templated, Contained], {
// summary:
// Defines controls used to manipulate a RotatorContainer
//
// description:
// A pager can be defined one of two ways:
//
// - Externally of the RotatorContainer's template and tell the
// RotatorPager the rotatorId of the RotatorContainer
// - As a direct descendant of the RotatorContainer (i.e. inside the
// RotatorContainer's template)
//
// The pager can contain the following components:
//
// - Previous button
// - Must be a dijit.form.Button
// - dojoAttachPoint must be named "previous"
// - Next button
// - Must be a dijit.form.Button
// - dojoAttachPoint must be named "next"
// - Play/Pause toggle button
// - Must be a dijit.form.ToggleButton
// - dojoAttachPoint must be named "playPause"
// - Use iconClass to specify toggled state
// - Current child #
// - dojoAttachPoint must be named "current"
// - Total # of children
// - dojoAttachPoint must be named "total"
//
// You can choose to exclude specific controls as well as add elements
// for styling.
//
// Should you need a pager, but don't want to use Dijit buttons, you can
// write your own pager widget and just wire it into the topics. The
// topic names are prefixed with the widget ID of the RotatorContainer.
// Notifications are received from and sent to the RotatorContainer as
// well as other RotatorPagers.
//
// ####published topics:
//
// [widgetId]-cycle - Notify that the next or previous button was pressed.
// Parameters:
//
// - /*boolean*/ next - true if next, false if previous
//
// [widgetId]-state - Notify that the play/pause button was toggled.
// Parameters:
//
// - /*boolean*/ playing - true if playing, false if paused
//
// example:
// A pager with the current/total children and previous/next buttons.
// |
// |
// | /
// |
// |
//
// example:
// A pager with only a play/pause toggle button.
// |
// |
// |
//
// example:
// A pager styled with iconClass.
// |
// |
// |
// |
// | /
// |
widgetsInTemplate: true,
// rotatorId: int
// The ID of the rotator this pager is tied to.
// Only required if defined outside of the RotatorContainer's container.
rotatorId: "",
postMixInProperties: function(){
this.templateString = "
" + this.srcNodeRef.innerHTML + "
";
},
postCreate: function(){
var p = manager.byId(this.rotatorId) || this.getParent();
if(p && p.declaredClass == "dojox.layout.RotatorContainer"){
if(this.previous){
connect.connect(this.previous, "onClick", function(){
connect.publish(p.id+"-cycle", [false]);
});
}
if(this.next){
connect.connect(this.next, "onClick", function(){
connect.publish(p.id+"-cycle", [true]);
});
}
if(this.playPause){
connect.connect(this.playPause, "onClick", function(){
this.set('label', this.checked ? "Pause" : "Play");
connect.publish(p.id+"-state", [this.checked]);
});
}
this._subscriptions = [
connect.subscribe(p.id+"-state", this, "_state"),
connect.subscribe(p.id+"-update", this, "_update")
];
}
},
destroy: function(){
// Unsubscribe to all of our topics
array.forEach(this._subscriptions, connect.unsubscribe);
this.inherited(arguments);
},
_state: function(/*boolean*/playing){
// summary:
// Updates the display of the play/pause button
if(this.playPause && this.playPause.checked != playing){
this.playPause.set("label", playing ? "Pause" : "Play");
this.playPause.set("checked", playing);
}
},
_update: function(/*boolean*/playing, /*int*/current, /*int*/total){
// summary:
// Updates the pager's play/pause button, current child, and total number of children.
this._state(playing);
if(this.current && current){
this.current.innerHTML = current;
}
if(this.total && total){
this.total.innerHTML = total;
}
}
});
return RotatorContainer;
});