Paging.html 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <title>The source code</title>
  6. <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  7. <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  8. <style type="text/css">
  9. .highlight { display: block; background-color: #ddd; }
  10. </style>
  11. <script type="text/javascript">
  12. function highlight() {
  13. document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
  14. }
  15. </script>
  16. </head>
  17. <body onload="prettyPrint(); highlight();">
  18. <pre class="prettyprint lang-js"><span id='Ext-toolbar-Paging'>/**
  19. </span> * As the number of records increases, the time required for the browser to render them increases. Paging is used to
  20. * reduce the amount of data exchanged with the client. Note: if there are more records/rows than can be viewed in the
  21. * available screen area, vertical scrollbars will be added.
  22. *
  23. * Paging is typically handled on the server side (see exception below). The client sends parameters to the server side,
  24. * which the server needs to interpret and then respond with the appropriate data.
  25. *
  26. * Ext.toolbar.Paging is a specialized toolbar that is bound to a {@link Ext.data.Store} and provides automatic
  27. * paging control. This Component {@link Ext.data.Store#method-load load}s blocks of data into the {@link #store} by passing
  28. * parameters used for paging criteria.
  29. *
  30. * {@img Ext.toolbar.Paging/Ext.toolbar.Paging.png Ext.toolbar.Paging component}
  31. *
  32. * Paging Toolbar is typically used as one of the Grid's toolbars:
  33. *
  34. * @example
  35. * var itemsPerPage = 2; // set the number of items you want per page
  36. *
  37. * var store = Ext.create('Ext.data.Store', {
  38. * id:'simpsonsStore',
  39. * autoLoad: false,
  40. * fields:['name', 'email', 'phone'],
  41. * pageSize: itemsPerPage, // items per page
  42. * proxy: {
  43. * type: 'ajax',
  44. * url: 'pagingstore.js', // url that will load data with respect to start and limit params
  45. * reader: {
  46. * type: 'json',
  47. * root: 'items',
  48. * totalProperty: 'total'
  49. * }
  50. * }
  51. * });
  52. *
  53. * // specify segment of data you want to load using params
  54. * store.load({
  55. * params:{
  56. * start:0,
  57. * limit: itemsPerPage
  58. * }
  59. * });
  60. *
  61. * Ext.create('Ext.grid.Panel', {
  62. * title: 'Simpsons',
  63. * store: store,
  64. * columns: [
  65. * { header: 'Name', dataIndex: 'name' },
  66. * { header: 'Email', dataIndex: 'email', flex: 1 },
  67. * { header: 'Phone', dataIndex: 'phone' }
  68. * ],
  69. * width: 400,
  70. * height: 125,
  71. * dockedItems: [{
  72. * xtype: 'pagingtoolbar',
  73. * store: store, // same store GridPanel is using
  74. * dock: 'bottom',
  75. * displayInfo: true
  76. * }],
  77. * renderTo: Ext.getBody()
  78. * });
  79. *
  80. * To use paging, you need to set a pageSize configuration on the Store, and pass the paging requirements to
  81. * the server when the store is first loaded.
  82. *
  83. * store.load({
  84. * params: {
  85. * // specify params for the first page load if using paging
  86. * start: 0,
  87. * limit: myPageSize,
  88. * // other params
  89. * foo: 'bar'
  90. * }
  91. * });
  92. *
  93. * If using {@link Ext.data.Store#autoLoad store's autoLoad} configuration:
  94. *
  95. * var myStore = Ext.create('Ext.data.Store', {
  96. * {@link Ext.data.Store#autoLoad autoLoad}: {start: 0, limit: 25},
  97. * ...
  98. * });
  99. *
  100. * The packet sent back from the server would have this form:
  101. *
  102. * {
  103. * &quot;success&quot;: true,
  104. * &quot;results&quot;: 2000,
  105. * &quot;rows&quot;: [ // ***Note:** this must be an Array
  106. * { &quot;id&quot;: 1, &quot;name&quot;: &quot;Bill&quot;, &quot;occupation&quot;: &quot;Gardener&quot; },
  107. * { &quot;id&quot;: 2, &quot;name&quot;: &quot;Ben&quot;, &quot;occupation&quot;: &quot;Horticulturalist&quot; },
  108. * ...
  109. * { &quot;id&quot;: 25, &quot;name&quot;: &quot;Sue&quot;, &quot;occupation&quot;: &quot;Botanist&quot; }
  110. * ]
  111. * }
  112. *
  113. * ## Paging with Local Data
  114. *
  115. * Paging can also be accomplished with local data using extensions:
  116. *
  117. * - [Ext.ux.data.PagingStore][1]
  118. * - Paging Memory Proxy (examples/ux/PagingMemoryProxy.js)
  119. *
  120. * [1]: http://sencha.com/forum/showthread.php?t=71532
  121. */
  122. Ext.define('Ext.toolbar.Paging', {
  123. extend: 'Ext.toolbar.Toolbar',
  124. alias: 'widget.pagingtoolbar',
  125. alternateClassName: 'Ext.PagingToolbar',
  126. requires: ['Ext.toolbar.TextItem', 'Ext.form.field.Number'],
  127. mixins: {
  128. bindable: 'Ext.util.Bindable'
  129. },
  130. <span id='Ext-toolbar-Paging-cfg-store'> /**
  131. </span> * @cfg {Ext.data.Store} store (required)
  132. * The {@link Ext.data.Store} the paging toolbar should use as its data source.
  133. */
  134. <span id='Ext-toolbar-Paging-cfg-displayInfo'> /**
  135. </span> * @cfg {Boolean} displayInfo
  136. * true to display the displayMsg
  137. */
  138. displayInfo: false,
  139. <span id='Ext-toolbar-Paging-cfg-prependButtons'> /**
  140. </span> * @cfg {Boolean} prependButtons
  141. * true to insert any configured items _before_ the paging buttons.
  142. */
  143. prependButtons: false,
  144. //&lt;locale&gt;
  145. <span id='Ext-toolbar-Paging-cfg-displayMsg'> /**
  146. </span> * @cfg {String} displayMsg
  147. * The paging status message to display. Note that this string is
  148. * formatted using the braced numbers {0}-{2} as tokens that are replaced by the values for start, end and total
  149. * respectively. These tokens should be preserved when overriding this string if showing those values is desired.
  150. */
  151. displayMsg : 'Displaying {0} - {1} of {2}',
  152. //&lt;/locale&gt;
  153. //&lt;locale&gt;
  154. <span id='Ext-toolbar-Paging-cfg-emptyMsg'> /**
  155. </span> * @cfg {String} emptyMsg
  156. * The message to display when no records are found.
  157. */
  158. emptyMsg : 'No data to display',
  159. //&lt;/locale&gt;
  160. //&lt;locale&gt;
  161. <span id='Ext-toolbar-Paging-cfg-beforePageText'> /**
  162. </span> * @cfg {String} beforePageText
  163. * The text displayed before the input item.
  164. */
  165. beforePageText : 'Page',
  166. //&lt;/locale&gt;
  167. //&lt;locale&gt;
  168. <span id='Ext-toolbar-Paging-cfg-afterPageText'> /**
  169. </span> * @cfg {String} afterPageText
  170. * Customizable piece of the default paging text. Note that this string is formatted using
  171. * {0} as a token that is replaced by the number of total pages. This token should be preserved when overriding this
  172. * string if showing the total page count is desired.
  173. */
  174. afterPageText : 'of {0}',
  175. //&lt;/locale&gt;
  176. //&lt;locale&gt;
  177. <span id='Ext-toolbar-Paging-cfg-firstText'> /**
  178. </span> * @cfg {String} firstText
  179. * The quicktip text displayed for the first page button.
  180. * **Note**: quick tips must be initialized for the quicktip to show.
  181. */
  182. firstText : 'First Page',
  183. //&lt;/locale&gt;
  184. //&lt;locale&gt;
  185. <span id='Ext-toolbar-Paging-cfg-prevText'> /**
  186. </span> * @cfg {String} prevText
  187. * The quicktip text displayed for the previous page button.
  188. * **Note**: quick tips must be initialized for the quicktip to show.
  189. */
  190. prevText : 'Previous Page',
  191. //&lt;/locale&gt;
  192. //&lt;locale&gt;
  193. <span id='Ext-toolbar-Paging-cfg-nextText'> /**
  194. </span> * @cfg {String} nextText
  195. * The quicktip text displayed for the next page button.
  196. * **Note**: quick tips must be initialized for the quicktip to show.
  197. */
  198. nextText : 'Next Page',
  199. //&lt;/locale&gt;
  200. //&lt;locale&gt;
  201. <span id='Ext-toolbar-Paging-cfg-lastText'> /**
  202. </span> * @cfg {String} lastText
  203. * The quicktip text displayed for the last page button.
  204. * **Note**: quick tips must be initialized for the quicktip to show.
  205. */
  206. lastText : 'Last Page',
  207. //&lt;/locale&gt;
  208. //&lt;locale&gt;
  209. <span id='Ext-toolbar-Paging-cfg-refreshText'> /**
  210. </span> * @cfg {String} refreshText
  211. * The quicktip text displayed for the Refresh button.
  212. * **Note**: quick tips must be initialized for the quicktip to show.
  213. */
  214. refreshText : 'Refresh',
  215. //&lt;/locale&gt;
  216. <span id='Ext-toolbar-Paging-cfg-inputItemWidth'> /**
  217. </span> * @cfg {Number} inputItemWidth
  218. * The width in pixels of the input field used to display and change the current page number.
  219. */
  220. inputItemWidth : 30,
  221. <span id='Ext-toolbar-Paging-method-getPagingItems'> /**
  222. </span> * Gets the standard paging items in the toolbar
  223. * @private
  224. */
  225. getPagingItems: function() {
  226. var me = this;
  227. return [{
  228. itemId: 'first',
  229. tooltip: me.firstText,
  230. overflowText: me.firstText,
  231. iconCls: Ext.baseCSSPrefix + 'tbar-page-first',
  232. disabled: true,
  233. handler: me.moveFirst,
  234. scope: me
  235. },{
  236. itemId: 'prev',
  237. tooltip: me.prevText,
  238. overflowText: me.prevText,
  239. iconCls: Ext.baseCSSPrefix + 'tbar-page-prev',
  240. disabled: true,
  241. handler: me.movePrevious,
  242. scope: me
  243. },
  244. '-',
  245. me.beforePageText,
  246. {
  247. xtype: 'numberfield',
  248. itemId: 'inputItem',
  249. name: 'inputItem',
  250. cls: Ext.baseCSSPrefix + 'tbar-page-number',
  251. allowDecimals: false,
  252. minValue: 1,
  253. hideTrigger: true,
  254. enableKeyEvents: true,
  255. keyNavEnabled: false,
  256. selectOnFocus: true,
  257. submitValue: false,
  258. // mark it as not a field so the form will not catch it when getting fields
  259. isFormField: false,
  260. width: me.inputItemWidth,
  261. margins: '-1 2 3 2',
  262. listeners: {
  263. scope: me,
  264. keydown: me.onPagingKeyDown,
  265. blur: me.onPagingBlur
  266. }
  267. },{
  268. xtype: 'tbtext',
  269. itemId: 'afterTextItem',
  270. text: Ext.String.format(me.afterPageText, 1)
  271. },
  272. '-',
  273. {
  274. itemId: 'next',
  275. tooltip: me.nextText,
  276. overflowText: me.nextText,
  277. iconCls: Ext.baseCSSPrefix + 'tbar-page-next',
  278. disabled: true,
  279. handler: me.moveNext,
  280. scope: me
  281. },{
  282. itemId: 'last',
  283. tooltip: me.lastText,
  284. overflowText: me.lastText,
  285. iconCls: Ext.baseCSSPrefix + 'tbar-page-last',
  286. disabled: true,
  287. handler: me.moveLast,
  288. scope: me
  289. },
  290. '-',
  291. {
  292. itemId: 'refresh',
  293. tooltip: me.refreshText,
  294. overflowText: me.refreshText,
  295. iconCls: Ext.baseCSSPrefix + 'tbar-loading',
  296. handler: me.doRefresh,
  297. scope: me
  298. }];
  299. },
  300. initComponent : function(){
  301. var me = this,
  302. pagingItems = me.getPagingItems(),
  303. userItems = me.items || me.buttons || [];
  304. if (me.prependButtons) {
  305. me.items = userItems.concat(pagingItems);
  306. } else {
  307. me.items = pagingItems.concat(userItems);
  308. }
  309. delete me.buttons;
  310. if (me.displayInfo) {
  311. me.items.push('-&gt;');
  312. me.items.push({xtype: 'tbtext', itemId: 'displayItem'});
  313. }
  314. me.callParent();
  315. me.addEvents(
  316. <span id='Ext-toolbar-Paging-event-change'> /**
  317. </span> * @event change
  318. * Fires after the active page has been changed.
  319. * @param {Ext.toolbar.Paging} this
  320. * @param {Object} pageData An object that has these properties:
  321. *
  322. * - `total` : Number
  323. *
  324. * The total number of records in the dataset as returned by the server
  325. *
  326. * - `currentPage` : Number
  327. *
  328. * The current page number
  329. *
  330. * - `pageCount` : Number
  331. *
  332. * The total number of pages (calculated from the total number of records in the dataset as returned by the
  333. * server and the current {@link Ext.data.Store#pageSize pageSize})
  334. *
  335. * - `toRecord` : Number
  336. *
  337. * The starting record index for the current page
  338. *
  339. * - `fromRecord` : Number
  340. *
  341. * The ending record index for the current page
  342. */
  343. 'change',
  344. <span id='Ext-toolbar-Paging-event-beforechange'> /**
  345. </span> * @event beforechange
  346. * Fires just before the active page is changed. Return false to prevent the active page from being changed.
  347. * @param {Ext.toolbar.Paging} this
  348. * @param {Number} page The page number that will be loaded on change
  349. */
  350. 'beforechange'
  351. );
  352. me.on('beforerender', me.onLoad, me, {single: true});
  353. me.bindStore(me.store || 'ext-empty-store', true);
  354. },
  355. // private
  356. updateInfo : function(){
  357. var me = this,
  358. displayItem = me.child('#displayItem'),
  359. store = me.store,
  360. pageData = me.getPageData(),
  361. count, msg;
  362. if (displayItem) {
  363. count = store.getCount();
  364. if (count === 0) {
  365. msg = me.emptyMsg;
  366. } else {
  367. msg = Ext.String.format(
  368. me.displayMsg,
  369. pageData.fromRecord,
  370. pageData.toRecord,
  371. pageData.total
  372. );
  373. }
  374. displayItem.setText(msg);
  375. }
  376. },
  377. // private
  378. onLoad : function(){
  379. var me = this,
  380. pageData,
  381. currPage,
  382. pageCount,
  383. afterText,
  384. count,
  385. isEmpty;
  386. count = me.store.getCount();
  387. isEmpty = count === 0;
  388. if (!isEmpty) {
  389. pageData = me.getPageData();
  390. currPage = pageData.currentPage;
  391. pageCount = pageData.pageCount;
  392. afterText = Ext.String.format(me.afterPageText, isNaN(pageCount) ? 1 : pageCount);
  393. } else {
  394. currPage = 0;
  395. pageCount = 0;
  396. afterText = Ext.String.format(me.afterPageText, 0);
  397. }
  398. Ext.suspendLayouts();
  399. me.child('#afterTextItem').setText(afterText);
  400. me.child('#inputItem').setDisabled(isEmpty).setValue(currPage);
  401. me.child('#first').setDisabled(currPage === 1 || isEmpty);
  402. me.child('#prev').setDisabled(currPage === 1 || isEmpty);
  403. me.child('#next').setDisabled(currPage === pageCount || isEmpty);
  404. me.child('#last').setDisabled(currPage === pageCount || isEmpty);
  405. me.child('#refresh').enable();
  406. me.updateInfo();
  407. Ext.resumeLayouts(true);
  408. if (me.rendered) {
  409. me.fireEvent('change', me, pageData);
  410. }
  411. },
  412. // private
  413. getPageData : function(){
  414. var store = this.store,
  415. totalCount = store.getTotalCount();
  416. return {
  417. total : totalCount,
  418. currentPage : store.currentPage,
  419. pageCount: Math.ceil(totalCount / store.pageSize),
  420. fromRecord: ((store.currentPage - 1) * store.pageSize) + 1,
  421. toRecord: Math.min(store.currentPage * store.pageSize, totalCount)
  422. };
  423. },
  424. // private
  425. onLoadError : function(){
  426. if (!this.rendered) {
  427. return;
  428. }
  429. this.child('#refresh').enable();
  430. },
  431. // private
  432. readPageFromInput : function(pageData){
  433. var v = this.child('#inputItem').getValue(),
  434. pageNum = parseInt(v, 10);
  435. if (!v || isNaN(pageNum)) {
  436. this.child('#inputItem').setValue(pageData.currentPage);
  437. return false;
  438. }
  439. return pageNum;
  440. },
  441. onPagingFocus : function(){
  442. this.child('#inputItem').select();
  443. },
  444. //private
  445. onPagingBlur : function(e){
  446. var curPage = this.getPageData().currentPage;
  447. this.child('#inputItem').setValue(curPage);
  448. },
  449. // private
  450. onPagingKeyDown : function(field, e){
  451. var me = this,
  452. k = e.getKey(),
  453. pageData = me.getPageData(),
  454. increment = e.shiftKey ? 10 : 1,
  455. pageNum;
  456. if (k == e.RETURN) {
  457. e.stopEvent();
  458. pageNum = me.readPageFromInput(pageData);
  459. if (pageNum !== false) {
  460. pageNum = Math.min(Math.max(1, pageNum), pageData.pageCount);
  461. if(me.fireEvent('beforechange', me, pageNum) !== false){
  462. me.store.loadPage(pageNum);
  463. }
  464. }
  465. } else if (k == e.HOME || k == e.END) {
  466. e.stopEvent();
  467. pageNum = k == e.HOME ? 1 : pageData.pageCount;
  468. field.setValue(pageNum);
  469. } else if (k == e.UP || k == e.PAGE_UP || k == e.DOWN || k == e.PAGE_DOWN) {
  470. e.stopEvent();
  471. pageNum = me.readPageFromInput(pageData);
  472. if (pageNum) {
  473. if (k == e.DOWN || k == e.PAGE_DOWN) {
  474. increment *= -1;
  475. }
  476. pageNum += increment;
  477. if (pageNum &gt;= 1 &amp;&amp; pageNum &lt;= pageData.pageCount) {
  478. field.setValue(pageNum);
  479. }
  480. }
  481. }
  482. },
  483. // private
  484. beforeLoad : function(){
  485. if(this.rendered &amp;&amp; this.refresh){
  486. this.refresh.disable();
  487. }
  488. },
  489. <span id='Ext-toolbar-Paging-method-moveFirst'> /**
  490. </span> * Move to the first page, has the same effect as clicking the 'first' button.
  491. */
  492. moveFirst : function(){
  493. if (this.fireEvent('beforechange', this, 1) !== false){
  494. this.store.loadPage(1);
  495. }
  496. },
  497. <span id='Ext-toolbar-Paging-method-movePrevious'> /**
  498. </span> * Move to the previous page, has the same effect as clicking the 'previous' button.
  499. */
  500. movePrevious : function(){
  501. var me = this,
  502. prev = me.store.currentPage - 1;
  503. if (prev &gt; 0) {
  504. if (me.fireEvent('beforechange', me, prev) !== false) {
  505. me.store.previousPage();
  506. }
  507. }
  508. },
  509. <span id='Ext-toolbar-Paging-method-moveNext'> /**
  510. </span> * Move to the next page, has the same effect as clicking the 'next' button.
  511. */
  512. moveNext : function(){
  513. var me = this,
  514. total = me.getPageData().pageCount,
  515. next = me.store.currentPage + 1;
  516. if (next &lt;= total) {
  517. if (me.fireEvent('beforechange', me, next) !== false) {
  518. me.store.nextPage();
  519. }
  520. }
  521. },
  522. <span id='Ext-toolbar-Paging-method-moveLast'> /**
  523. </span> * Move to the last page, has the same effect as clicking the 'last' button.
  524. */
  525. moveLast : function(){
  526. var me = this,
  527. last = me.getPageData().pageCount;
  528. if (me.fireEvent('beforechange', me, last) !== false) {
  529. me.store.loadPage(last);
  530. }
  531. },
  532. <span id='Ext-toolbar-Paging-method-doRefresh'> /**
  533. </span> * Refresh the current page, has the same effect as clicking the 'refresh' button.
  534. */
  535. doRefresh : function(){
  536. var me = this,
  537. current = me.store.currentPage;
  538. if (me.fireEvent('beforechange', me, current) !== false) {
  539. me.store.loadPage(current);
  540. }
  541. },
  542. getStoreListeners: function() {
  543. return {
  544. beforeload: this.beforeLoad,
  545. load: this.onLoad,
  546. exception: this.onLoadError
  547. };
  548. },
  549. <span id='Ext-toolbar-Paging-method-unbind'> /**
  550. </span> * Unbinds the paging toolbar from the specified {@link Ext.data.Store} **(deprecated)**
  551. * @param {Ext.data.Store} store The data store to unbind
  552. */
  553. unbind : function(store){
  554. this.bindStore(null);
  555. },
  556. <span id='Ext-toolbar-Paging-method-bind'> /**
  557. </span> * Binds the paging toolbar to the specified {@link Ext.data.Store} **(deprecated)**
  558. * @param {Ext.data.Store} store The data store to bind
  559. */
  560. bind : function(store){
  561. this.bindStore(store);
  562. },
  563. // private
  564. onDestroy : function(){
  565. this.unbind();
  566. this.callParent();
  567. }
  568. });
  569. </pre>
  570. </body>
  571. </html>