dojo.provide("dojox.layout.RotatorContainer"); dojo.require("dojo.fx"); dojo.require("dijit.layout.StackContainer"); dojo.require("dijit.layout.StackController"); dojo.require("dijit._Widget"); dojo.require("dijit._Templated"); dojo.require("dijit._Contained"); dojo.declare("dojox.layout.RotatorContainer", [dijit.layout.StackContainer, dijit._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, // _timer: int // The timer used for controlling the transitions. _timer: null, // _over: Boolean // Flag to quick check if the mouse is over the rotator. _over: false, // _playing: Boolean // Flag to track transition state. _playing: false, // 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 dojo.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(); var sc = new dijit.layout.StackController({ containerId:id }, this.tabNode); this.tabNode = sc.domNode; this._stackController = sc; dojo.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 = [ dojo.subscribe(this.id+"-cycle", this, "_cycle"), dojo.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(dojo.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(/*Widget*/next, /*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(/*Widget*/next, /*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 }; var anim = dojo.fx.combine([ dojo["fadeOut"](dojo.mixin({node:prev.domNode},args)), dojo["fadeIn"](dojo.mixin({node:next.domNode},args)) ]); this.connect(anim, "onEnd", dojo.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. console.log(arguments); dojo.style(node, "opacity", opacity); dojo.style(node, "zIndex", zIndex); dojo.style(node, "position", "absolute"); } }); dojo.declare("dojox.layout.RotatorPager", [dijit._Widget, dijit._Templated, dijit._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 = dijit.byId(this.rotatorId) || this.getParent(); if(p && p.declaredClass == "dojox.layout.RotatorContainer"){ if(this.previous){ dojo.connect(this.previous, "onClick", function(){ dojo.publish(p.id+"-cycle", [false]); }); } if(this.next){ dojo.connect(this.next, "onClick", function(){ dojo.publish(p.id+"-cycle", [true]); }); } if(this.playPause){ dojo.connect(this.playPause, "onClick", function(){ this.attr('label', this.checked ? "Pause" : "Play"); dojo.publish(p.id+"-state", [this.checked]); }); } this._subscriptions = [ dojo.subscribe(p.id+"-state", this, "_state"), dojo.subscribe(p.id+"-update", this, "_update") ]; } }, destroy: function(){ // summary: Unsubscribe to all of our topics dojo.forEach(this._subscriptions, dojo.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.attr('label', playing ? "Pause" : "Play"); this.playPause.setAttribute("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; } } });