summaryrefslogtreecommitdiff
path: root/includes/js/dojox/presentation/_base.js
diff options
context:
space:
mode:
Diffstat (limited to 'includes/js/dojox/presentation/_base.js')
-rw-r--r--includes/js/dojox/presentation/_base.js557
1 files changed, 557 insertions, 0 deletions
diff --git a/includes/js/dojox/presentation/_base.js b/includes/js/dojox/presentation/_base.js
new file mode 100644
index 0000000..2077a4e
--- /dev/null
+++ b/includes/js/dojox/presentation/_base.js
@@ -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);
+ }
+
+});
+
+}