Pagination.js 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978
  1. require({cache:{
  2. 'url:dojox/grid/enhanced/templates/Pagination.html':"<div dojoAttachPoint=\"paginatorBar\"\n\t><table cellpadding=\"0\" cellspacing=\"0\" class=\"dojoxGridPaginator\"\n\t\t><tr\n\t\t\t><td dojoAttachPoint=\"descriptionTd\" class=\"dojoxGridDescriptionTd\"\n\t\t\t\t><div dojoAttachPoint=\"descriptionDiv\" class=\"dojoxGridDescription\"></div\n\t\t\t></div></td\n\t\t\t><td dojoAttachPoint=\"sizeSwitchTd\"></td\n\t\t\t><td dojoAttachPoint=\"pageStepperTd\" class=\"dojoxGridPaginatorFastStep\"\n\t\t\t\t><div dojoAttachPoint=\"pageStepperDiv\" class=\"dojoxGridPaginatorStep\"></div\n\t\t\t></td\n\t\t\t><td dojoAttachPoint=\"gotoPageTd\" class=\"dojoxGridPaginatorGotoTd\"\n\t\t\t\t><div dojoAttachPoint=\"gotoPageDiv\" class=\"dojoxGridPaginatorGotoDiv\" dojoAttachEvent=\"onclick:_openGotopageDialog, onkeydown:_openGotopageDialog\"\n\t\t\t\t\t><span class=\"dojoxGridWardButtonInner\">&#8869;</span\n\t\t\t\t></div\n\t\t\t></td\n\t\t></tr\n\t></table\n></div>\n"}});
  3. define("dojox/grid/enhanced/plugins/Pagination", [
  4. "dojo/_base/kernel",
  5. "dojo/_base/declare",
  6. "dojo/_base/array",
  7. "dojo/_base/connect",
  8. "dojo/_base/lang",
  9. "dojo/_base/html",
  10. "dojo/_base/event",
  11. "dojo/_base/window",
  12. "dojo/query",
  13. "dojo/string",
  14. "dojo/i18n",
  15. "dojo/keys",
  16. "dojo/text!../templates/Pagination.html",
  17. "./Dialog",
  18. "./_StoreLayer",
  19. "../_Plugin",
  20. "../../EnhancedGrid",
  21. "dijit/form/Button",
  22. "dijit/form/NumberTextBox",
  23. "dijit/focus",
  24. "dijit/_Widget",
  25. "dijit/_TemplatedMixin",
  26. "dijit/_WidgetsInTemplateMixin",
  27. "dojox/html/metrics",
  28. "dojo/i18n!../nls/Pagination"
  29. ], function(kernel, declare, array, connect, lang, html, event, win, query,
  30. string, i18n, keys, template, Dialog, layers, _Plugin, EnhancedGrid,
  31. Button, NumberTextBox, dijitFocus, _Widget, _TemplatedMixin, _WidgetsInTemplateMixin, metrics){
  32. var _GotoPagePane = declare("dojox.grid.enhanced.plugins.pagination._GotoPagePane", [_Widget, _TemplatedMixin, _WidgetsInTemplateMixin], {
  33. templateString: "<div>" +
  34. "<div class='dojoxGridDialogMargin' dojoAttachPoint='_mainMsgNode'></div>" +
  35. "<div class='dojoxGridDialogMargin'>" +
  36. "<input dojoType='dijit.form.NumberTextBox' style='width: 50px;' dojoAttachPoint='_pageInputBox' dojoAttachEvent='onKeyUp: _onKey'></input>" +
  37. "<label dojoAttachPoint='_pageLabelNode'></label>" +
  38. "</div>" +
  39. "<div class='dojoxGridDialogButton'>" +
  40. "<button dojoType='dijit.form.Button' dojoAttachPoint='_confirmBtn' dojoAttachEvent='onClick: _onConfirm'></button>" +
  41. "<button dojoType='dijit.form.Button' dojoAttachPoint='_cancelBtn' dojoAttachEvent='onClick: _onCancel'></button>" +
  42. "</div>" +
  43. "</div>",
  44. widgetsInTemplate: true,
  45. dlg: null,
  46. postMixInProperties: function(){
  47. this.plugin = this.dlg.plugin;
  48. },
  49. postCreate: function(){
  50. this.inherited(arguments);
  51. this._mainMsgNode.innerHTML = this.plugin._nls[12];
  52. this._confirmBtn.set("label", this.plugin._nls[14]);
  53. this._confirmBtn.set("disabled", true);
  54. this._cancelBtn.set("label", this.plugin._nls[15]);
  55. },
  56. _onConfirm: function(evt){
  57. if(this._pageInputBox.isValid() && this._pageInputBox.getDisplayedValue() !== ""){
  58. this.plugin.currentPage(this._pageInputBox.parse(this._pageInputBox.getDisplayedValue()));
  59. this.dlg._gotoPageDialog.hide();
  60. this._pageInputBox.reset();
  61. }
  62. stopEvent(evt);
  63. },
  64. _onCancel: function(evt){
  65. this._pageInputBox.reset();
  66. this.dlg._gotoPageDialog.hide();
  67. stopEvent(evt);
  68. },
  69. _onKey: function(evt){
  70. this._confirmBtn.set("disabled", !this._pageInputBox.isValid() || this._pageInputBox.getDisplayedValue() == "");
  71. if(!evt.altKey && !evt.metaKey && evt.keyCode === keys.ENTER){
  72. this._onConfirm(evt);
  73. }
  74. }
  75. });
  76. var _GotoPageDialog = declare("dojox.grid.enhanced.plugins.pagination._GotoPageDialog", null, {
  77. pageCount: 0,
  78. dlgPane: null,
  79. constructor: function(plugin){
  80. this.plugin = plugin;
  81. this.dlgPane = new _GotoPagePane({"dlg": this});
  82. this.dlgPane.startup();
  83. this._gotoPageDialog = new Dialog({
  84. "refNode": plugin.grid.domNode,
  85. "title": this.plugin._nls[11],
  86. "content": this.dlgPane
  87. });
  88. this._gotoPageDialog.startup();
  89. },
  90. _updatePageCount: function(){
  91. this.pageCount = this.plugin.getTotalPageNum();
  92. this.dlgPane._pageInputBox.constraints = {fractional:false, min:1, max:this.pageCount};
  93. this.dlgPane._pageLabelNode.innerHTML = string.substitute(this.plugin._nls[13], [this.pageCount]);
  94. },
  95. showDialog: function(){
  96. this._updatePageCount();
  97. this._gotoPageDialog.show();
  98. },
  99. destroy: function(){
  100. this._gotoPageDialog.destroy();
  101. }
  102. });
  103. var _ForcedPageStoreLayer = declare("dojox.grid.enhanced.plugins._ForcedPageStoreLayer", layers._StoreLayer, {
  104. tags: ["presentation"],
  105. constructor: function(plugin){
  106. this._plugin = plugin;
  107. },
  108. _fetch: function(request){
  109. var _this = this,
  110. plugin = _this._plugin,
  111. grid = plugin.grid,
  112. scope = request.scope || win.global,
  113. onBegin = request.onBegin;
  114. request.start = (plugin._currentPage - 1) * plugin._currentPageSize + request.start;
  115. _this.startIdx = request.start;
  116. _this.endIdx = request.start + plugin._currentPageSize - 1;
  117. var p = plugin._paginator;
  118. if(!plugin._showAll){
  119. plugin._showAll = !p.sizeSwitch && !p.pageStepper && !p.gotoButton;
  120. }
  121. if(onBegin && plugin._showAll){
  122. request.onBegin = function(size, req){
  123. plugin._maxSize = plugin._currentPageSize = size;
  124. _this.startIdx = 0;
  125. _this.endIdx = size - 1;
  126. plugin._paginator._update();
  127. req.onBegin = onBegin;
  128. req.onBegin.call(scope, size, req);
  129. };
  130. }else if(onBegin){
  131. request.onBegin = function(size, req){
  132. req.start = 0;
  133. req.count = plugin._currentPageSize;
  134. plugin._maxSize = size;
  135. _this.endIdx = _this.endIdx >= size ? (size - 1) : _this.endIdx;
  136. if(_this.startIdx > size && size !== 0){
  137. grid._pending_requests[req.start] = false;
  138. plugin.firstPage();
  139. }
  140. plugin._paginator._update();
  141. req.onBegin = onBegin;
  142. req.onBegin.call(scope, Math.min(plugin._currentPageSize, (size - _this.startIdx)), req);
  143. };
  144. }
  145. return lang.hitch(this._store, this._originFetch)(request);
  146. }
  147. });
  148. var stopEvent = function(evt){
  149. try{
  150. if(evt){
  151. event.stop(evt);
  152. }
  153. }catch(e){}
  154. };
  155. var _Focus = declare("dojox.grid.enhanced.plugins.pagination._Focus", null, {
  156. _focusedNode: null,
  157. _isFocused: false,
  158. constructor: function(paginator){
  159. this._pager = paginator;
  160. var focusMgr = paginator.plugin.grid.focus;
  161. paginator.plugin.connect(paginator, 'onSwitchPageSize', lang.hitch(this, '_onActive'));
  162. paginator.plugin.connect(paginator, 'onPageStep', lang.hitch(this, '_onActive'));
  163. paginator.plugin.connect(paginator, 'onShowGotoPageDialog', lang.hitch(this, '_onActive'));
  164. paginator.plugin.connect(paginator, '_update', lang.hitch(this, '_moveFocus'));
  165. },
  166. _onFocus: function(evt, step){
  167. var node, nodes;
  168. if(!this._isFocused){
  169. node = this._focusedNode || query('[tabindex]', this._pager.domNode)[0];
  170. }else if(step && this._focusedNode){
  171. var dir = step > 0 ? -1 : 1,
  172. tabindex = parseInt(this._focusedNode.getAttribute('tabindex'), 10) + dir;
  173. while(tabindex >= -3 && tabindex < 0){
  174. node = query('[tabindex=' + tabindex + ']', this._pager.domNode)[0];
  175. if(node){
  176. break;
  177. }else{
  178. tabindex += dir;
  179. }
  180. }
  181. }
  182. return this._focus(node, evt);
  183. },
  184. _onBlur: function(evt, step){
  185. if(!step || !this._focusedNode){
  186. this._isFocused = false;
  187. if(this._focusedNode && html.hasClass(this._focusedNode, 'dojoxGridButtonFocus')){
  188. html.removeClass(this._focusedNode, 'dojoxGridButtonFocus');
  189. }
  190. return true;
  191. }
  192. var node, dir = step > 0 ? -1 : 1,
  193. tabindex = parseInt(this._focusedNode.getAttribute('tabindex'), 10) + dir;
  194. while(tabindex >= -3 && tabindex < 0){
  195. node = query('[tabindex=' + tabindex + ']', this._pager.domNode)[0];
  196. if(node){
  197. break;
  198. }else{
  199. tabindex += dir;
  200. }
  201. }
  202. if(!node){
  203. this._isFocused = false;
  204. if(html.hasClass(this._focusedNode, 'dojoxGridButtonFocus')){
  205. html.removeClass(this._focusedNode, 'dojoxGridButtonFocus');
  206. }
  207. }
  208. return node ? false : true;
  209. },
  210. _onMove: function(rowDelta, colDelta, evt){
  211. if(this._focusedNode){
  212. var tabindex = this._focusedNode.getAttribute('tabindex'),
  213. delta = colDelta == 1 ? "nextSibling" : "previousSibling",
  214. node = this._focusedNode[delta];
  215. while(node){
  216. if(node.getAttribute('tabindex') == tabindex){
  217. this._focus(node);
  218. break;
  219. }
  220. node = node[delta];
  221. }
  222. }
  223. },
  224. _focus: function(node, evt){
  225. if(node){
  226. this._isFocused = true;
  227. if(kernel.isIE && this._focusedNode){
  228. html.removeClass(this._focusedNode, 'dojoxGridButtonFocus');
  229. }
  230. this._focusedNode = node;
  231. node.focus();
  232. if(kernel.isIE){
  233. html.addClass(node, 'dojoxGridButtonFocus');
  234. }
  235. stopEvent(evt);
  236. return true;
  237. }
  238. return false;
  239. },
  240. _onActive: function(e){
  241. this._focusedNode = e.target;
  242. if(!this._isFocused){
  243. this._pager.plugin.grid.focus.focusArea('pagination' + this._pager.position);
  244. }
  245. },
  246. _moveFocus: function(){
  247. if(this._focusedNode && !this._focusedNode.getAttribute('tabindex')){
  248. var next = this._focusedNode.nextSibling;
  249. while(next){
  250. if(next.getAttribute('tabindex')){
  251. this._focus(next);
  252. return;
  253. }
  254. next = next.nextSibling;
  255. }
  256. var prev = this._focusedNode.previousSibling;
  257. while(prev){
  258. if(prev.getAttribute('tabindex')){
  259. this._focus(prev);
  260. return;
  261. }
  262. prev = prev.previousSibling;
  263. }
  264. this._focusedNode = null;
  265. this._onBlur();
  266. }else if(kernel.isIE && this._focusedNode){
  267. html.addClass(this._focusedNode, 'dojoxGridButtonFocus');
  268. }
  269. }
  270. });
  271. var _Paginator = declare("dojox.grid.enhanced.plugins._Paginator", [_Widget, _TemplatedMixin], {
  272. templateString: template,
  273. constructor: function(params){
  274. lang.mixin(this, params);
  275. this.grid = this.plugin.grid;
  276. },
  277. postCreate: function(){
  278. this.inherited(arguments);
  279. var _this = this, g = this.grid;
  280. this.plugin.connect(g, "_resize", lang.hitch(this, "_resetGridHeight"));
  281. this._originalResize = g.resize;
  282. g.resize = function(changeSize, resultSize){
  283. _this._changeSize = changeSize;
  284. _this._resultSize = resultSize;
  285. _this._originalResize.apply(g, arguments);
  286. };
  287. this.focus = _Focus(this);
  288. this._placeSelf();
  289. },
  290. destroy: function(){
  291. this.inherited(arguments);
  292. this.grid.focus.removeArea("pagination" + this.position);
  293. if(this._gotoPageDialog){
  294. this._gotoPageDialog.destroy();
  295. }
  296. this.grid.resize = this._originalResize;
  297. },
  298. onSwitchPageSize: function(/*Event*/evt){
  299. },
  300. onPageStep: function(/*Event*/evt){
  301. },
  302. onShowGotoPageDialog: function(/*Event*/evt){
  303. },
  304. _update: function(){
  305. // summary:
  306. // Function to update paging information and update
  307. // pagination bar display.
  308. this._updateDescription();
  309. this._updatePageStepper();
  310. this._updateSizeSwitch();
  311. this._updateGotoButton();
  312. },
  313. _registerFocus: function(isTop){
  314. // summary:
  315. // Function to register pagination bar to focus manager.
  316. var focusMgr = this.grid.focus,
  317. name = "pagination" + this.position,
  318. f = this.focus;
  319. focusMgr.addArea({
  320. name: name,
  321. onFocus: lang.hitch(this.focus, "_onFocus"),
  322. onBlur: lang.hitch(this.focus, "_onBlur"),
  323. onMove: lang.hitch(this.focus, "_onMove")
  324. });
  325. focusMgr.placeArea(name, isTop ? "before" : "after", isTop ? "header" : "content");
  326. },
  327. _placeSelf: function(){
  328. // summary:
  329. // Place pagination bar to a position.
  330. // There are two options, top of the grid, bottom of the grid.
  331. var g = this.grid,
  332. isTop = this.position == "top";
  333. this.placeAt(isTop ? g.viewsHeaderNode : g.viewsNode, isTop ? "before" : "after");
  334. this._registerFocus(isTop);
  335. },
  336. _resetGridHeight: function(changeSize, resultSize){
  337. // summary:
  338. // Function of resize grid height to place this pagination bar.
  339. // Since the grid would be able to add other element in its domNode, we have
  340. // change the grid view size to place the pagination bar.
  341. // This function will resize the grid viewsNode height, scorllboxNode height
  342. var g = this.grid;
  343. changeSize = changeSize || this._changeSize;
  344. resultSize = resultSize || this._resultSize;
  345. delete this._changeSize;
  346. delete this._resultSize;
  347. if(g._autoHeight){
  348. return;
  349. }
  350. var padBorder = g._getPadBorder().h;
  351. if(!this.plugin.gh){
  352. this.plugin.gh = (g.domNode.clientHeight || html.style(g.domNode, 'height')) + 2 * padBorder;
  353. }
  354. if(resultSize){
  355. changeSize = resultSize;
  356. }
  357. if(changeSize){
  358. this.plugin.gh = html.contentBox(g.domNode).h + 2 * padBorder;
  359. }
  360. var gh = this.plugin.gh,
  361. hh = g._getHeaderHeight(),
  362. ph = html.marginBox(this.domNode).h;
  363. // ph = this.plugin._paginator.position == "bottom" ? ph * 2 : ph;
  364. if(typeof g.autoHeight === "number"){
  365. var cgh = gh + ph - padBorder;
  366. html.style(g.domNode, "height", cgh + "px");
  367. html.style(g.viewsNode, "height", (cgh - ph - hh) + "px");
  368. this._styleMsgNode(hh, html.marginBox(g.viewsNode).w, cgh - ph - hh);
  369. }else{
  370. var h = gh - ph - hh - padBorder;
  371. html.style(g.viewsNode, "height", h + "px");
  372. var hasHScroller = array.some(g.views.views, function(v){
  373. return v.hasHScrollbar();
  374. });
  375. array.forEach(g.viewsNode.childNodes, function(c){
  376. html.style(c, "height", h + "px");
  377. });
  378. array.forEach(g.views.views, function(v){
  379. if(v.scrollboxNode){
  380. if(!v.hasHScrollbar() && hasHScroller){
  381. html.style(v.scrollboxNode, "height", (h - metrics.getScrollbar().h) + "px");
  382. }else{
  383. html.style(v.scrollboxNode, "height", h + "px");
  384. }
  385. }
  386. });
  387. this._styleMsgNode(hh, html.marginBox(g.viewsNode).w, h);
  388. }
  389. },
  390. _styleMsgNode: function(top, width, height){
  391. var messagesNode = this.grid.messagesNode;
  392. html.style(messagesNode, {"position": "absolute", "top": top + "px", "width": width + "px", "height": height + "px", "z-Index": "100"});
  393. },
  394. _updateDescription: function(){
  395. // summary:
  396. // Update size information.
  397. var s = this.plugin.forcePageStoreLayer,
  398. maxSize = this.plugin._maxSize,
  399. nls = this.plugin._nls,
  400. getItemTitle = function(){
  401. return maxSize <= 0 || maxSize == 1 ? nls[5] : nls[4];
  402. };
  403. if(this.description && this.descriptionDiv){
  404. this.descriptionDiv.innerHTML = maxSize > 0 ? string.substitute(nls[0], [getItemTitle(), maxSize, s.startIdx + 1, s.endIdx + 1]) : "0 " + getItemTitle();
  405. }
  406. },
  407. _updateSizeSwitch: function(){
  408. // summary:
  409. // Update "items per page" information.
  410. html.style(this.sizeSwitchTd, "display", this.sizeSwitch ? "" : "none");
  411. if(!this.sizeSwitch){
  412. return;
  413. }
  414. if(this.sizeSwitchTd.childNodes.length < 1){
  415. this._createSizeSwitchNodes();
  416. }
  417. this._updateSwitchNodesStyle();
  418. },
  419. _createSizeSwitchNodes: function(){
  420. // summary:
  421. // The function to create the size switch nodes
  422. var node = null,
  423. nls = this.plugin._nls,
  424. connect = lang.hitch(this.plugin, 'connect');
  425. array.forEach(this.pageSizes, function(size){
  426. // create page size switch node
  427. var labelValue = isFinite(size) ? string.substitute(nls[2], [size]) : nls[1],
  428. value = isFinite(size) ? size : nls[16];
  429. node = html.create("span", {innerHTML: value, title: labelValue, value: size, tabindex: "-1"}, this.sizeSwitchTd, "last");
  430. // for accessibility
  431. node.setAttribute("aria-label", labelValue);
  432. // connect event
  433. connect(node, "onclick", lang.hitch(this, "_onSwitchPageSize"));
  434. connect(node, "onkeydown", lang.hitch(this, "_onSwitchPageSize"));
  435. connect(node, "onmouseover", function(e){
  436. html.addClass(e.target, "dojoxGridPageTextHover");
  437. });
  438. connect(node, "onmouseout", function(e){
  439. html.removeClass(e.target, "dojoxGridPageTextHover");
  440. });
  441. // create a separation node
  442. node = html.create("span", {innerHTML: "|"}, this.sizeSwitchTd, "last");
  443. html.addClass(node, "dojoxGridSeparator");
  444. }, this);
  445. // delete last separation node
  446. html.destroy(node);
  447. },
  448. _updateSwitchNodesStyle: function(){
  449. // summary:
  450. // Update the switch nodes style
  451. var size = null;
  452. var styleNode = function(node, status){
  453. if(status){
  454. html.addClass(node, "dojoxGridActivedSwitch");
  455. html.removeAttr(node, "tabindex");
  456. }else{
  457. html.addClass(node, "dojoxGridInactiveSwitch");
  458. node.setAttribute("tabindex", "-1");
  459. }
  460. };
  461. array.forEach(this.sizeSwitchTd.childNodes, function(node){
  462. if(node.value){
  463. html.removeClass(node);
  464. size = node.value;
  465. if(this.plugin._showAll){
  466. styleNode(node, isNaN(parseInt(size, 10)));
  467. }else{
  468. styleNode(node, this.plugin._currentPageSize == size);
  469. }
  470. }
  471. }, this);
  472. },
  473. _updatePageStepper: function(){
  474. // summary:
  475. // Update the page step nodes
  476. html.style(this.pageStepperTd, "display", this.pageStepper ? "" : "none");
  477. if(!this.pageStepper){
  478. return;
  479. }
  480. if(this.pageStepperDiv.childNodes.length < 1){
  481. this._createPageStepNodes();
  482. this._createWardBtns();
  483. }else{
  484. this._resetPageStepNodes();
  485. }
  486. this._updatePageStepNodesStyle();
  487. },
  488. _createPageStepNodes: function(){
  489. // summary:
  490. // Create the page step nodes if they do not exist
  491. var startPage = this._getStartPage(),
  492. stepSize = this._getStepPageSize(),
  493. label = "", node = null, i = startPage,
  494. connect = lang.hitch(this.plugin, 'connect');
  495. for(; i < startPage + this.maxPageStep + 1; i++){
  496. label = string.substitute(this.plugin._nls[3], [i]);
  497. node = html.create("div", {innerHTML: i, value: i, title: label}, this.pageStepperDiv, "last");
  498. node.setAttribute("aria-label", label);
  499. // connect event
  500. connect(node, "onclick", lang.hitch(this, "_onPageStep"));
  501. connect(node, "onkeydown", lang.hitch(this, "_onPageStep"));
  502. connect(node, "onmouseover", function(e){
  503. html.addClass(e.target, "dojoxGridPageTextHover");
  504. });
  505. connect(node, "onmouseout", function(e){
  506. html.removeClass(e.target, "dojoxGridPageTextHover");
  507. });
  508. html.style(node, "display", i < startPage + stepSize ? "" : "none");
  509. }
  510. },
  511. _createWardBtns: function(){
  512. // summary:
  513. // Create the previous/next/first/last button
  514. var _this = this, nls = this.plugin._nls;
  515. var highContrastLabel = {prevPage: "&#60;", firstPage: "&#171;", nextPage: "&#62;", lastPage: "&#187;"};
  516. var createWardBtn = function(value, label, position){
  517. var node = html.create("div", {value: value, title: label, tabindex: "-2"}, _this.pageStepperDiv, position);
  518. _this.plugin.connect(node, "onclick", lang.hitch(_this, "_onPageStep"));
  519. _this.plugin.connect(node, "onkeydown", lang.hitch(_this, "_onPageStep"));
  520. node.setAttribute("aria-label", label);
  521. // for high contrast
  522. var highConrastNode = html.create("span", {value: value, title: label, innerHTML: highContrastLabel[value]}, node, position);
  523. html.addClass(highConrastNode, "dojoxGridWardButtonInner");
  524. };
  525. createWardBtn("prevPage", nls[6], "first");
  526. createWardBtn("firstPage", nls[7], "first");
  527. createWardBtn("nextPage", nls[8], "last");
  528. createWardBtn("lastPage", nls[9], "last");
  529. },
  530. _resetPageStepNodes: function(){
  531. // summary:
  532. // The page step nodes might be changed when fetch data, we need to
  533. // update/reset them
  534. var startPage = this._getStartPage(),
  535. stepSize = this._getStepPageSize(),
  536. stepNodes = this.pageStepperDiv.childNodes,
  537. node = null, i = startPage, j = 2, tip;
  538. for(; j < stepNodes.length - 2; j++, i++){
  539. node = stepNodes[j];
  540. if(i < startPage + stepSize){
  541. tip = string.substitute(this.plugin._nls[3], [i]);
  542. html.attr(node, {
  543. "innerHTML": i,
  544. "title": tip,
  545. "value": i
  546. });
  547. html.style(node, "display", "");
  548. node.setAttribute("aria-label", tip);
  549. }else{
  550. html.style(node, "display", "none");
  551. }
  552. }
  553. },
  554. _updatePageStepNodesStyle: function(){
  555. // summary:
  556. // Update the style of the page step nodes
  557. var value = null,
  558. curPage = this.plugin.currentPage(),
  559. pageCount = this.plugin.getTotalPageNum();
  560. var updateClass = function(node, isWardBtn, status){
  561. var value = node.value,
  562. enableClass = isWardBtn ? "dojoxGrid" + value + "Btn" : "dojoxGridInactived",
  563. disableClass = isWardBtn ? "dojoxGrid" + value + "BtnDisable" : "dojoxGridActived";
  564. if(status){
  565. html.addClass(node, disableClass);
  566. html.removeAttr(node, "tabindex");
  567. }else{
  568. html.addClass(node, enableClass);
  569. node.setAttribute("tabindex", "-2");
  570. }
  571. };
  572. array.forEach(this.pageStepperDiv.childNodes, function(node){
  573. html.removeClass(node);
  574. if(isNaN(parseInt(node.value, 10))){
  575. html.addClass(node, "dojoxGridWardButton");
  576. var disablePageNum = node.value == "prevPage" || node.value == "firstPage" ? 1 : pageCount;
  577. updateClass(node, true, (curPage === disablePageNum));
  578. }else{
  579. value = parseInt(node.value, 10);
  580. updateClass(node, false, (value === curPage || html.style(node, "display") === "none"));
  581. }
  582. }, this);
  583. },
  584. _showGotoButton: function(flag){
  585. this.gotoButton = flag;
  586. this._updateGotoButton();
  587. },
  588. _updateGotoButton: function(){
  589. // summary:
  590. // Create/destroy the goto page button
  591. if(!this.gotoButton){
  592. if(this._gotoPageDialog){
  593. this._gotoPageDialog.destroy();
  594. }
  595. html.removeAttr(this.gotoPageDiv, "tabindex");
  596. html.style(this.gotoPageTd, 'display', 'none');
  597. return;
  598. }
  599. if(html.style(this.gotoPageTd, 'display') == 'none'){
  600. html.style(this.gotoPageTd, 'display', '');
  601. }
  602. this.gotoPageDiv.setAttribute('title', this.plugin._nls[10]);
  603. html.toggleClass(this.gotoPageDiv, "dojoxGridPaginatorGotoDivDisabled", this.plugin.getTotalPageNum() <= 1);
  604. if(this.plugin.getTotalPageNum() <= 1){
  605. html.removeAttr(this.gotoPageDiv, "tabindex");
  606. }else{
  607. this.gotoPageDiv.setAttribute("tabindex", "-3");
  608. }
  609. },
  610. _openGotopageDialog: function(e){
  611. // summary:
  612. // Show the goto page dialog
  613. if(this.plugin.getTotalPageNum() <= 1){
  614. return;
  615. }
  616. if(e.type === "keydown" && e.keyCode !== keys.ENTER && e.keyCode !== keys.SPACE){
  617. return;
  618. }
  619. if(!this._gotoPageDialog){
  620. this._gotoPageDialog = new _GotoPageDialog(this.plugin);
  621. }
  622. this._gotoPageDialog.showDialog();
  623. this.onShowGotoPageDialog(e);
  624. },
  625. _onSwitchPageSize: function(/*Event*/e){
  626. // summary:
  627. // The handler of switch the page size
  628. if(e.type === "keydown" && e.keyCode !== keys.ENTER && e.keyCode !== keys.SPACE){
  629. return;
  630. }
  631. this.onSwitchPageSize(e);
  632. this.plugin.currentPageSize(e.target.value);
  633. },
  634. _onPageStep: function(/*Event*/e){
  635. // summary:
  636. // The handler jump page event
  637. if(e.type === "keydown" && e.keyCode !== keys.ENTER && e.keyCode !== keys.SPACE){
  638. return;
  639. }
  640. var p = this.plugin,
  641. value = e.target.value;
  642. this.onPageStep(e);
  643. if(!isNaN(parseInt(value, 10))){
  644. p.currentPage(parseInt(value, 10));
  645. }else{
  646. p[value]();
  647. }
  648. },
  649. _getStartPage: function(){
  650. var cp = this.plugin.currentPage(),
  651. ms = this.maxPageStep,
  652. hs = parseInt(ms / 2, 10),
  653. tp = this.plugin.getTotalPageNum();
  654. if(cp < hs || (cp - hs) < 1 || tp <= ms){
  655. return 1;
  656. }else{
  657. return tp - cp < hs && cp - ms >= 0 ? tp - ms + 1 : cp - hs;
  658. }
  659. },
  660. _getStepPageSize: function(){
  661. var sp = this._getStartPage(),
  662. tp = this.plugin.getTotalPageNum(),
  663. ms = this.maxPageStep;
  664. return sp + ms > tp ? tp - sp + 1 : ms;
  665. }
  666. });
  667. var Pagination = declare("dojox.grid.enhanced.plugins.Pagination", _Plugin, {
  668. // summary:
  669. // The typical pagination way to deal with huge dataset
  670. // an alternative for the default virtual scrolling manner.
  671. name: "pagination",
  672. // defaultPageSize: Integer
  673. // Number of rows in a page, 25 by default.
  674. defaultPageSize: 25,
  675. // defaultPage: Integer
  676. // Which page will be displayed initially, 1st page by default.
  677. defaultPage: 1,
  678. // description: boolean
  679. // Whether the description information will be displayed, true by default.
  680. description: true,
  681. // sizeSwitch: boolean
  682. // Whether the page size switch options will be displayed, true by default.
  683. sizeSwitch: true,
  684. // pageStepper: boolean
  685. // Whether the page switch options will be displayed, true by default.
  686. pageStepper: true,
  687. // gotoButton: boolean
  688. // Whether the goto page button will be displayed, false by default.
  689. gotoButton: false,
  690. // pageSizes: Array
  691. // Array of page sizes for switching, e.g. [10, 25, 50, 100, Infinity] by default,
  692. // Infinity or any NaN value will be treated as "all".
  693. pageSizes: [10, 25, 50, 100, Infinity],
  694. // maxPageStep: Integer
  695. // The max number of page sizes to be displayed, 7 by default.
  696. maxPageStep: 7,
  697. // position: string
  698. // The position of the pagination bar - "top"|"bottom", "bottom" by default.
  699. position: 'bottom',
  700. init: function(){
  701. var g = this.grid;
  702. g.usingPagination = true;
  703. this._initOptions();
  704. this._currentPage = this.defaultPage;
  705. this._currentPageSize = this.grid.rowsPerPage = this.defaultPageSize;
  706. // wrap store layer
  707. this._store = g.store;
  708. this.forcePageStoreLayer = new _ForcedPageStoreLayer(this);
  709. layers.wrap(g, "_storeLayerFetch", this.forcePageStoreLayer);
  710. // create pagination bar
  711. this._paginator = this.option.position != "top" ?
  712. new _Paginator(lang.mixin(this.option, {position: "bottom", plugin: this})) :
  713. new _Paginator(lang.mixin(this.option, {position: "top", plugin: this}));
  714. this._regApis();
  715. },
  716. destroy: function(){
  717. this.inherited(arguments);
  718. this._paginator.destroy();
  719. var g = this.grid;
  720. g.unwrap(this.forcePageStoreLayer.name());
  721. g.scrollToRow = this._gridOriginalfuncs[0];
  722. g._onNew = this._gridOriginalfuncs[1];
  723. g.removeSelectedRows = this._gridOriginalfuncs[2];
  724. this._paginator = null;
  725. this._nls = null;
  726. },
  727. currentPage: function(page){
  728. // summary:
  729. // Shift to the given page, return current page number. If there
  730. // is no valid page was passed in, just return current page num.
  731. // page: Integer
  732. // The page to go to, starting at 1.
  733. // return:
  734. // Current page number
  735. if(page <= this.getTotalPageNum() && page > 0 && this._currentPage !== page){
  736. this._currentPage = page;
  737. this.grid._refresh(true);
  738. this.grid.resize();
  739. }
  740. return this._currentPage;
  741. },
  742. nextPage: function(){
  743. // summary:
  744. // Go to the next page.
  745. this.currentPage(this._currentPage + 1);
  746. },
  747. prevPage: function(){
  748. // summary:
  749. // Go to the previous page.
  750. this.currentPage(this._currentPage - 1);
  751. },
  752. firstPage: function(){
  753. // summary:
  754. // Go to the first page
  755. this.currentPage(1);
  756. },
  757. lastPage: function(){
  758. // summary:
  759. // Go to the last page
  760. this.currentPage(this.getTotalPageNum());
  761. },
  762. currentPageSize: function(size){
  763. // summary:
  764. // Change the size of current page or return the current page size.
  765. // size: Integer || null
  766. // An integer identifying the number of rows per page. If the size
  767. // is an Infinity, all rows will be displayed; if an invalid value pssed
  768. // in, the current page size will be returned.
  769. // return
  770. // Current size of items per page.
  771. if(!isNaN(size)){
  772. var g = this.grid,
  773. startIndex = this._currentPageSize * (this._currentPage - 1), endIndex;
  774. this._showAll = !isFinite(size);
  775. this.grid.usingPagination = !this._showAll;
  776. this._currentPageSize = this._showAll ? this._maxSize : size;
  777. g.rowsPerPage = this._showAll ? this._defaultRowsPerPage : size;
  778. endIndex = startIndex + Math.min(this._currentPageSize, this._maxSize);
  779. if(endIndex > this._maxSize){
  780. this.lastPage();
  781. }else{
  782. var cp = Math.ceil(startIndex / this._currentPageSize) + 1;
  783. if(cp !== this._currentPage){
  784. this.currentPage(cp);
  785. }else{
  786. this.grid._refresh(true);
  787. }
  788. }
  789. this.grid.resize();
  790. }
  791. return this._currentPageSize;
  792. },
  793. getTotalPageNum: function(){
  794. // summary:
  795. // Get total page number
  796. return Math.ceil(this._maxSize / this._currentPageSize);
  797. },
  798. getTotalRowCount: function(){
  799. // summary:
  800. // Function for get total row count
  801. return this._maxSize;
  802. },
  803. scrollToRow: function(inRowIndex){
  804. // summary:
  805. // Override the grid.scrollToRow(), could jump to the right page
  806. // and scroll to the specific row
  807. // inRowIndex: integer
  808. // The row index
  809. var page = parseInt(inRowIndex / this._currentPageSize, 10) + 1;
  810. if(page > this.getTotalPageNum()){
  811. return;
  812. }
  813. this.currentPage(page);
  814. var rowIdx = inRowIndex % this._currentPageSize;
  815. return this._gridOriginalfuncs[0](rowIdx);
  816. },
  817. removeSelectedRows: function(){
  818. this._multiRemoving = true;
  819. this._gridOriginalfuncs[2].apply();
  820. this._multiRemoving = false;
  821. if(this.grid.store.save){
  822. this.grid.store.save();
  823. }
  824. this.grid.resize();
  825. this.grid._refresh();
  826. },
  827. showGotoPageButton: function(flag){
  828. // summary:
  829. // For show/hide the go to page button dynamically
  830. // flag: boolean
  831. // Show the go to page button when flag is true, otherwise hide it
  832. this._paginator.gotoButton = flag;
  833. this._paginator._updateGotoButton();
  834. },
  835. // [DEPRECATED] ============
  836. gotoPage: function(page){
  837. kernel.deprecated("dojox.grid.enhanced.EnhancedGrid.gotoPage(page)", "use dojox.grid.enhanced.EnhancedGrid.currentPage(page) instead", "1.8");
  838. this.currentPage(page);
  839. },
  840. gotoFirstPage: function(){
  841. kernel.deprecated("dojox.grid.enhanced.EnhancedGrid.gotoFirstPage()", "use dojox.grid.enhanced.EnhancedGrid.firstPage() instead", "1.8");
  842. this.firstPage();
  843. },
  844. gotoLastPage: function(){
  845. kernel.deprecated("dojox.grid.enhanced.EnhancedGrid.gotoLastPage()", "use dojox.grid.enhanced.EnhancedGrid.lastPage() instead", "1.8");
  846. this.lastPage();
  847. },
  848. changePageSize: function(size){
  849. kernel.deprecated("dojox.grid.enhanced.EnhancedGrid.changePageSize(size)", "use dojox.grid.enhanced.EnhancedGrid.currentPageSize(size) instead", "1.8");
  850. this.currentPageSize(size);
  851. },
  852. // =============== Protected ================
  853. _nls: null,
  854. _showAll: false,
  855. _maxSize: 0,
  856. // =============== Private ===============
  857. _defaultRowsPerPage: 25,
  858. _currentPage: 1,
  859. _currentPageSize: 25,
  860. _initOptions: function(){
  861. this._defaultRowsPerPage = this.grid.rowsPerPage || 25;
  862. this.defaultPage = this.option.defaultPage >= 1 ? parseInt(this.option.defaultPage, 10) : 1;
  863. this.option.description = this.option.description !== undefined ? !!this.option.description : this.description;
  864. this.option.sizeSwitch = this.option.sizeSwitch !== undefined ? !!this.option.sizeSwitch : this.sizeSwitch;
  865. this.option.pageStepper = this.option.pageStepper !== undefined ? !!this.option.pageStepper : this.pageStepper;
  866. this.option.gotoButton = this.option.gotoButton !== undefined ? !!this.option.gotoButton : this.gotoButton;
  867. if(lang.isArray(this.option.pageSizes)){
  868. var pageSizes = [];
  869. array.forEach(this.option.pageSizes, function(size){
  870. size = typeof size == 'number' ? size : parseInt(size, 10);
  871. if(!isNaN(size) && size > 0){
  872. pageSizes.push(size);
  873. }else if(array.indexOf(pageSizes, Infinity) < 0){
  874. pageSizes.push(Infinity);
  875. }
  876. }, this);
  877. this.option.pageSizes = pageSizes.sort(function(a, b){return a - b;});
  878. }else{
  879. this.option.pageSizes = this.pageSizes;
  880. }
  881. this.defaultPageSize = this.option.defaultPageSize >= 1 ? parseInt(this.option.defaultPageSize, 10) : this.pageSizes[0];
  882. this.option.maxPageStep = this.option.maxPageStep > 0 ? this.option.maxPageStep : this.maxPageStep;
  883. this.option.position = lang.isString(this.option.position) ? this.option.position.toLowerCase() : this.position;
  884. var nls = i18n.getLocalization("dojox.grid.enhanced", "Pagination");
  885. this._nls = [
  886. nls.descTemplate,
  887. nls.allItemsLabelTemplate,
  888. nls.pageSizeLabelTemplate,
  889. nls.pageStepLabelTemplate,
  890. nls.itemTitle,
  891. nls.singularItemTitle,
  892. nls.prevTip,
  893. nls.firstTip,
  894. nls.nextTip,
  895. nls.lastTip,
  896. nls.gotoButtonTitle,
  897. nls.dialogTitle,
  898. nls.dialogIndication,
  899. nls.pageCountIndication,
  900. nls.dialogConfirm,
  901. nls.dialogCancel,
  902. nls.all
  903. ];
  904. },
  905. _regApis: function(){
  906. var g = this.grid;
  907. // New added APIs
  908. g.currentPage = lang.hitch(this, this.currentPage);
  909. g.nextPage = lang.hitch(this, this.nextPage);
  910. g.prevPage = lang.hitch(this, this.prevPage);
  911. g.firstPage = lang.hitch(this, this.firstPage);
  912. g.lastPage = lang.hitch(this, this.lastPage);
  913. g.currentPageSize = lang.hitch(this, this.currentPageSize);
  914. g.showGotoPageButton = lang.hitch(this, this.showGotoPageButton);
  915. g.getTotalRowCount = lang.hitch(this, this.getTotalRowCount);
  916. g.getTotalPageNum = lang.hitch(this, this.getTotalPageNum);
  917. g.gotoPage = lang.hitch(this, this.gotoPage);
  918. g.gotoFirstPage = lang.hitch(this, this.gotoFirstPage);
  919. g.gotoLastPage = lang.hitch(this, this.gotoLastPage);
  920. g.changePageSize = lang.hitch(this, this.changePageSize);
  921. // Changed APIs
  922. this._gridOriginalfuncs = [
  923. lang.hitch(g, g.scrollToRow),
  924. lang.hitch(g, g._onNew),
  925. lang.hitch(g, g.removeSelectedRows)
  926. ];
  927. g.scrollToRow = lang.hitch(this, this.scrollToRow);
  928. g.removeSelectedRows = lang.hitch(this, this.removeSelectedRows);
  929. g._onNew = lang.hitch(this, this._onNew);
  930. this.connect(g, "_onDelete", lang.hitch(this, this._onDelete));
  931. },
  932. _onNew: function(item, parentInfo){
  933. var totalPages = this.getTotalPageNum();
  934. if(((this._currentPage === totalPages || totalPages === 0) && this.grid.get('rowCount') < this._currentPageSize) || this._showAll){
  935. lang.hitch(this.grid, this._gridOriginalfuncs[1])(item, parentInfo);
  936. this.forcePageStoreLayer.endIdx++;
  937. }
  938. this._maxSize++;
  939. if(this._showAll){
  940. this._currentPageSize++;
  941. }
  942. if(this._showAll && this.grid.autoHeight){
  943. this.grid._refresh();
  944. }else{
  945. this._paginator._update();
  946. }
  947. },
  948. _onDelete: function(){
  949. if(!this._multiRemoving){
  950. this.grid.resize();
  951. if(this._showAll){
  952. this.grid._refresh();
  953. }
  954. }
  955. if(this.grid.get('rowCount') === 0){
  956. this.prevPage();
  957. }
  958. }
  959. });
  960. EnhancedGrid.registerPlugin(Pagination/*name:'pagination'*/);
  961. return Pagination;
  962. });