You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
571 lines
17 KiB
571 lines
17 KiB
define(["dojo/aspect", "dojo/_base/array", "dojo/_base/declare", "dojo/dom", "dojo/dom-attr", "dojo/dom-class", "dojo/dom-construct", "dojo/dom-geometry", "dojo/dom-style", "dojo/fx", "dojo/_base/kernel", "dojo/keys", |
|
"dojo/_base/lang", "dojo/on", "dijit/_WidgetBase", "dijit/_TemplatedMixin", "./PagerItem", "dojo/text!./Pager/Pager.html"], |
|
function(aspect, array, declare, dom, attr, domClass, domConstruct, geometry, style, fx, kernel, keys, lang, on, _WidgetBase, _TemplatedMixin, PagerItem, template){ |
|
|
|
kernel.experimental("dojox.widget.Pager"); |
|
|
|
return declare("dojox.widget.Pager", |
|
[_WidgetBase, _TemplatedMixin], |
|
{ |
|
// summary: |
|
// A Pager, displaying a list of sized nodes |
|
|
|
|
|
templateString: template, |
|
|
|
|
|
// iconPrevious: String? |
|
// The url of the previous page icon |
|
iconPrevious: "", |
|
|
|
// iconNext: String? |
|
// The url of the next page icon |
|
iconNext: "", |
|
|
|
iconPage: require.toUrl("dojox/widget/Pager/images/pageInactive.png"), |
|
iconPageActive: require.toUrl("dojox/widget/Pager/images/pageActive.png"), |
|
|
|
// store: Object |
|
// A dojo.data Data store |
|
store: null, // data store for items |
|
|
|
// orientation: String |
|
// Either "horizontal or "vertical" to define the direction the pages will slide |
|
orientation: "horizontal", // or vertical |
|
|
|
// statusPos: String |
|
// A string describing where to put the Pager "current page" indicator. Options are |
|
// "leading" or "trailing". In the case of horiztonal orientation, "leading" indicates |
|
// positioned above the PageItems. In the case of vertical, "leading" indicates "before". |
|
statusPos: "leading", |
|
|
|
// pagerPos: String |
|
// TODOC |
|
pagerPos: "center", |
|
|
|
// duration: Integer |
|
// Time in milliseconds to transition the pages |
|
duration: 500, |
|
|
|
// itemSpace: Integer |
|
// Spacing between items? TODOC |
|
itemSpace: 2, |
|
|
|
// resizeChildren: Boolean |
|
// TODOC |
|
resizeChildren: true, |
|
|
|
// itemClass: String|Widget |
|
// The full dotted named of a Class or Widget constructor to use for the internal Pager Items. |
|
itemClass: PagerItem, |
|
|
|
// itemsPage: Integer |
|
// The numbers of items to display in each "Page" |
|
itemsPage: 3, |
|
|
|
postMixInProperties: function(){ |
|
var h = (this.orientation == "horizontal"); |
|
lang.mixin(this,{ |
|
_totalPages:0, |
|
_currentPage:1, |
|
dirClass: "pager" + (h ? "Horizontal" : "Vertical"), |
|
iconNext: require.toUrl("dojox/widget/Pager/images/" + (h ? "h" : "v") + "Next.png"), |
|
iconPrevious: require.toUrl("dojox/widget/Pager/images/" + (h ? "h" : "v") + "Previous.png") |
|
}); |
|
}, |
|
|
|
// Bidi Support |
|
_next: function(){ |
|
// summary: |
|
// Handle next behavior depends on widget direction |
|
if(!this.isLeftToRight()){ |
|
this._pagerPrevious(); |
|
}else{ |
|
this._pagerNext(); |
|
} |
|
}, |
|
|
|
// Bidi Support |
|
_previous: function(){ |
|
// summary: |
|
// Handle previous behavior depends on widget direction |
|
if(!this.isLeftToRight()){ |
|
this._pagerNext(); |
|
}else{ |
|
this._pagerPrevious(); |
|
} |
|
}, |
|
|
|
postCreate: function(){ |
|
this.inherited(arguments); |
|
this.store.fetch({ |
|
onComplete: lang.hitch(this, "_init") |
|
}); |
|
|
|
}, |
|
|
|
_a11yStyle: function(e){ |
|
// summary: |
|
// top level onfocus/onblur listen to set a class "pagerFocus" on some node |
|
// and remove it onblur |
|
domClass.toggle(e.target, "pagerFocus", (e.type == "focus")); |
|
}, |
|
|
|
_handleKey: function(e){ |
|
// summary: |
|
// Handle keyboard navigation internally |
|
|
|
var key = (e.charCode == keys.SPACE ? keys.SPACE : e.keyCode); |
|
switch(key){ |
|
|
|
case keys.UP_ARROW: |
|
case keys.RIGHT_ARROW: |
|
case 110: |
|
case 78: // key "n" |
|
e.preventDefault(); |
|
this._next(); |
|
break; |
|
case keys.DOWN_ARROW: |
|
case keys.LEFT_ARROW: |
|
case 112: |
|
case 80: // key "p" |
|
e.preventDefault(); |
|
this._previous(); |
|
break; |
|
case keys.ENTER: |
|
switch(e.target){ |
|
case this.pagerNext : this._next(); break; |
|
case this.pagerPrevious : this._previous(); break; |
|
} |
|
break; |
|
} |
|
}, |
|
|
|
_init: function(items) { |
|
this.items = items; |
|
this._renderPages(); |
|
this._renderStatus(); |
|
this._renderPager(); |
|
}, |
|
|
|
generatePagerItem: function(/*item */ item, /* Number */ cnt){ |
|
// summary: |
|
// this method instantiates pagerItems to be used by the pager, it is overridable to allow |
|
// customizing these items |
|
|
|
// only use getObject if its not the default _PagerItem value |
|
var itemClass = this.itemClass, |
|
pagerItem = (typeof itemClass == "string" ? lang.getObject(itemClass) : itemClass); |
|
|
|
var contentContainer = domConstruct.create('div', { |
|
innerHTML: item.content |
|
}); |
|
|
|
return new pagerItem({ |
|
id: this.id + '-item-' + (cnt + 1) |
|
}, contentContainer); |
|
}, |
|
|
|
_renderPages: function(){ |
|
var pcv = this.pagerContainerView, |
|
_h = (this.orientation == "horizontal"); |
|
|
|
if(_h){ |
|
var pagerH = geometry.getMarginBox(this.pagerContainerPager).h, |
|
statusH = geometry.getMarginBox(this.pagerContainerStatus).h; |
|
|
|
if (this.pagerPos != 'center'){ |
|
var addonHeight = pagerH+statusH; |
|
}else{ |
|
var addonHeight = statusH; |
|
|
|
var widthSub = this.pagerIconNext.width, |
|
containerWidth = style.get(pcv, 'width'), |
|
newWidth = containerWidth-(2*widthSub); |
|
|
|
style.set(pcv, { |
|
width: newWidth+'px', |
|
marginLeft: this.pagerIconNext.width+'px', |
|
marginRight: this.pagerIconNext.width+'px' |
|
}); |
|
} |
|
var totalH = style.get(this.pagerContainer, 'height') - addonHeight; |
|
style.set(this.pagerContainerView, 'height', totalH+'px'); |
|
|
|
var itemSpace = Math.floor(style.get(pcv, 'width') / this.itemsPage); |
|
if(this.statusPos == 'trailing'){ |
|
if(this.pagerPos != 'center'){ |
|
style.set(pcv, 'marginTop', pagerH+'px'); |
|
} |
|
style.set(pcv, 'marginBottom', statusH+'px'); |
|
}else{ |
|
style.set(pcv, 'marginTop', statusH+'px'); |
|
if (this.pagerPos != 'center'){ |
|
style.set(pcv, 'marginTop', pagerH+'px'); |
|
} |
|
} |
|
}else{ |
|
var pagerW = geometry.getMarginBox(this.pagerContainerPager).w, |
|
statusW = geometry.getMarginBox(this.pagerContainerStatus).w, |
|
containerW = style.get(this.pagerContainer, 'width'); |
|
|
|
if(this.pagerPos != 'center'){ |
|
var addonWidth = pagerW + statusW; |
|
}else{ |
|
var addonWidth = statusW, |
|
heightSub = this.pagerIconNext.height, |
|
containerHeight = style.get(pcv, 'height'), |
|
newHeight = containerHeight - (2 * heightSub); |
|
|
|
style.set(pcv,{ |
|
height: newHeight+'px', |
|
marginTop: this.pagerIconNext.height+'px', |
|
marginBottom: this.pagerIconNext.height+'px' |
|
}); |
|
} |
|
var totalW = style.get(this.pagerContainer, 'width') - addonWidth; |
|
style.set(pcv, 'width', totalW+'px'); |
|
|
|
var itemSpace = Math.floor(style.get(pcv, 'height') / this.itemsPage); |
|
if(this.statusPos == 'trailing'){ |
|
if (this.pagerPos != 'center'){ |
|
style.set(pcv, 'marginLeft', pagerW + 'px'); |
|
} |
|
style.set(pcv, 'marginRight', statusW + 'px'); |
|
}else{ |
|
style.set(pcv, 'marginLeft', statusW + 'px'); |
|
if(this.pagerPos != 'center'){ |
|
style.set(pcv, 'marginRight', pagerW+'px'); |
|
} |
|
} |
|
} |
|
var paddingLead = "padding" + (_h ? "Left" : "Top"), |
|
paddingTrail = "padding" + (_h ? "Right" : "Bottom"); |
|
|
|
array.forEach(this.items, function(item, cnt){ |
|
var pagerItem = this.generatePagerItem(item, cnt), |
|
containerProps = {}; |
|
|
|
this.pagerItems.appendChild(pagerItem.domNode); |
|
|
|
containerProps[(_h ? "width" : "height")] = (itemSpace - this.itemSpace) + "px"; |
|
var p = (_h ? "height" : "width"); |
|
containerProps[p] = style.get(pcv, p) + "px"; |
|
style.set(pagerItem.containerNode, containerProps); |
|
|
|
if(this.resizeChildren){ |
|
pagerItem.resizeChildren(); |
|
} |
|
pagerItem.parseChildren(); |
|
|
|
// only display amount of items as defined in itemsPage |
|
style.set(pagerItem.domNode, "position", "absolute"); |
|
|
|
if (cnt < this.itemsPage){ |
|
var pos = (cnt) * itemSpace, |
|
trailingDir = (_h ? "left" : "top"), |
|
dir = (_h ? "top" : "left"); |
|
|
|
style.set(pagerItem.domNode, dir, "0px"); |
|
style.set(pagerItem.domNode, trailingDir, pos+"px"); |
|
}else{ |
|
style.set(pagerItem.domNode, "top", "-1000px"); |
|
style.set(pagerItem.domNode, "left", "-1000px"); |
|
} |
|
|
|
style.set(pagerItem.domNode, paddingTrail, (this.itemSpace/2)+"px"); |
|
style.set(pagerItem.domNode, paddingLead, (this.itemSpace/2)+"px"); |
|
|
|
}, this); |
|
}, |
|
|
|
_renderPager: function() { |
|
var tcp = this.pagerContainerPager, |
|
zero = "0px", |
|
_h = (this.orientation == "horizontal"); |
|
|
|
if(_h){ |
|
|
|
if(this.statusPos == 'center'){ |
|
|
|
}else if (this.statusPos == 'trailing'){ |
|
style.set(tcp, 'top', zero); |
|
}else{ |
|
style.set(tcp, 'bottom', zero); |
|
} |
|
style.set(this.pagerNext, 'right', zero); |
|
style.set(this.pagerPrevious, 'left', zero); |
|
|
|
}else{ |
|
|
|
if (this.statusPos == 'trailing'){ |
|
style.set(tcp, 'left', zero); |
|
}else{ |
|
style.set(tcp, 'right', zero); |
|
} |
|
style.set(this.pagerNext, 'bottom', zero); |
|
style.set(this.pagerPrevious, 'top', zero); |
|
} |
|
|
|
}, |
|
|
|
_renderStatus: function() { |
|
this._totalPages = Math.ceil(this.items.length / this.itemsPage); |
|
// FIXME!! |
|
this.iconWidth = 0; |
|
this.iconHeight = 0; |
|
this.iconsLoaded = 0; |
|
this._iconConnects = []; |
|
|
|
for (var i = 1; i <= this._totalPages; i++){ |
|
var icon = new Image(); |
|
|
|
var pointer = i; |
|
on(icon, 'click', lang.hitch(this, "_pagerSkip", pointer)); |
|
|
|
this._iconConnects[pointer] = on(icon, 'load', lang.hitch(this, function(pointer){ |
|
this.iconWidth += icon.width; |
|
this.iconHeight += icon.height; |
|
this.iconsLoaded++; |
|
|
|
if (this._totalPages == this.iconsLoaded){ |
|
if (this.orientation == "horizontal"){ |
|
if (this.statusPos == 'trailing'){ |
|
if (this.pagerPos == 'center'){ |
|
var containerHeight = style.get(this.pagerContainer, 'height'), |
|
statusHeight = style.get(this.pagerContainerStatus, 'height'); |
|
|
|
style.set(this.pagerContainerPager, 'top', ((containerHeight/2)-(statusHeight/2))+'px'); |
|
} |
|
style.set(this.pagerContainerStatus, 'bottom', '0px'); |
|
}else{ |
|
if (this.pagerPos == 'center'){ |
|
var containerHeight = style.get(this.pagerContainer, 'height'), |
|
statusHeight = style.get(this.pagerContainerStatus, 'height'); |
|
|
|
style.set(this.pagerContainerPager, 'bottom', ((containerHeight/2)-(statusHeight/2))+'px'); |
|
} |
|
style.set(this.pagerContainerStatus, 'top', '0px'); |
|
} |
|
|
|
var position = (style.get(this.pagerContainer, 'width')/2)-(this.iconWidth/2); |
|
// Bidi Support |
|
style.set(this.pagerContainerStatus, this.isLeftToRight()?'paddingLeft':'paddingRight', position+'px'); |
|
}else{ |
|
if (this.statusPos == 'trailing'){ |
|
if (this.pagerPos == 'center'){ |
|
var containerWidth = style.get(this.pagerContainer, 'width'), |
|
statusWidth = style.get(this.pagerContainerStatus, 'width'); |
|
|
|
style.set(this.pagerContainerPager, 'left', ((containerWidth/2)-(statusWidth/2))+'px'); |
|
} |
|
style.set(this.pagerContainerStatus, 'right', '0px'); |
|
}else{ |
|
if (this.pagerPos == 'center'){ |
|
var containerWidth = style.get(this.pagerContainer, 'width'), |
|
statusWidth = style.get(this.pagerContainerStatus, 'width'); |
|
|
|
style.set(this.pagerContainerPager, 'right', ((containerWidth/2)-(statusWidth/2))+'px'); |
|
} |
|
style.set(this.pagerContainerStatus, 'left', '0px'); |
|
} |
|
var position = (style.get(this.pagerContainer, 'height')/2)-(this.iconHeight/2); |
|
style.set(this.pagerContainerStatus, 'paddingTop', position+'px'); |
|
} |
|
} |
|
this._iconConnects[pointer].remove(); |
|
}, pointer)); |
|
|
|
if (i==this._currentPage){ |
|
icon.src=this.iconPageActive; |
|
}else{ |
|
icon.src=this.iconPage; |
|
} |
|
var pointer = i; |
|
|
|
domClass.add(icon, this.orientation+'PagerIcon'); |
|
attr.set(icon, 'id', this.id+'-status-'+i); |
|
this.pagerContainerStatus.appendChild(icon); |
|
|
|
if (this.orientation == "vertical"){ |
|
style.set(icon, 'display', 'block'); |
|
} |
|
} |
|
}, |
|
|
|
_pagerSkip: function(page){ |
|
if (this._currentPage == page){ |
|
return; |
|
}else{ |
|
// calculate whether to go left or right, take shortest way |
|
var distanceP; var distanceN; |
|
if (page < this._currentPage){ |
|
distanceP = this._currentPage - page; |
|
distanceN = (this._totalPages + page) - this._currentPage; |
|
}else{ |
|
distanceP = (this._totalPages + this._currentPage) - page; |
|
distanceN = page - this._currentPage; |
|
} |
|
|
|
var b = (distanceN > distanceP); |
|
this._toScroll = (b ? distanceP : distanceN); |
|
var cmd = (b ? "_pagerPrevious" : "_pagerNext"), |
|
handle = aspect.after(this, "onScrollEnd", lang.hitch(this, function(){ |
|
this._toScroll--; |
|
if(this._toScroll < 1){ |
|
handle.remove(); |
|
}else{ |
|
this[cmd](); |
|
} |
|
}), true); |
|
|
|
this[cmd](); |
|
} |
|
}, |
|
|
|
_pagerNext: function(){ |
|
if(this._anim) return; |
|
|
|
/** |
|
* fade slide out current items |
|
* make sure that next items are ligned up nicely before sliding them in |
|
*/ |
|
var _anims = []; |
|
for (var i = this._currentPage * this.itemsPage; i > (this._currentPage - 1) * this.itemsPage; i--){ |
|
if (!dom.byId(this.id+'-item-'+i)) continue; |
|
|
|
var currentItem = dom.byId(this.id+'-item-'+i); |
|
var marginBox = geometry.getMarginBox(currentItem); |
|
if (this.orientation == "horizontal") { |
|
var move = marginBox.l - (this.itemsPage * marginBox.w); |
|
_anims.push(fx.slideTo({node: currentItem, left: move, duration: this.duration})); |
|
}else{ |
|
var move = marginBox.t - (this.itemsPage * marginBox.h); |
|
_anims.push(fx.slideTo({node: currentItem, top: move, duration: this.duration})); |
|
} |
|
|
|
} |
|
var previousPage = this._currentPage; |
|
if (this._currentPage == this._totalPages){ |
|
this._currentPage = 1; |
|
}else{ |
|
this._currentPage++; |
|
} |
|
|
|
var cnt = this.itemsPage; |
|
for (var i=this._currentPage*this.itemsPage; i>(this._currentPage-1)*this.itemsPage; i--){ |
|
if (dom.byId(this.id+'-item-'+i)){ |
|
var currentItem = dom.byId(this.id+'-item-'+i); |
|
var marginBox = geometry.getMarginBox(currentItem); |
|
if (this.orientation == "horizontal") { |
|
var newPos = (style.get(this.pagerContainerView, 'width')+((cnt-1)*marginBox.w))-1; |
|
style.set(currentItem, 'left', newPos+'px'); |
|
style.set(currentItem, 'top', '0px'); |
|
|
|
var move = newPos-(this.itemsPage*marginBox.w); |
|
_anims.push(fx.slideTo({node: currentItem, left: move, duration: this.duration})); |
|
}else{ |
|
newPos = (style.get(this.pagerContainerView, 'height')+((cnt-1)*marginBox.h))-1; |
|
style.set(currentItem, 'top', newPos+'px'); |
|
style.set(currentItem, 'left', '0px'); |
|
|
|
var move = newPos-(this.itemsPage*marginBox.h); |
|
_anims.push(fx.slideTo({ node: currentItem, top: move, duration: this.duration})); |
|
} |
|
} |
|
cnt--; |
|
} |
|
|
|
this._anim = fx.combine(_anims); |
|
var animHandle = aspect.after(this._anim, "onEnd", lang.hitch(this, function(){ |
|
delete this._anim; |
|
this.onScrollEnd(); |
|
animHandle.remove(); |
|
}), true); |
|
|
|
this._anim.play(); |
|
|
|
// set pager icons |
|
dom.byId(this.id+'-status-'+previousPage).src = this.iconPage; |
|
dom.byId(this.id+'-status-'+this._currentPage).src = this.iconPageActive; |
|
}, |
|
|
|
_pagerPrevious: function(){ |
|
if(this._anim) return; |
|
|
|
var _anims = []; |
|
for (var i=this._currentPage*this.itemsPage; i>(this._currentPage-1)*this.itemsPage; i--){ |
|
if (!dom.byId(this.id+'-item-'+i)) continue; |
|
|
|
var currentItem = dom.byId(this.id+'-item-'+i); |
|
var marginBox = geometry.getMarginBox(currentItem); |
|
if (this.orientation == "horizontal") { |
|
var move = style.get(currentItem, 'left')+(this.itemsPage*marginBox.w); |
|
_anims.push(fx.slideTo({node: currentItem, left: move, duration: this.duration})); |
|
}else{ |
|
var move = style.get(currentItem, 'top')+(this.itemsPage*marginBox.h); |
|
_anims.push(fx.slideTo({node: currentItem, top: move, duration: this.duration})); |
|
} |
|
} |
|
|
|
var previousPage = this._currentPage; |
|
if (this._currentPage == 1){ |
|
this._currentPage = this._totalPages; |
|
}else{ |
|
this._currentPage--; |
|
} |
|
|
|
var cnt = this.itemsPage; |
|
var j=1; |
|
for (var i=this._currentPage*this.itemsPage; i>(this._currentPage-1)*this.itemsPage; i--){ |
|
if(dom.byId(this.id+'-item-'+i)){ |
|
var currentItem = dom.byId(this.id+'-item-'+i), |
|
marginBox = geometry.getMarginBox(currentItem); |
|
|
|
if (this.orientation == "horizontal") { |
|
var newPos = -(j * marginBox.w) + 1; |
|
style.set(currentItem, 'left', newPos+'px'); |
|
style.set(currentItem, 'top', '0px'); |
|
|
|
var move = ((cnt - 1) * marginBox.w); |
|
_anims.push(fx.slideTo({node: currentItem, left: move, duration: this.duration})); |
|
|
|
var move = newPos+(this.itemsPage * marginBox.w); |
|
_anims.push(fx.slideTo({node: currentItem, left: move, duration: this.duration})); |
|
}else{ |
|
newPos = -((j * marginBox.h) + 1); |
|
style.set(currentItem, 'top', newPos+'px'); |
|
style.set(currentItem, 'left', '0px'); |
|
|
|
var move = ((cnt - 1) * marginBox.h); |
|
_anims.push(fx.slideTo({node: currentItem, top: move, duration: this.duration})); |
|
} |
|
|
|
} |
|
cnt--; |
|
j++; |
|
} |
|
|
|
this._anim = fx.combine(_anims); |
|
var animHandle = aspect.after(this._anim, "onEnd", lang.hitch(this, function(){ |
|
delete this._anim; |
|
this.onScrollEnd(); |
|
animHandle.remove(); |
|
}), true); |
|
|
|
this._anim.play(); |
|
|
|
// set pager icons |
|
dom.byId(this.id + '-status-' + previousPage).src = this.iconPage; |
|
dom.byId(this.id + '-status-' + this._currentPage).src = this.iconPageActive; |
|
|
|
}, |
|
|
|
onScrollEnd: function(){ |
|
// summary: |
|
// Stub Function. Fired after the slide is complete. Override or connect. |
|
} |
|
|
|
}); |
|
|
|
});
|
|
|