]> git.pond.sub.org Git - eow/blobdiff - static/dojo-release-1.1.1/dojox/presentation/_base.js
add Dojo 1.1.1
[eow] / static / dojo-release-1.1.1 / dojox / presentation / _base.js
diff --git a/static/dojo-release-1.1.1/dojox/presentation/_base.js b/static/dojo-release-1.1.1/dojox/presentation/_base.js
new file mode 100644 (file)
index 0000000..2077a4e
--- /dev/null
@@ -0,0 +1,557 @@
+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 disallow
+       useNav: 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" button
+       nextIcon: dojo.moduleUrl('dojox.presentation','resources/icons/next.png'),
+
+       // prevIcon: String
+       //      icon for navigation "previous" button
+       prevIcon: 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 presention
+               this.inherited(arguments);
+
+               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 param
+               var 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 slide
+               if (!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 localtion
+               return this.id+"_SlideNo_"+id;
+       },
+       
+       _hideNav: function(evt){
+               // summary: hides navigation
+               if(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 navigation
+               if(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 slides
+                       var 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 slide
+               this.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-ability 
+               var nodeName = evt.target.nodeName.toLowerCase();
+               // TODO: check for noClick='true' in target attrs & return true
+               // TODO: check for relayClick='true' in target attrs & return false
+               switch(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 access
+               if(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 Slide
+       title: "",
+
+       // 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.inherited(arguments);
+               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 action
+               var 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 slide
+                       this.getParent().nextSlide(evt);
+               }       
+       },
+
+       _getNextAction: function(){
+               // summary: returns the _next action in this sequence
+               return this._actions[this._actionIndex+1] || 0;
+       },
+
+       _reset: function(){
+               // summary: set action chain back to 0 and re-init each Part
+               this._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: "",
+       
+       // startVisible: boolean
+       //      true to leave in page on slide startup/reset
+       //      false to hide on slide startup/reset
+       startVisible: false,
+
+       // isShowing: Boolean,
+       //      private holder for _current_ state of Part
+       _isShowing: false,
+
+       postCreate: function(){
+               // summary: override and init() this component
+               this._reset();
+       },
+
+       _reset: function(){
+               // summary: set part back to initial calculate state
+               // these _seem_ backwards, but quickToggle flips it
+               this._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' attribute
+       forSlide: "",
+
+       // 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' node
+       duration: 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; 
+                       //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()?
+
+               this.inherited(arguments);
+               // 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/as 
+               this._attached = [];
+               dojo.forEach(parents,function(parentPart){
+                       if(this.forSlide == parentPart.as){ 
+                               this._attached.push(parentPart); 
+                       }
+               },this);
+       }       
+
+});
+
+}