Blame | Last modification | View Log | RSS feed
if(!dojo._hasResource["dojox.presentation._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.dojo._hasResource["dojox.presentation._base"] = true;dojo.provide("dojox.presentation._base");dojo.experimental("dojox.presentation");dojo.require("dijit._Widget");dojo.require("dijit._Container");dojo.require("dijit._Templated");dojo.require("dijit.layout.StackContainer");dojo.require("dijit.layout.ContentPane");dojo.require("dojo.fx");dojo.declare("dojox.presentation.Deck", [ dijit.layout.StackContainer, dijit._Templated ], {// summary:// dojox.presentation class// basic powerpoint esque engine for handling transitons and control// in a page-by-page and part-by-part way//// FIXME: parsing part(s)/widget(s) in href="" Slides not working// TODO: make auto actions progress.// FIXME: Safari keydown/press/up listener not working.// noClick=true prevents progression of slides in that broweser//// fullScreen: Boolean// unsupported (that i know of) just yet. Default it to take control// of window. Would be nice to be able to contain presentation in a// styled container, like StackContainer ... theoretically possible.// [and may not need this variable?]fullScreen: true,// useNav: Boolean// true to allow navigation popup, false to disallowuseNav: true,// navDuration: Integer// time in MS fadein/out of popup nav [default: 250]navDuration: 250,// noClick: Boolean// if true, prevents _any_ click events to propagate actions// (limiting control to keyboard and/or action.on="auto" or action.delay=""// actions.noClick: false,// setHash: Boolean// if true, window location bar will get a #link to slide for direct// access to a particular slide number.setHash: true,// just to over-ride:templateString: null,templateString:"<div class=\"dojoShow\" dojoAttachPoint=\"showHolder\">\n\t<div class=\"dojoShowNav\" dojoAttachPoint=\"showNav\" dojoAttachEvent=\"onmouseover: _showNav, onmouseout: _hideNav\">\n\t<div class=\"dojoShowNavToggler\" dojoAttachPoint=\"showToggler\">\n\t\t<img dojoAttachPoint=\"prevNode\" src=\"${prevIcon}\" dojoAttachEvent=\"onclick:previousSlide\">\n\t\t<select dojoAttachEvent=\"onchange:_onEvent\" dojoAttachPoint=\"select\">\n\t\t\t<option dojoAttachPoint=\"_option\">Title</option>\n\t\t</select>\n\t\t<img dojoAttachPoint=\"nextNode\" src=\"${nextIcon}\" dojoAttachEvent=\"onclick:nextSlide\">\n\t</div>\n\t</div>\n\t<div dojoAttachPoint=\"containerNode\"></div>\n</div>\n",// nextIcon: String// icon for navigation "next" buttonnextIcon: dojo.moduleUrl('dojox.presentation','resources/icons/next.png'),// prevIcon: String// icon for navigation "previous" buttonprevIcon: dojo.moduleUrl('dojox.presentation','resources/icons/prev.png'),_navOpacMin: 0,_navOpacMax: 0.85,_slideIndex: 0,// Private:_slides: [],_navShowing: true,_inNav: false,startup: function(){// summary: connect to the various handlers and controls for this presentiondojox.presentation.Deck.superclass.startup.call(this);if(this.useNav){this._hideNav();}else{this.showNav.style.display = "none";}this.connect(document,'onclick', '_onEvent');this.connect(document,'onkeypress', '_onEvent');// only if this.fullScreen == true?this.connect(window, 'onresize', '_resizeWindow');this._resizeWindow();this._updateSlides();this._readHash();this._setHash();},moveTo: function(/* Integer */ number){// summary: jump to slide based on paramvar slideIndex = number - 1;if(slideIndex < 0)slideIndex = 0;if(slideIndex > this._slides.length - 1)slideIndex = this._slides.length - 1;this._gotoSlide(slideIndex);},onMove: function (number){// summary: stub function? TODOC: ?},nextSlide: function(/*Event*/ evt){// summary: transition to the next slide.if (!this.selectedChildWidget.isLastChild) {this._gotoSlide(this._slideIndex+1);}if (evt) { evt.stopPropagation(); }},previousSlide: function(/*Event*/ evt){// summary: transition to the previous slideif (!this.selectedChildWidget.isFirstChild) {this._gotoSlide(this._slideIndex-1);} else { this.selectedChildWidget._reset(); }if (evt) { evt.stopPropagation();}},getHash: function(id){// summary: get the current hash to set in localtionreturn this.id+"_SlideNo_"+id;},_hideNav: function(evt){// summary: hides navigationif(this._navAnim){ this._navAnim.stop(); }this._navAnim = dojo.animateProperty({node:this.showNav,duration:this.navDuration,properties: {opacity: { end:this._navOpacMin }}}).play();},_showNav: function(evt){// summary: shows navigationif(this._navAnim){ this._navAnim.stop(); }this._navAnim = dojo.animateProperty({node:this.showNav,duration:this.navDuration,properties: {opacity: { end:this._navOpacMax }}}).play();},_handleNav: function(evt){// summary: does nothing? _that_ seems useful.evt.stopPropagation();},_updateSlides: function(){// summary:// populate navigation select list with refs to slides call this// if you add a node to your presentation dynamically.this._slides = this.getChildren();if(this.useNav){// populate the select box with top-level slidesvar i=0;dojo.forEach(this._slides,dojo.hitch(this,function(slide){i++;var tmp = this._option.cloneNode(true);tmp.text = slide.title+" ("+i+") ";this._option.parentNode.insertBefore(tmp,this._option);}));if(this._option.parentNode){this._option.parentNode.removeChild(this._option);}// dojo._destroyElement(this._option);}},_onEvent: function(/* Event */ evt){// summary:// main presentation function, determines next 'best action' for a// specified event.var _node = evt.target;var _type = evt.type;if(_type == "click" || _type == "change"){if(_node.index && _node.parentNode == this.select){this._gotoSlide(_node.index);}else if(_node == this.select){this._gotoSlide(_node.selectedIndex);}else{if (this.noClick || this.selectedChildWidget.noClick || this._isUnclickable(evt)) return;this.selectedChildWidget._nextAction(evt);}}else if(_type=="keydown" || _type == "keypress"){// FIXME: safari doesn't report keydown/keypress?var key = (evt.charCode == dojo.keys.SPACE ? dojo.keys.SPACE : evt.keyCode);switch(key){case dojo.keys.DELETE:case dojo.keys.BACKSPACE:case dojo.keys.LEFT_ARROW:case dojo.keys.UP_ARROW:case dojo.keys.PAGE_UP:case 80: // key 'p'this.previousSlide(evt);break;case dojo.keys.ENTER:case dojo.keys.SPACE:case dojo.keys.RIGHT_ARROW:case dojo.keys.DOWN_ARROW:case dojo.keys.PAGE_DOWN:case 78: // key 'n'this.selectedChildWidget._nextAction(evt);break;case dojo.keys.HOME: this._gotoSlide(0);}}this._resizeWindow();evt.stopPropagation();},_gotoSlide: function(/* Integer */ slideIndex){// summary: goes to slidethis.selectChild(this._slides[slideIndex]);this.selectedChildWidget._reset();this._slideIndex = slideIndex;if(this.useNav){this.select.selectedIndex = slideIndex;}if(this.setHash){this._setHash();}this.onMove(this._slideIndex+1);},_isUnclickable: function(/* Event */ evt){// summary: returns true||false base of a nodes click-abilityvar nodeName = evt.target.nodeName.toLowerCase();// TODO: check for noClick='true' in target attrs & return true// TODO: check for relayClick='true' in target attrs & return falseswitch(nodeName){case 'a' :case 'input' :case 'textarea' : return true; break;}return false;},_readHash: function(){var th = window.location.hash;if (th.length && this.setHash) {var parts = (""+window.location).split(this.getHash(''));if(parts.length>1){this._gotoSlide(parseInt(parts[1])-1);}}},_setHash: function(){// summary: sets url #mark to direct slide accessif(this.setHash){var slideNo = this._slideIndex+1;window.location.href = "#"+this.getHash(slideNo);}},_resizeWindow: function(/*Event*/ evt){// summary: resize this and children to fix this window/container// only if this.fullScreen?dojo.body().style.height = "auto";var wh = dijit.getViewport();var h = Math.max(document.documentElement.scrollHeight || dojo.body().scrollHeight,wh.h);var w = wh.w;this.selectedChildWidget.domNode.style.height = h +'px';this.selectedChildWidget.domNode.style.width = w +'px';},_transition: function(newWidget,oldWidget){// summary: over-ride stackcontainers _transition method// but atm, i find it to be ugly with not way to call// _showChild() without over-riding it too. hopefull// basic toggles in superclass._transition will be available// in dijit, and this won't be necessary.var anims = [];if(oldWidget){/*anims.push(dojo.fadeOut({ node: oldWidget.domNode,duration:250,onEnd: dojo.hitch(this,function(){this._hideChild(oldWidget);})}));*/this._hideChild(oldWidget);}if(newWidget){/*anims.push(dojo.fadeIn({node:newWidget.domNode, start:0, end:1,duration:300,onEnd: dojo.hitch(this,function(){this._showChild(newWidget);newWidget._reset();})}));*/this._showChild(newWidget);newWidget._reset();}//dojo.fx.combine(anims).play();}});dojo.declare("dojox.presentation.Slide",[dijit.layout.ContentPane,dijit._Contained,dijit._Container,dijit._Templated],{// summary:// a Comonent of a dojox.presentation, and container for each 'Slide'// made up of direct HTML (no part/action relationship), and dojox.presentation.Part(s),// and their attached Actions.// templatPath: String// make a ContentPane templated, and style the 'titleNode'templateString:"<div dojoAttachPoint=\"showSlide\" class=\"dojoShowPrint dojoShowSlide\">\n\t<h1 class=\"showTitle\" dojoAttachPoint=\"slideTitle\"><span class=\"dojoShowSlideTitle\" dojoAttachPoint=\"slideTitleText\">${title}</span></h1>\n\t<div class=\"dojoShowBody\" dojoAttachPoint=\"containerNode\"></div>\n</div>\n",// title: String// string to insert into titleNode, title of Slidetitle: "",// inherited from ContentPane FIXME: don't seem to work ATM?refreshOnShow: true,preLoad: false,doLayout: true,parseContent: true,// noClick: Boolean// true on slide tag prevents clicking, false allows// (can also be set on base presentation for global control)noClick: false,// private holders:_parts: [],_actions: [],_actionIndex: 0,_runningDelay: false,startup: function(){// summary: setup this slide with actions and components (Parts)this.slideTitleText.innerHTML = this.title;var children = this.getChildren();this._actions = [];dojo.forEach(children,function(child){var tmpClass = child.declaredClass.toLowerCase();switch(tmpClass){case "dojox.presentation.part" : this._parts.push(child); break;case "dojox.presentation.action" : this._actions.push(child); break;}},this);},_nextAction: function(evt){// summary: gotoAndPlay current cached actionvar tmpAction = this._actions[this._actionIndex] || 0;if (tmpAction){// is this action a delayed action? [auto? thoughts?]if(tmpAction.on == "delay"){this._runningDelay = setTimeout(dojo.hitch(tmpAction,"_runAction"),tmpAction.delay);console.debug('started delay action',this._runningDelay);}else{tmpAction._runAction();}// FIXME: it gets hairy here. maybe runAction should// call _actionIndex++ onEnd? if a delayed action is running, do// we want to prevent action++?var tmpNext = this._getNextAction();this._actionIndex++;if(tmpNext.on == "delay"){// FIXME: yeah it looks like _runAction() onend should report// _actionIndex++console.debug('started delay action',this._runningDelay);setTimeout(dojo.hitch(tmpNext,"_runAction"),tmpNext.delay);}}else{// no more actions in this slidethis.getParent().nextSlide(evt);}},_getNextAction: function(){// summary: returns the _next action in this sequencereturn this._actions[this._actionIndex+1] || 0;},_reset: function(){// summary: set action chain back to 0 and re-init each Partthis._actionIndex = [0];dojo.forEach(this._parts,function(part){part._reset();},this);}});dojo.declare("dojox.presentation.Part", [dijit._Widget,dijit._Contained], {// summary:// a node in a presentation.Slide that inherits control from a// dojox.presentation.Action// can be any element type, and requires styling before parsing//// as: String// like an ID, attach to Action via (part) as="" / (action) forSlide="" tags// this should be unique identifier?as: null,// startVisible: boolean// true to leave in page on slide startup/reset// false to hide on slide startup/resetstartVisible: false,// isShowing: Boolean,// private holder for _current_ state of Part_isShowing: false,postCreate: function(){// summary: override and init() this componentthis._reset();},_reset: function(){// summary: set part back to initial calculate state// these _seem_ backwards, but quickToggle flips itthis._isShowing =! this.startVisible;this._quickToggle();},_quickToggle: function(){// summary: ugly [unworking] fix to test setting state of component// before/after an animation. display:none prevents fadeIns?if(this._isShowing){dojo.style(this.domNode,'display','none');dojo.style(this.domNode,'visibility','hidden');dojo.style(this.domNode,'opacity',0);}else{dojo.style(this.domNode,'display','');dojo.style(this.domNode,'visibility','visible');dojo.style(this.domNode,'opacity',1);}this._isShowing =! this._isShowing;}});dojo.declare("dojox.presentation.Action", [dijit._Widget,dijit._Contained], {// summary:// a widget to attach to a dojox.presentation.Part to control// it's properties based on an inherited chain of events ...////// on: String// FIXME: only 'click' supported ATM. plans include on="delay",// on="end" of="", and on="auto". those should make semantic sense// to you.on: 'click',// forSlide: String// attach this action to a dojox.presentation.Part with a matching 'as' attributeforSlide: null,// toggle: String// will toggle attached [matching] node(s) via forSlide/as relationship(s)toggle: 'fade',// delay: Integer//delay: 0,// duration: Integer// default time in MS to run this action effect on it's 'forSlide' nodeduration: 1000,// private holders:_attached: [],_nullAnim: false,_runAction: function(){// summary: runs this action on attached node(s)var anims = [];// executes the action for each attached 'Part'dojo.forEach(this._attached,function(node){// FIXME: this is ugly, and where is toggle class? :(var dir = (node._isShowing) ? "Out" : "In";// node._isShowing =! node._isShowing;node._quickToggle(); // (?) this is annoying//var _anim = dojox.fx[ this.toggle ? this.toggle+dir : "fade"+dir]({var _anim = dojo.fadeIn({node:node.domNode,duration: this.duration//beforeBegin: dojo.hitch(node,"_quickToggle")});anims.push(_anim);},this);var _anim = dojo.fx.combine(anims);if(_anim){ _anim.play(); }},_getSiblingsByType: function(/* String */ declaredClass){// summary: quick replacement for getChildrenByType("class"), but in// a child here ... so it's getSiblings. courtesy bill in #dojo// could be moved into parent, and just call this.getChildren(),// which makes more sense.var siblings = dojo.filter( this.getParent().getChildren(), function(widget){return widget.declaredClass==declaredClass;});return siblings; // dijit._Widget},postCreate: function(){// summary: run this once, should this be startup: function()?// prevent actions from being visible, _always_dojo.style(this.domNode,"display","none");var parents = this._getSiblingsByType('dojox.presentation.Part');// create a list of "parts" we are attached to via forSlide/asthis._attached = [];dojo.forEach(parents,function(parentPart){if(this.forSlide == parentPart.as){this._attached.push(parentPart);}},this);}});}