Pager.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojox.widget.Pager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.widget.Pager"] = true;
  8. dojo.provide("dojox.widget.Pager");
  9. dojo.experimental("dojox.widget.Pager");
  10. dojo.require("dijit._Widget");
  11. dojo.require("dijit._Templated");
  12. dojo.require("dojo.fx");
  13. dojo.declare("dojox.widget.Pager",
  14. [dijit._Widget, dijit._Templated],
  15. {
  16. // summary: A Pager, displaying a list of sized nodes
  17. templateString: dojo.cache("dojox.widget", "Pager/Pager.html", "<div dojoAttachPoint=\"pagerContainer\" tabIndex=\"0\" dojoAttachEvent=\"onkeypress: _handleKey, onfocus: _a11yStyle, onblur:_a11yStyle\" class=\"${orientation}PagerContainer\">\n <div class=\"pagerContainer\">\n\t\t<div dojoAttachPoint=\"pagerContainerStatus\" class=\"${orientation}PagerStatus\"></div>\n\t\t<div dojoAttachPoint=\"pagerContainerView\" class=\"${orientation}PagerView\">\n\t\t <div dojoAttachPoint=\"pagerItemContainer\"><ul dojoAttachPoint=\"pagerItems\" class=\"pagerItems\"></ul></div>\n\t\t</div>\n\t\t<div dojoAttachPoint=\"pagerContainerPager\" class=\"${orientation}PagerPager\">\n\t\t\t<div tabIndex=\"0\" dojoAttachPoint=\"pagerNext\" class=\"pagerIconContainer\" dojoAttachEvent=\"onclick: _pagerNext\"><img dojoAttachPoint=\"pagerIconNext\" src=\"${iconNext}\" alt=\"Next\" /></div>\n\t\t\t<div tabIndex=\"0\" dojoAttachPoint=\"pagerPrevious\" class=\"pagerIconContainer\" dojoAttachEvent=\"onclick: _pagerPrevious\"><img dojoAttachPoint=\"pagerIconPrevious\" src=\"${iconPrevious}\" alt=\"Previous\" /></div>\n\t\t</div>\n </div>\n\t<div dojoAttachPoint=\"containerNode\" style=\"display:none\"></div>\n</div>\n"),
  18. /*=====
  19. // iconPrevious: String?
  20. // The url of the previous page icon
  21. iconPrevious: "",
  22. // iconNext: String?
  23. // The url of the next page icon
  24. iconNext: "",
  25. =====*/
  26. iconPage: dojo.moduleUrl("dojox.widget", "Pager/images/pageInactive.png"),
  27. iconPageActive: dojo.moduleUrl("dojox.widget", "Pager/images/pageActive.png"),
  28. // store: Object
  29. // A dojo.data Data store
  30. store: null, // data store for items
  31. // orientation: String
  32. // Either "horizontal or "vertical" to define the direction the pages will slide
  33. orientation: "horizontal", // or vertical
  34. // statusPos: String
  35. // A string describing where to put the Pager "current page" indicator. Options are
  36. // "leading" or "trailing". In the case of horiztonal orientation, "leading" indicates
  37. // positioned above the PageItems. In the case of vertical, "leading" indicates "before".
  38. statusPos: "leading",
  39. // pagerPos: String
  40. // TODOC
  41. pagerPos: "center",
  42. // duration: Integer
  43. // Time in milliseconds to transition the pages
  44. duration: 500,
  45. // itemSpace: Integer
  46. // Spacing between items? TODOC
  47. itemSpace: 2,
  48. // resizeChildren: Boolean
  49. // TODOC
  50. resizeChildren: true,
  51. // itemClass: String
  52. // The full dotted named of a Class to use for the internal Pager Items.
  53. itemClass: "dojox.widget._PagerItem",
  54. // itemsPage: Integer
  55. // The numbers of items to display in each "Page"
  56. itemsPage: 3,
  57. postMixInProperties: function(){
  58. var h = (this.orientation == "horizontal");
  59. dojo.mixin(this,{
  60. _totalPages:0,
  61. _currentPage:1,
  62. dirClass: "pager" + (h ? "Horizontal" : "Vertical"),
  63. iconNext: dojo.moduleUrl("dojox.widget", "Pager/images/" + (h ? "h" : "v") + "Next.png"),
  64. iconPrevious: dojo.moduleUrl("dojox.widget", "Pager/images/" + (h ? "h" : "v") + "Previous.png")
  65. });
  66. },
  67. postCreate: function(){
  68. this.inherited(arguments);
  69. //this.connect(this.domNode,"onkeypress","_handleKey");
  70. this.store.fetch({
  71. onComplete: dojo.hitch(this, "_init")
  72. });
  73. },
  74. _a11yStyle: function(e){
  75. // summary: top level onfocus/onblur listen to set a class "pagerFocus" on some node
  76. // and remove it onblur
  77. dojo[(e.type == "focus" ? "addClass" : "removeClass")](e.target,"pagerFocus");
  78. },
  79. _handleKey: function(e){
  80. // summary: Handle keyboard navigation internally
  81. var dk = dojo.keys;
  82. var key = (e.charCode == dk.SPACE ? dk.SPACE : e.keyCode);
  83. switch(key){
  84. case dk.UP_ARROW:
  85. case dk.RIGHT_ARROW:
  86. case 110:
  87. case 78: // key "n"
  88. e.preventDefault();
  89. this._pagerNext();
  90. break;
  91. case dk.DOWN_ARROW:
  92. case dk.LEFT_ARROW:
  93. case 112:
  94. case 80: // key "p"
  95. e.preventDefault();
  96. this._pagerPrevious();
  97. break;
  98. case dk.ENTER:
  99. switch(e.target){
  100. case this.pagerNext : this._pagerNext(); break;
  101. case this.pagerPrevious : this._pagerPrevious(); break;
  102. }
  103. break;
  104. }
  105. },
  106. _init: function(items) {
  107. this.items = items;
  108. this._renderPages();
  109. this._renderStatus();
  110. this._renderPager();
  111. },
  112. _renderPages: function(){
  113. var pcv = this.pagerContainerView;
  114. var _h = (this.orientation == "horizontal");
  115. var style = dojo.style;
  116. if(_h){
  117. var pagerH = dojo.marginBox(this.pagerContainerPager).h;
  118. var statusH = dojo.marginBox(this.pagerContainerStatus).h;
  119. if (this.pagerPos != 'center'){
  120. var addonHeight = pagerH+statusH;
  121. }else{
  122. var addonHeight = statusH;
  123. var widthSub = this.pagerIconNext.width;
  124. var containerWidth = style(pcv, 'width');
  125. var newWidth = containerWidth-(2*widthSub);
  126. style(pcv, {
  127. width: newWidth+'px',
  128. marginLeft: this.pagerIconNext.width+'px',
  129. marginRight: this.pagerIconNext.width+'px'
  130. });
  131. }
  132. var totalH = style(this.pagerContainer, 'height') - addonHeight;
  133. style(this.pagerContainerView, 'height', totalH+'px');
  134. var itemSpace = Math.floor(style(pcv, 'width') / this.itemsPage);
  135. if(this.statusPos == 'trailing'){
  136. if(this.pagerPos != 'center'){
  137. style(pcv, 'marginTop', pagerH+'px');
  138. }
  139. style(pcv, 'marginBottom', statusH+'px');
  140. }else{
  141. style(pcv, 'marginTop', statusH+'px');
  142. if (this.pagerPos != 'center'){
  143. style(pcv, 'marginTop', pagerH+'px');
  144. }
  145. }
  146. }else{
  147. var pagerW = dojo.marginBox(this.pagerContainerPager).w;
  148. var statusW = dojo.marginBox(this.pagerContainerStatus).w;
  149. var containerW = style(this.pagerContainer, 'width');
  150. if(this.pagerPos != 'center'){
  151. var addonWidth = pagerW + statusW;
  152. }else{
  153. var addonWidth = statusW;
  154. var heightSub = this.pagerIconNext.height;
  155. var containerHeight = style(pcv, 'height');
  156. var newHeight = containerHeight - (2 * heightSub);
  157. style(pcv,{
  158. height: newHeight+'px',
  159. marginTop: this.pagerIconNext.height+'px',
  160. marginBottom: this.pagerIconNext.height+'px'
  161. });
  162. }
  163. var totalW = style(this.pagerContainer, 'width') - addonWidth;
  164. style(pcv, 'width', totalW+'px');
  165. var itemSpace = Math.floor(style(pcv, 'height') / this.itemsPage);
  166. if(this.statusPos == 'trailing'){
  167. if (this.pagerPos != 'center'){
  168. style(pcv, 'marginLeft', pagerW + 'px');
  169. }
  170. style(pcv, 'marginRight', statusW + 'px');
  171. }else{
  172. style(pcv, 'marginLeft', statusW + 'px');
  173. if(this.pagerPos != 'center'){
  174. style(pcv, 'marginRight', pagerW+'px');
  175. }
  176. }
  177. }
  178. var _PagerItem = dojo.getObject(this.itemClass);
  179. var paddingLead = "padding" + (_h ? "Left" : "Top");
  180. var paddingTrail = "padding" + (_h ? "Right" : "Bottom");
  181. dojo.forEach(this.items, function(item, cnt){
  182. var contentContainer = dojo.create('div', {
  183. innerHTML: item.content
  184. });
  185. var pagerItem = new _PagerItem({
  186. id: this.id + '-item-' + (cnt + 1)
  187. }, contentContainer);
  188. this.pagerItems.appendChild(pagerItem.domNode);
  189. var containerProps = {};
  190. containerProps[(_h ? "width" : "height")] = (itemSpace - this.itemSpace) + "px";
  191. var p = (_h ? "height" : "width");
  192. containerProps[p] = style(pcv, p) + "px";
  193. style(pagerItem.containerNode, containerProps);
  194. if(this.resizeChildren){
  195. pagerItem.resizeChildren();
  196. }
  197. pagerItem.parseChildren();
  198. // only display amount of items as defined in itemsPage
  199. style(pagerItem.domNode, "position", "absolute");
  200. if (cnt < this.itemsPage){
  201. var pos = (cnt) * itemSpace;
  202. var trailingDir = (_h ? "left" : "top");
  203. var dir = (_h ? "top" : "left");
  204. style(pagerItem.domNode, dir, "0px");
  205. style(pagerItem.domNode, trailingDir, pos+"px");
  206. }else{
  207. style(pagerItem.domNode, "top", "-1000px");
  208. style(pagerItem.domNode, "left", "-1000px");
  209. }
  210. style(pagerItem.domNode, paddingTrail, (this.itemSpace/2)+"px");
  211. style(pagerItem.domNode, paddingLead, (this.itemSpace/2)+"px");
  212. }, this);
  213. },
  214. _renderPager: function() {
  215. var tcp = this.pagerContainerPager;
  216. var zero = "0px";
  217. var _h = (this.orientation == "horizontal");
  218. if(_h){
  219. if(this.statusPos == 'center'){
  220. }else if (this.statusPos == 'trailing'){
  221. dojo.style(tcp, 'top', zero);
  222. }else{
  223. dojo.style(tcp, 'bottom', zero);
  224. }
  225. dojo.style(this.pagerNext, 'right', zero);
  226. dojo.style(this.pagerPrevious, 'left', zero);
  227. }else{
  228. if (this.statusPos == 'trailing'){
  229. dojo.style(tcp, 'left', zero);
  230. }else{
  231. dojo.style(tcp, 'right', zero);
  232. }
  233. dojo.style(this.pagerNext, 'bottom', zero);
  234. dojo.style(this.pagerPrevious, 'top', zero);
  235. }
  236. },
  237. _renderStatus: function() {
  238. this._totalPages = Math.ceil(this.items.length / this.itemsPage);
  239. // FIXME!!
  240. this.iconWidth = 0;
  241. this.iconHeight = 0;
  242. this.iconsLoaded = 0;
  243. this._iconConnects = [];
  244. for (var i = 1; i <= this._totalPages; i++){
  245. var icon = new Image();
  246. var pointer = i;
  247. dojo.connect(icon, 'onclick', dojo.hitch(this, function(pointer) {
  248. this._pagerSkip(pointer);
  249. }, pointer));
  250. this._iconConnects[pointer] = dojo.connect(icon, 'onload', dojo.hitch(this,function(pointer){
  251. this.iconWidth += icon.width;
  252. this.iconHeight += icon.height;
  253. this.iconsLoaded++;
  254. if (this._totalPages == this.iconsLoaded){
  255. if (this.orientation == "horizontal"){
  256. if (this.statusPos == 'trailing'){
  257. if (this.pagerPos == 'center'){
  258. var containerHeight = dojo.style(this.pagerContainer, 'height');
  259. var statusHeight = dojo.style(this.pagerContainerStatus, 'height');
  260. dojo.style(this.pagerContainerPager, 'top', ((containerHeight/2)-(statusHeight/2))+'px');
  261. }
  262. dojo.style(this.pagerContainerStatus, 'bottom', '0px');
  263. }else{
  264. if (this.pagerPos == 'center'){
  265. var containerHeight = dojo.style(this.pagerContainer, 'height');
  266. var statusHeight = dojo.style(this.pagerContainerStatus, 'height');
  267. dojo.style(this.pagerContainerPager, 'bottom', ((containerHeight/2)-(statusHeight/2))+'px');
  268. }
  269. dojo.style(this.pagerContainerStatus, 'top', '0px');
  270. }
  271. var position = (dojo.style(this.pagerContainer, 'width')/2)-(this.iconWidth/2);
  272. dojo.style(this.pagerContainerStatus, 'paddingLeft', position+'px');
  273. }else{
  274. if (this.statusPos == 'trailing'){
  275. if (this.pagerPos == 'center'){
  276. var containerWidth = dojo.style(this.pagerContainer, 'width');
  277. var statusWidth = dojo.style(this.pagerContainerStatus, 'width');
  278. dojo.style(this.pagerContainerPager, 'left', ((containerWidth/2)-(statusWidth/2))+'px');
  279. }
  280. dojo.style(this.pagerContainerStatus, 'right', '0px');
  281. }else{
  282. if (this.pagerPos == 'center'){
  283. var containerWidth = dojo.style(this.pagerContainer, 'width');
  284. var statusWidth = dojo.style(this.pagerContainerStatus, 'width');
  285. dojo.style(this.pagerContainerPager, 'right', ((containerWidth/2)-(statusWidth/2))+'px');
  286. }
  287. dojo.style(this.pagerContainerStatus, 'left', '0px');
  288. }
  289. var position = (dojo.style(this.pagerContainer, 'height')/2)-(this.iconHeight/2);
  290. dojo.style(this.pagerContainerStatus, 'paddingTop', position+'px');
  291. }
  292. }
  293. dojo.disconnect(this._iconConnects[pointer]);
  294. }, pointer));
  295. if (i==this._currentPage){
  296. icon.src=this.iconPageActive;
  297. }else{
  298. icon.src=this.iconPage;
  299. }
  300. var pointer = i;
  301. dojo.addClass(icon, this.orientation+'PagerIcon');
  302. dojo.attr(icon, 'id', this.id+'-status-'+i);
  303. this.pagerContainerStatus.appendChild(icon);
  304. if (this.orientation == "vertical"){
  305. dojo.style(icon, 'display', 'block');
  306. }
  307. }
  308. },
  309. _pagerSkip: function(page){
  310. if (this._currentPage == page){
  311. return;
  312. }else{
  313. // calculate whether to go left or right, take shortest way
  314. var distanceP; var distanceN;
  315. if (page < this._currentPage){
  316. distanceP = this._currentPage - page;
  317. distanceN = (this._totalPages + page) - this._currentPage;
  318. }else{
  319. distanceP = (this._totalPages + this._currentPage) - page;
  320. distanceN = page - this._currentPage;
  321. }
  322. var b = (distanceN > distanceP);
  323. this._toScroll = (b ? distanceP : distanceN);
  324. var cmd = (b ? "_pagerPrevious" : "_pagerNext");
  325. var connect = this.connect(this, "onScrollEnd", function(){
  326. this._toScroll--;
  327. if(this._toScroll < 1){
  328. this.disconnect(connect);
  329. }else{
  330. this[cmd]();
  331. }
  332. });
  333. this[cmd]();
  334. }
  335. },
  336. _pagerNext: function(){
  337. if(this._anim) return;
  338. /**
  339. * fade slide out current items
  340. * make sure that next items are ligned up nicely before sliding them in
  341. */
  342. var _anims = [];
  343. for (var i = this._currentPage * this.itemsPage; i > (this._currentPage - 1) * this.itemsPage; i--){
  344. if (!dojo.byId(this.id+'-item-'+i)) continue;
  345. var currentItem = dojo.byId(this.id+'-item-'+i);
  346. var marginBox = dojo.marginBox(currentItem);
  347. if (this.orientation == "horizontal") {
  348. var move = marginBox.l - (this.itemsPage * marginBox.w);
  349. _anims.push(dojo.fx.slideTo({node: currentItem, left: move, duration: this.duration}));
  350. }else{
  351. var move = marginBox.t - (this.itemsPage * marginBox.h);
  352. _anims.push(dojo.fx.slideTo({node: currentItem, top: move, duration: this.duration}));
  353. }
  354. }
  355. var previousPage = this._currentPage;
  356. if (this._currentPage == this._totalPages){
  357. this._currentPage = 1;
  358. }else{
  359. this._currentPage++;
  360. }
  361. var cnt = this.itemsPage;
  362. for (var i=this._currentPage*this.itemsPage; i>(this._currentPage-1)*this.itemsPage; i--){
  363. if (dojo.byId(this.id+'-item-'+i)){
  364. var currentItem = dojo.byId(this.id+'-item-'+i);
  365. var marginBox = dojo.marginBox(currentItem);
  366. if (this.orientation == "horizontal") {
  367. var newPos = (dojo.style(this.pagerContainerView, 'width')+((cnt-1)*marginBox.w))-1;
  368. dojo.style(currentItem, 'left', newPos+'px');
  369. dojo.style(currentItem, 'top', '0px');
  370. var move = newPos-(this.itemsPage*marginBox.w);
  371. _anims.push(dojo.fx.slideTo({node: currentItem, left: move, duration: this.duration}));
  372. }else{
  373. newPos = (dojo.style(this.pagerContainerView, 'height')+((cnt-1)*marginBox.h))-1;
  374. dojo.style(currentItem, 'top', newPos+'px');
  375. dojo.style(currentItem, 'left', '0px');
  376. var move = newPos-(this.itemsPage*marginBox.h);
  377. _anims.push(dojo.fx.slideTo({ node: currentItem, top: move, duration: this.duration}));
  378. }
  379. }
  380. cnt--;
  381. }
  382. this._anim = dojo.fx.combine(_anims);
  383. var animConnect = this.connect(this._anim, "onEnd", function(){
  384. delete this._anim;
  385. this.onScrollEnd();
  386. this.disconnect(animConnect);
  387. });
  388. this._anim.play();
  389. // set pager icons
  390. dojo.byId(this.id+'-status-'+previousPage).src = this.iconPage;
  391. dojo.byId(this.id+'-status-'+this._currentPage).src = this.iconPageActive;
  392. },
  393. _pagerPrevious: function(){
  394. if(this._anim) return;
  395. var _anims = [];
  396. for (var i=this._currentPage*this.itemsPage; i>(this._currentPage-1)*this.itemsPage; i--){
  397. if (!dojo.byId(this.id+'-item-'+i)) continue;
  398. var currentItem = dojo.byId(this.id+'-item-'+i);
  399. var marginBox = dojo.marginBox(currentItem);
  400. if (this.orientation == "horizontal") {
  401. var move = dojo.style(currentItem, 'left')+(this.itemsPage*marginBox.w);
  402. _anims.push(dojo.fx.slideTo({node: currentItem, left: move, duration: this.duration}));
  403. }else{
  404. var move = dojo.style(currentItem, 'top')+(this.itemsPage*marginBox.h);
  405. _anims.push(dojo.fx.slideTo({node: currentItem, top: move, duration: this.duration}));
  406. }
  407. }
  408. var previousPage = this._currentPage;
  409. if (this._currentPage == 1){
  410. this._currentPage = this._totalPages;
  411. }else{
  412. this._currentPage--;
  413. }
  414. var cnt = this.itemsPage;
  415. var j=1;
  416. for (var i=this._currentPage*this.itemsPage; i>(this._currentPage-1)*this.itemsPage; i--){
  417. if(dojo.byId(this.id+'-item-'+i)){
  418. var currentItem = dojo.byId(this.id+'-item-'+i);
  419. var marginBox = dojo.marginBox(currentItem);
  420. if (this.orientation == "horizontal") {
  421. var newPos = -(j * marginBox.w) + 1;
  422. dojo.style(currentItem, 'left', newPos+'px');
  423. dojo.style(currentItem, 'top', '0px');
  424. var move = ((cnt - 1) * marginBox.w);
  425. _anims.push(dojo.fx.slideTo({node: currentItem, left: move, duration: this.duration}));
  426. var move = newPos+(this.itemsPage * marginBox.w);
  427. _anims.push(dojo.fx.slideTo({node: currentItem, left: move, duration: this.duration}));
  428. }else{
  429. newPos = -((j * marginBox.h) + 1);
  430. dojo.style(currentItem, 'top', newPos+'px');
  431. dojo.style(currentItem, 'left', '0px');
  432. var move = ((cnt - 1) * marginBox.h);
  433. _anims.push(dojo.fx.slideTo({node: currentItem, top: move, duration: this.duration}));
  434. }
  435. }
  436. cnt--;
  437. j++;
  438. }
  439. this._anim = dojo.fx.combine(_anims);
  440. var animConnect = dojo.connect(this._anim, "onEnd", dojo.hitch(this, function(){
  441. delete this._anim;
  442. this.onScrollEnd();
  443. dojo.disconnect(animConnect);
  444. }));
  445. this._anim.play();
  446. // set pager icons
  447. dojo.byId(this.id + '-status-' + previousPage).src = this.iconPage;
  448. dojo.byId(this.id + '-status-' + this._currentPage).src = this.iconPageActive;
  449. },
  450. onScrollEnd: function(){
  451. // summary: Stub Function. Fired after the slide is complete. Override or connect.
  452. }
  453. });
  454. dojo.declare("dojox.widget._PagerItem",
  455. [dijit._Widget, dijit._Templated],
  456. {
  457. templateString: '<li class="pagerItem" dojoAttachPoint="containerNode"></li>',
  458. resizeChildren: function(){
  459. var box = dojo.marginBox(this.containerNode);
  460. dojo.style(this.containerNode.firstChild, {
  461. width: box.w +'px',
  462. height: box.h + 'px'
  463. });
  464. },
  465. parseChildren: function(){
  466. dojo.parser.parse(this.containerNode);
  467. }
  468. });
  469. }