├── .github └── ISSUE_TEMPLATE │ └── bug_report.md ├── .gitignore ├── .npmignore ├── .npmrc ├── Gruntfile.js ├── LICENSE ├── README.md ├── bower.json ├── component.json ├── dist ├── pagination.css ├── pagination.js ├── pagination.less └── pagination.min.js ├── docs ├── cn.md └── en.md ├── examples ├── images │ └── paginationjs_record.gif └── pagination.html ├── package.json └── src ├── pagination.js └── pagination.less /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Provide a re-produciable demo: http://codepen.io/superRaytin/pen/RRoZBz 15 | 16 | **Expected behavior** 17 | A clear and concise description of what you expected to happen. 18 | 19 | **Versions:** 20 | - Pagination: [e.g. 2.1.5] 21 | - jQuery [e.g. 1.8.3] 22 | - Browser [e.g. Chrome] 23 | 24 | **Additional context** 25 | Add any other context about the problem here. 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build and Release Folders 2 | bin/ 3 | bin-debug/ 4 | bin-release/ 5 | 6 | # Other files and folders 7 | .settings/ 8 | node_modules/ 9 | .idea/ 10 | .DS_Store 11 | npm-debug.log 12 | yarn.lock 13 | 14 | # Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties` 15 | # should NOT be excluded as they contain compiler settings and other important 16 | # information for Eclipse / Flash Builder. 17 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | docs 2 | examples 3 | component.json 4 | bower.json -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmjs.org -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | grunt.initConfig({ 3 | pkg: grunt.file.readJSON('package.json'), 4 | 5 | uglify: { 6 | options: { 7 | banner: '/*\n' + 8 | ' * pagination.js <%= pkg.version %>\n' + 9 | ' * <%= pkg.description %>\n' + 10 | ' * <%= pkg.repository.url %>\n\n' + 11 | ' * Homepage: <%= pkg.homepage %>\n' + 12 | ' *\n' + 13 | ' * Copyright 2014-2100, <%= pkg.author %>\n' + 14 | ' * Released under the <%= pkg.license %> license.\n' + 15 | '*/\n' 16 | }, 17 | main: { 18 | files: [ 19 | { 20 | src: ['src/pagination.js'], 21 | dest: 'dist/pagination.min.js' 22 | } 23 | ] 24 | } 25 | }, 26 | 27 | copy: { 28 | main: { 29 | files: [ 30 | { 31 | src: 'src/pagination.js', 32 | dest: 'dist/pagination.js' 33 | }, 34 | { 35 | src: 'src/pagination.less', 36 | dest: 'dist/pagination.less' 37 | } 38 | ] 39 | } 40 | }, 41 | 42 | less: { 43 | main: { 44 | src: 'src/pagination.less', 45 | dest: 'dist/pagination.css' 46 | } 47 | }, 48 | 49 | cssmin: { 50 | main: { 51 | src: 'dist/pagination.css', 52 | dest: 'dist/pagination.css' 53 | } 54 | } 55 | }); 56 | 57 | grunt.loadNpmTasks('grunt-contrib-uglify'); 58 | grunt.loadNpmTasks('grunt-contrib-less'); 59 | grunt.loadNpmTasks('grunt-contrib-cssmin'); 60 | grunt.loadNpmTasks('grunt-contrib-copy'); 61 | 62 | grunt.registerTask('default', [ 63 | 'uglify', 64 | 'copy', 65 | 'less', 66 | 'cssmin' 67 | ]); 68 | }; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2048 SuperRaytin 柳裟 <superRaytin@163.com> 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pagination.js 2 | 3 | > A jQuery plugin to provide simple yet fully customisable pagination. 4 | 5 | [![NPM version][npm-image]][npm-url] 6 | [![Bower version][bower-image]][bower-url] 7 | [![CDNJS](https://img.shields.io/cdnjs/v/paginationjs.svg)](https://cdnjs.com/libraries/paginationjs) 8 | 9 | [npm-url]: https://npmjs.org/package/paginationjs 10 | [npm-image]: http://img.shields.io/npm/v/paginationjs.svg 11 | [bower-url]:http://badge.fury.io/bo/paginationjs 12 | [bower-image]: https://badge.fury.io/bo/paginationjs.svg 13 | 14 | paginationjs 15 | 16 | See demos and full documentation at official site: [http://pagination.js.org](http://pagination.js.org) 17 | 18 | # Installation / Download 19 | 20 | `npm install paginationjs` or `bower install paginationjs` or just download [pagination.js](dist/pagination.js) from the git repo. 21 | 22 | # Quick Start 23 | 24 | ```html 25 |
26 |
27 | ``` 28 | 29 | ```js 30 | $('#pagination-container').pagination({ 31 | dataSource: [1, 2, 3, 4, 5, 6, 7, ... , 195], 32 | callback: function(data, pagination) { 33 | // template method of yourself 34 | var html = template(data); 35 | $('#data-container').html(html); 36 | } 37 | }) 38 | ``` 39 | 40 | # Rendering data 41 | 42 | Below is a minimal rendering method: 43 | 44 | ```js 45 | function simpleTemplating(data) { 46 | var html = ''; 51 | return html; 52 | } 53 | ``` 54 | 55 | Call: 56 | 57 | ```js 58 | $('#pagination-container').pagination({ 59 | dataSource: [1, 2, 3, 4, 5, 6, 7, ... , 195], 60 | callback: function(data, pagination) { 61 | var html = simpleTemplating(data); 62 | $('#data-container').html(html); 63 | } 64 | }) 65 | ``` 66 | 67 | To make it easier to maintain, you'd better to use specialized templating engine to do that. Such as [Handlebars](http://handlebarsjs.com/) and [Undercore.template](http://underscorejs.org/#template). 68 | 69 | ### Handlebars 70 | 71 | ```html 72 | 79 | ``` 80 | 81 | ```js 82 | $('#pagination-container').pagination({ 83 | dataSource: [1, 2, 3, 4, 5, 6, 7, ... , 195], 84 | callback: function(data, pagination) { 85 | var html = Handlebars.compile($('#template-demo').html(), { 86 | data: data 87 | }); 88 | $('#data-container').html(html); 89 | } 90 | }) 91 | ``` 92 | 93 | ### Underscore 94 | 95 | ```html 96 | 103 | ``` 104 | 105 | ```js 106 | $('#pagination-container').pagination({ 107 | dataSource: [1, 2, 3, 4, 5, 6, 7, ... , 195], 108 | callback: function(data, pagination) { 109 | var html = _.template($('#template-demo').html(), { 110 | data: data 111 | }); 112 | $('#data-container').html(html); 113 | } 114 | }) 115 | ``` 116 | 117 | Or any other templating engine you prefer. 118 | 119 | # License 120 | 121 | Released under the MIT license. 122 | 123 | MIT: [http://rem.mit-license.org](http://rem.mit-license.org/), See [LICENSE](/LICENSE) 124 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "paginationjs", 3 | "version": "2.6.0", 4 | "main": "dist/pagination.min.js", 5 | "keywords": [ 6 | "paginationjs", 7 | "pagination.js", 8 | "pagination", 9 | "jquery.pagination", 10 | "jquery pagination" 11 | ], 12 | "ignore": [ 13 | "**/.*", 14 | "src", 15 | "docs", 16 | "examples", 17 | "node_modules", 18 | "LICENSE", 19 | "component.json", 20 | "bower.json", 21 | "package.json", 22 | "README*.md", 23 | "example.js", 24 | "Gruntfile.js" 25 | ], 26 | "dependencies": { 27 | "jquery": "git://github.com/components/jquery.git#~3" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "paginationjs", 3 | "version": "2.6.0", 4 | "repo": "superRaytin/paginationjs", 5 | "description": "A jQuery plugin to provide simple yet fully customisable pagination", 6 | "keywords": [ 7 | "paginationjs", 8 | "pagination.js", 9 | "pagination", 10 | "jquery.pagination", 11 | "jquery pagination" 12 | ], 13 | "main": "dist/pagination.min.js", 14 | "scripts": [ 15 | "dist/pagination.min.js", 16 | "dist/pagination.js", 17 | "dist/pagination.css", 18 | "dist/pagination.less" 19 | ], 20 | "license": "MIT" 21 | } 22 | -------------------------------------------------------------------------------- /dist/pagination.css: -------------------------------------------------------------------------------- 1 | .paginationjs{display:flex;line-height:1.6;font-family:Marmelad,"Lucida Grande",Arial,"Hiragino Sans GB",Georgia,sans-serif;font-size:14px;box-sizing:initial}.paginationjs:after{display:table;content:" ";clear:both}.paginationjs .paginationjs-pages{float:left;margin-left:10px}.paginationjs .paginationjs-pages ul{float:left;margin:0;padding:0}.paginationjs .paginationjs-go-button,.paginationjs .paginationjs-go-input,.paginationjs .paginationjs-size-changer{margin-left:10px;float:left;font-size:14px}.paginationjs .paginationjs-pages li{float:left;border:1px solid #aaa;border-right:none;list-style:none}.paginationjs .paginationjs-pages li>a{min-width:30px;height:28px;line-height:28px;display:block;background:#fff;font-size:14px;color:#333;text-decoration:none;text-align:center;cursor:pointer}.paginationjs .paginationjs-pages li>a:hover{background:#eee}.paginationjs .paginationjs-pages li.active{border:none}.paginationjs .paginationjs-pages li.active>a{height:30px;line-height:30px;background:#aaa;color:#fff;cursor:default}.paginationjs .paginationjs-pages li.disabled>a{opacity:.3;cursor:default}.paginationjs .paginationjs-pages li.disabled>a:hover{background:0 0}.paginationjs .paginationjs-pages li:first-child,.paginationjs .paginationjs-pages li:first-child>a{border-radius:3px 0 0 3px}.paginationjs .paginationjs-pages li:last-child{border-right:1px solid #aaa;border-radius:0 3px 3px 0}.paginationjs .paginationjs-pages li:last-child>a{border-radius:0 3px 3px 0}.paginationjs .paginationjs-size-changer>select{height:28px;background:#fff;border-radius:3px;border:1px solid #aaa;padding:0;font-size:14px;text-align:center;vertical-align:baseline;outline:0;box-shadow:none;box-sizing:initial}.paginationjs .paginationjs-go-input>input[type=text]{width:30px;height:28px;background:#fff;border-radius:3px;border:1px solid #aaa;padding:0;font-size:14px;text-align:center;vertical-align:baseline;outline:0;box-shadow:none;box-sizing:initial}.paginationjs .paginationjs-go-button>input[type=button]{min-width:40px;height:30px;line-height:28px;background:#fff;border-radius:3px;border:1px solid #aaa;text-align:center;padding:0 8px;font-size:14px;vertical-align:baseline;outline:0;box-shadow:none;color:#333;cursor:pointer;vertical-align:middle\9}.paginationjs .paginationjs-go-button>input[type=button]:hover{background-color:#f8f8f8}.paginationjs .paginationjs-nav{float:left;height:30px;line-height:30px;font-size:14px}.paginationjs.paginationjs-small{font-size:12px}.paginationjs.paginationjs-small .paginationjs-pages li>a{min-width:26px;height:24px;line-height:24px;font-size:12px}.paginationjs.paginationjs-small .paginationjs-pages li.active>a{height:26px;line-height:26px}.paginationjs.paginationjs-small .paginationjs-size-changer{font-size:12px}.paginationjs.paginationjs-small .paginationjs-size-changer>select{height:24px;font-size:12px}.paginationjs.paginationjs-small .paginationjs-go-input{font-size:12px}.paginationjs.paginationjs-small .paginationjs-go-input>input[type=text]{width:26px;height:24px;font-size:12px}.paginationjs.paginationjs-small .paginationjs-go-button{font-size:12px}.paginationjs.paginationjs-small .paginationjs-go-button>input[type=button]{min-width:30px;height:26px;line-height:24px;padding:0 6px;font-size:12px}.paginationjs.paginationjs-small .paginationjs-nav{height:26px;line-height:26px;font-size:12px}.paginationjs.paginationjs-big{font-size:16px}.paginationjs.paginationjs-big .paginationjs-pages li>a{min-width:36px;height:34px;line-height:34px;font-size:16px}.paginationjs.paginationjs-big .paginationjs-pages li.active>a{height:36px;line-height:36px}.paginationjs.paginationjs-big .paginationjs-size-changer{font-size:16px}.paginationjs.paginationjs-big .paginationjs-size-changer>select{height:34px;font-size:16px}.paginationjs.paginationjs-big .paginationjs-go-input{font-size:16px}.paginationjs.paginationjs-big .paginationjs-go-input>input[type=text]{width:36px;height:34px;font-size:16px}.paginationjs.paginationjs-big .paginationjs-go-button{font-size:16px}.paginationjs.paginationjs-big .paginationjs-go-button>input[type=button]{min-width:50px;height:36px;line-height:34px;padding:0 12px;font-size:16px}.paginationjs.paginationjs-big .paginationjs-nav{height:36px;line-height:36px;font-size:16px}.paginationjs>:first-child{margin-left:0}.paginationjs.paginationjs-theme-blue .paginationjs-pages li{border-color:#289de9}.paginationjs.paginationjs-theme-blue .paginationjs-pages li>a{color:#289de9}.paginationjs.paginationjs-theme-blue .paginationjs-pages li>a:hover{background:#e9f4fc}.paginationjs.paginationjs-theme-blue .paginationjs-pages li.active>a{background:#289de9;color:#fff}.paginationjs.paginationjs-theme-blue .paginationjs-pages li.disabled>a:hover{background:0 0}.paginationjs.paginationjs-theme-blue .paginationjs-go-input>input[type=text],.paginationjs.paginationjs-theme-blue .paginationjs-size-changer>select{border-color:#289de9}.paginationjs.paginationjs-theme-blue .paginationjs-go-button>input[type=button]{background:#289de9;border-color:#289de9;color:#fff}.paginationjs.paginationjs-theme-blue .paginationjs-go-button>input[type=button]:hover{background-color:#3ca5ea}.paginationjs.paginationjs-theme-green .paginationjs-pages li{border-color:#449d44}.paginationjs.paginationjs-theme-green .paginationjs-pages li>a{color:#449d44}.paginationjs.paginationjs-theme-green .paginationjs-pages li>a:hover{background:#ebf4eb}.paginationjs.paginationjs-theme-green .paginationjs-pages li.active>a{background:#449d44;color:#fff}.paginationjs.paginationjs-theme-green .paginationjs-pages li.disabled>a:hover{background:0 0}.paginationjs.paginationjs-theme-green .paginationjs-go-input>input[type=text],.paginationjs.paginationjs-theme-green .paginationjs-size-changer>select{border-color:#449d44}.paginationjs.paginationjs-theme-green .paginationjs-go-button>input[type=button]{background:#449d44;border-color:#449d44;color:#fff}.paginationjs.paginationjs-theme-green .paginationjs-go-button>input[type=button]:hover{background-color:#55a555}.paginationjs.paginationjs-theme-yellow .paginationjs-pages li{border-color:#ec971f}.paginationjs.paginationjs-theme-yellow .paginationjs-pages li>a{color:#ec971f}.paginationjs.paginationjs-theme-yellow .paginationjs-pages li>a:hover{background:#fdf5e9}.paginationjs.paginationjs-theme-yellow .paginationjs-pages li.active>a{background:#ec971f;color:#fff}.paginationjs.paginationjs-theme-yellow .paginationjs-pages li.disabled>a:hover{background:0 0}.paginationjs.paginationjs-theme-yellow .paginationjs-go-input>input[type=text],.paginationjs.paginationjs-theme-yellow .paginationjs-size-changer>select{border-color:#ec971f}.paginationjs.paginationjs-theme-yellow .paginationjs-go-button>input[type=button]{background:#ec971f;border-color:#ec971f;color:#fff}.paginationjs.paginationjs-theme-yellow .paginationjs-go-button>input[type=button]:hover{background-color:#eea135}.paginationjs.paginationjs-theme-red .paginationjs-pages li{border-color:#c9302c}.paginationjs.paginationjs-theme-red .paginationjs-pages li>a{color:#c9302c}.paginationjs.paginationjs-theme-red .paginationjs-pages li>a:hover{background:#faeaea}.paginationjs.paginationjs-theme-red .paginationjs-pages li.active>a{background:#c9302c;color:#fff}.paginationjs.paginationjs-theme-red .paginationjs-pages li.disabled>a:hover{background:0 0}.paginationjs.paginationjs-theme-red .paginationjs-go-input>input[type=text],.paginationjs.paginationjs-theme-red .paginationjs-size-changer>select{border-color:#c9302c}.paginationjs.paginationjs-theme-red .paginationjs-go-button>input[type=button]{background:#c9302c;border-color:#c9302c;color:#fff}.paginationjs.paginationjs-theme-red .paginationjs-go-button>input[type=button]:hover{background-color:#ce4541}.paginationjs .paginationjs-pages li.paginationjs-next{border-right:1px solid #aaa\9}.paginationjs .paginationjs-size-changer{margin-left:5px\9}.paginationjs .paginationjs-size-changer>select{line-height:28px\9;vertical-align:middle\9}.paginationjs .paginationjs-go-input{margin-left:5px\9}.paginationjs .paginationjs-go-input>input[type=text]{line-height:28px\9;vertical-align:middle\9}.paginationjs .paginationjs-go-button{margin-left:5px\9}.paginationjs.paginationjs-big .paginationjs-pages li>a{line-height:36px\9}.paginationjs.paginationjs-big .paginationjs-go-input>input[type=text]{height:36px\9;line-height:36px\9} -------------------------------------------------------------------------------- /dist/pagination.js: -------------------------------------------------------------------------------- 1 | /* 2 | * pagination.js 2.6.0 3 | * A jQuery plugin to provide simple yet fully customisable pagination. 4 | * https://github.com/superRaytin/paginationjs 5 | * 6 | * Homepage: http://pagination.js.org 7 | * 8 | * Copyright 2014-2100, superRaytin 9 | * Released under the MIT license. 10 | */ 11 | 12 | (function(global, $) { 13 | 14 | if (typeof $ === 'undefined') { 15 | throwError('Pagination requires jQuery.'); 16 | } 17 | 18 | var pluginName = 'pagination'; 19 | 20 | var pluginHookMethod = 'addHook'; 21 | 22 | var eventPrefix = '__pagination-'; 23 | 24 | if ($.fn.pagination) { 25 | throwError('plugin conflicted, the name "pagination" has been taken by another jQuery plugin.'); 26 | } 27 | 28 | $.fn[pluginName] = function(options) { 29 | 30 | if (typeof options === 'undefined') { 31 | return this; 32 | } 33 | 34 | var container = $(this); 35 | 36 | var attributes = $.extend({}, $.fn[pluginName].defaults, options); 37 | 38 | var pagination = { 39 | 40 | initialize: function() { 41 | var self = this; 42 | 43 | // Cache data for current instance 44 | if (!container.data('pagination')) { 45 | container.data('pagination', {}); 46 | } 47 | 48 | if (self.callHook('beforeInit') === false) return; 49 | 50 | // Pagination has been initialized, destroy it 51 | if (container.data('pagination').initialized) { 52 | $('.paginationjs', container).remove(); 53 | } 54 | 55 | // Whether to disable Pagination at the initialization 56 | self.disabled = !!attributes.disabled; 57 | 58 | // Model will be passed to the callback function 59 | var model = self.model = { 60 | pageRange: attributes.pageRange, 61 | pageSize: attributes.pageSize 62 | }; 63 | 64 | // Parse dataSource to find available paging data 65 | self.parseDataSource(attributes.dataSource, function(dataSource) { 66 | 67 | // Asynchronous mode 68 | self.isAsync = Helpers.isString(dataSource); 69 | if (Helpers.isArray(dataSource)) { 70 | model.totalNumber = attributes.totalNumber = dataSource.length; 71 | } 72 | 73 | // Asynchronous mode and a 'totalNumberLocator' has been specified 74 | self.isDynamicTotalNumber = self.isAsync && attributes.totalNumberLocator; 75 | 76 | var el = self.render(true); 77 | 78 | // Add extra className to the pagination element 79 | if (attributes.className) { 80 | el.addClass(attributes.className); 81 | } 82 | 83 | model.el = el; 84 | 85 | // Append / prepend pagination element to the container 86 | container[attributes.position === 'bottom' ? 'append' : 'prepend'](el); 87 | 88 | // Bind events 89 | self.observer(); 90 | 91 | // Mark pagination has been initialized 92 | container.data('pagination').initialized = true; 93 | 94 | // Call hook after initialization 95 | self.callHook('afterInit', el); 96 | }); 97 | }, 98 | 99 | render: function(isBoot) { 100 | var self = this; 101 | var model = self.model; 102 | var el = model.el || $('
'); 103 | var isForced = isBoot !== true; 104 | 105 | self.callHook('beforeRender', isForced); 106 | 107 | var currentPage = model.pageNumber || attributes.pageNumber; 108 | var pageRange = attributes.pageRange || 0; 109 | var totalPage = self.getTotalPage(); 110 | 111 | var rangeStart = currentPage - pageRange; 112 | var rangeEnd = currentPage + pageRange; 113 | 114 | if (rangeEnd > totalPage) { 115 | rangeEnd = totalPage; 116 | rangeStart = totalPage - pageRange * 2; 117 | rangeStart = rangeStart < 1 ? 1 : rangeStart; 118 | } 119 | 120 | if (rangeStart <= 1) { 121 | rangeStart = 1; 122 | rangeEnd = Math.min(pageRange * 2 + 1, totalPage); 123 | } 124 | 125 | el.html(self.generateHTML({ 126 | currentPage: currentPage, 127 | pageRange: pageRange, 128 | rangeStart: rangeStart, 129 | rangeEnd: rangeEnd 130 | })); 131 | 132 | // Whether to hide pagination when there is only one page 133 | if (attributes.hideOnlyOnePage) { 134 | el[totalPage <= 1 ? 'hide' : 'show'](); 135 | } 136 | 137 | self.callHook('afterRender', isForced); 138 | 139 | return el; 140 | }, 141 | 142 | getPageLinkTag: function(index) { 143 | var pageLink = attributes.pageLink; 144 | return pageLink ? `${index}` : `${index}`; 145 | }, 146 | 147 | // Generate HTML for page numbers 148 | generatePageNumbersHTML: function(args) { 149 | var self = this; 150 | var currentPage = args.currentPage; 151 | var totalPage = self.getTotalPage(); 152 | var getPageLinkTag = self.getPageLinkTag; 153 | var rangeStart = args.rangeStart; 154 | var rangeEnd = args.rangeEnd; 155 | var html = ''; 156 | var i; 157 | 158 | var ellipsisText = attributes.ellipsisText; 159 | 160 | var classPrefix = attributes.classPrefix; 161 | var pageClassName = attributes.pageClassName || ''; 162 | var activeClassName = attributes.activeClassName || ''; 163 | var disableClassName = attributes.disableClassName || ''; 164 | 165 | // Display all page numbers if page range disabled 166 | if (attributes.pageRange === null) { 167 | for (i = 1; i <= totalPage; i++) { 168 | if (i == currentPage) { 169 | html += `
  • ${i}
  • `; 170 | } else { 171 | html += `
  • ${getPageLinkTag(i)}
  • `; 172 | } 173 | } 174 | return html; 175 | } 176 | 177 | if (rangeStart <= 3) { 178 | for (i = 1; i < rangeStart; i++) { 179 | if (i == currentPage) { 180 | html += `
  • ${i}
  • `; 181 | } else { 182 | html += `
  • ${getPageLinkTag(i)}
  • `; 183 | } 184 | } 185 | } else { 186 | if (!attributes.hideFirstOnEllipsisShow) { 187 | html += `
  • ${getPageLinkTag(1)}
  • `; 188 | } 189 | html += `
  • ${ellipsisText}
  • `; 190 | } 191 | 192 | for (i = rangeStart; i <= rangeEnd; i++) { 193 | if (i == currentPage) { 194 | html += `
  • ${i}
  • `; 195 | } else { 196 | html += `
  • ${getPageLinkTag(i)}
  • `; 197 | } 198 | } 199 | 200 | if (rangeEnd >= totalPage - 2) { 201 | for (i = rangeEnd + 1; i <= totalPage; i++) { 202 | html += `
  • ${getPageLinkTag(i)}
  • `; 203 | } 204 | } else { 205 | html += `
  • ${ellipsisText}
  • `; 206 | 207 | if (!attributes.hideLastOnEllipsisShow) { 208 | html += `
  • ${getPageLinkTag(totalPage)}
  • `; 209 | } 210 | } 211 | 212 | return html; 213 | }, 214 | 215 | // Generate HTML content 216 | generateHTML: function(args) { 217 | var self = this; 218 | var currentPage = args.currentPage; 219 | var totalPage = self.getTotalPage(); 220 | var getPageLinkTag = self.getPageLinkTag; 221 | 222 | var totalNumber = self.getTotalNumber(); 223 | 224 | var pageSize = attributes.pageSize; 225 | var showPrevious = attributes.showPrevious; 226 | var showNext = attributes.showNext; 227 | var showPageNumbers = attributes.showPageNumbers; 228 | var showNavigator = attributes.showNavigator; 229 | var showSizeChanger = attributes.showSizeChanger; 230 | var sizeChangerOptions = attributes.sizeChangerOptions; 231 | var showGoInput = attributes.showGoInput; 232 | var showGoButton = attributes.showGoButton; 233 | 234 | var prevText = attributes.prevText; 235 | var nextText = attributes.nextText; 236 | var goButtonText = attributes.goButtonText; 237 | 238 | var classPrefix = attributes.classPrefix; 239 | var disableClassName = attributes.disableClassName || ''; 240 | var ulClassName = attributes.ulClassName || ''; 241 | var prevClassName = attributes.prevClassName || ''; 242 | var nextClassName = attributes.nextClassName || ''; 243 | 244 | var html = ''; 245 | var sizeSelect = `'; 247 | var goButton = ``; 248 | var formattedString; 249 | 250 | var formatSizeChanger = typeof attributes.formatSizeChanger === 'function' ? attributes.formatSizeChanger(currentPage, totalPage, totalNumber) : attributes.formatSizeChanger; 251 | var formatNavigator = typeof attributes.formatNavigator === 'function' ? attributes.formatNavigator(currentPage, totalPage, totalNumber) : attributes.formatNavigator; 252 | var formatGoInput = typeof attributes.formatGoInput === 'function' ? attributes.formatGoInput(goInput, currentPage, totalPage, totalNumber) : attributes.formatGoInput; 253 | var formatGoButton = typeof attributes.formatGoButton === 'function' ? attributes.formatGoButton(goButton, currentPage, totalPage, totalNumber) : attributes.formatGoButton; 254 | 255 | var autoHidePrevious = typeof attributes.autoHidePrevious === 'function' ? attributes.autoHidePrevious() : attributes.autoHidePrevious; 256 | var autoHideNext = typeof attributes.autoHideNext === 'function' ? attributes.autoHideNext() : attributes.autoHideNext; 257 | 258 | var header = typeof attributes.header === 'function' ? attributes.header(currentPage, totalPage, totalNumber) : attributes.header; 259 | var footer = typeof attributes.footer === 'function' ? attributes.footer(currentPage, totalPage, totalNumber) : attributes.footer; 260 | 261 | // Prepend extra contents to the pagination buttons 262 | if (header) { 263 | formattedString = self.replaceVariables(header, { 264 | currentPage: currentPage, 265 | totalPage: totalPage, 266 | totalNumber: totalNumber 267 | }); 268 | html += formattedString; 269 | } 270 | 271 | // Whether to display navigator 272 | if (showNavigator) { 273 | if (formatNavigator) { 274 | formattedString = self.replaceVariables(formatNavigator, { 275 | currentPage: currentPage, 276 | totalPage: totalPage, 277 | totalNumber: totalNumber, 278 | rangeStart: (currentPage - 1) * pageSize + 1, 279 | rangeEnd: Math.min(currentPage * pageSize, totalNumber) 280 | }); 281 | html += `
    ${formattedString}
    `; 282 | } 283 | } 284 | 285 | if (showPrevious || showPageNumbers || showNext) { 286 | html += '
    '; 287 | 288 | if (ulClassName) { 289 | html += `
    `; 321 | } 322 | 323 | if (showSizeChanger) { 324 | if (Helpers.isArray(sizeChangerOptions)) { 325 | if (sizeChangerOptions.indexOf(pageSize) === -1) { 326 | sizeChangerOptions.unshift(pageSize); 327 | sizeChangerOptions.sort((a, b) => a - b); 328 | } 329 | for (let i = 0; i < sizeChangerOptions.length; i++) { 330 | sizeSelect += ``; 331 | } 332 | sizeSelect += ``; 333 | formattedString = sizeSelect; 334 | 335 | if (formatSizeChanger) { 336 | formattedString = self.replaceVariables(formatSizeChanger, { 337 | length: sizeSelect, 338 | total: totalNumber 339 | }); 340 | } 341 | html += `
    ${formattedString}
    `; 342 | } 343 | } 344 | 345 | // Whether to display Go input 346 | if (showGoInput) { 347 | if (formatGoInput) { 348 | formattedString = self.replaceVariables(formatGoInput, { 349 | currentPage: currentPage, 350 | totalPage: totalPage, 351 | totalNumber: totalNumber, 352 | input: goInput 353 | }); 354 | html += `
    ${formattedString}
    `; 355 | } 356 | } 357 | 358 | // Whether to display Go button 359 | if (showGoButton) { 360 | if (formatGoButton) { 361 | formattedString = self.replaceVariables(formatGoButton, { 362 | currentPage: currentPage, 363 | totalPage: totalPage, 364 | totalNumber: totalNumber, 365 | button: goButton 366 | }); 367 | html += `
    ${formattedString}
    `; 368 | } 369 | } 370 | 371 | // Append extra contents to the pagination buttons 372 | if (footer) { 373 | formattedString = self.replaceVariables(footer, { 374 | currentPage: currentPage, 375 | totalPage: totalPage, 376 | totalNumber: totalNumber 377 | }); 378 | html += formattedString; 379 | } 380 | 381 | return html; 382 | }, 383 | 384 | // dataSource is a request URL and a 'totalNumberLocator' function specified 385 | // execute it to find out 'totalNumber' from the response 386 | findTotalNumberFromRemoteResponse: function(response) { 387 | var self = this; 388 | self.model.totalNumber = attributes.totalNumberLocator(response); 389 | }, 390 | 391 | // Go to the specified page 392 | go: function(number, callback) { 393 | var self = this; 394 | var model = self.model; 395 | 396 | if (self.disabled) return; 397 | 398 | var pageNumber = number; 399 | pageNumber = parseInt(pageNumber); 400 | 401 | if (!pageNumber || pageNumber < 1) return; 402 | 403 | var pageSize = attributes.pageSize; 404 | var totalNumber = self.getTotalNumber(); 405 | var totalPage = self.getTotalPage(); 406 | 407 | if (totalNumber > 0 && pageNumber > totalPage) return; 408 | 409 | // Pick paging data in synchronous mode 410 | if (!self.isAsync) { 411 | render(self.getPagingData(pageNumber)); 412 | return; 413 | } 414 | 415 | var postData = {}; 416 | var alias = attributes.alias || {}; 417 | var pageSizeName = alias.pageSize ? alias.pageSize : 'pageSize'; 418 | var pageNumberName = alias.pageNumber ? alias.pageNumber : 'pageNumber'; 419 | postData[pageSizeName] = pageSize; 420 | postData[pageNumberName] = pageNumber; 421 | 422 | var ajaxParams = typeof attributes.ajax === 'function' ? attributes.ajax() : attributes.ajax; 423 | 424 | // If the pageNumber's value starts with 0 via Ajax 425 | if (ajaxParams && ajaxParams.pageNumberStartWithZero) { 426 | postData[pageNumberName] = pageNumber - 1; 427 | } 428 | 429 | var formatAjaxParams = { 430 | type: 'get', 431 | cache: false, 432 | data: {}, 433 | contentType: 'application/x-www-form-urlencoded; charset=UTF-8', 434 | dataType: 'json', 435 | async: true 436 | }; 437 | 438 | $.extend(true, formatAjaxParams, ajaxParams); 439 | $.extend(formatAjaxParams.data, postData); 440 | 441 | formatAjaxParams.url = attributes.dataSource; 442 | formatAjaxParams.success = function(response) { 443 | try { 444 | self.model.originalResponse = response; 445 | if (self.isDynamicTotalNumber) { 446 | self.findTotalNumberFromRemoteResponse(response); 447 | } else { 448 | self.model.totalNumber = attributes.totalNumber; 449 | } 450 | 451 | var finalData = self.filterDataWithLocator(response); 452 | render(finalData); 453 | } catch (e) { 454 | if(typeof attributes.onError === 'function') { 455 | attributes.onError(e, 'ajaxSuccessHandlerError'); 456 | } else { 457 | throw e; 458 | } 459 | } 460 | }; 461 | formatAjaxParams.error = function(jqXHR, textStatus, errorThrown) { 462 | attributes.formatAjaxError && attributes.formatAjaxError(jqXHR, textStatus, errorThrown); 463 | self.enable(); 464 | }; 465 | 466 | self.disable(); 467 | 468 | if (attributes.ajaxFunction) { 469 | attributes.ajaxFunction(formatAjaxParams); 470 | } else { 471 | $.ajax(formatAjaxParams); 472 | } 473 | 474 | function render(data) { 475 | if (self.callHook('beforePaging', pageNumber) === false) return false; 476 | 477 | // Pagination direction 478 | model.direction = typeof model.pageNumber === 'undefined' ? 0 : (pageNumber > model.pageNumber ? 1 : -1); 479 | 480 | model.pageNumber = pageNumber; 481 | 482 | self.render(); 483 | 484 | if (self.disabled && self.isAsync) { 485 | // enable pagination 486 | self.enable(); 487 | } 488 | 489 | // cache model data 490 | container.data('pagination').model = model; 491 | 492 | // format result data before callback invoked 493 | if (attributes.formatResult) { 494 | var cloneData = $.extend(true, [], data); 495 | if (!Helpers.isArray(data = attributes.formatResult(cloneData))) { 496 | data = cloneData; 497 | } 498 | } 499 | 500 | container.data('pagination').currentPageData = data; 501 | 502 | self.doCallback(data, callback); 503 | 504 | self.callHook('afterPaging', pageNumber); 505 | 506 | if (pageNumber == 1) { 507 | self.callHook('afterIsFirstPage'); 508 | } else if (pageNumber == self.getTotalPage()) { 509 | self.callHook('afterIsLastPage'); 510 | } 511 | } 512 | }, 513 | 514 | doCallback: function(data, customCallback) { 515 | var self = this; 516 | var model = self.model; 517 | 518 | if (typeof customCallback === 'function') { 519 | customCallback(data, model); 520 | } else if (typeof attributes.callback === 'function') { 521 | attributes.callback(data, model); 522 | } 523 | }, 524 | 525 | destroy: function() { 526 | if (this.callHook('beforeDestroy') === false) return; 527 | 528 | this.model.el.remove(); 529 | container.off(); 530 | 531 | // Remove style element 532 | $('#paginationjs-style').remove(); 533 | 534 | this.callHook('afterDestroy'); 535 | }, 536 | 537 | previous: function(callback) { 538 | this.go(this.model.pageNumber - 1, callback); 539 | }, 540 | 541 | next: function(callback) { 542 | this.go(this.model.pageNumber + 1, callback); 543 | }, 544 | 545 | disable: function() { 546 | var self = this; 547 | var source = self.isAsync ? 'async' : 'sync'; 548 | 549 | if (self.callHook('beforeDisable', source) === false) return; 550 | 551 | self.disabled = true; 552 | self.model.disabled = true; 553 | 554 | self.callHook('afterDisable', source); 555 | }, 556 | 557 | enable: function() { 558 | var self = this; 559 | var source = self.isAsync ? 'async' : 'sync'; 560 | 561 | if (self.callHook('beforeEnable', source) === false) return; 562 | 563 | self.disabled = false; 564 | self.model.disabled = false; 565 | 566 | self.callHook('afterEnable', source); 567 | }, 568 | 569 | refresh: function(callback) { 570 | this.go(this.model.pageNumber, callback); 571 | }, 572 | 573 | show: function() { 574 | var self = this; 575 | 576 | if (self.model.el.is(':visible')) return; 577 | 578 | self.model.el.show(); 579 | }, 580 | 581 | hide: function() { 582 | var self = this; 583 | 584 | if (!self.model.el.is(':visible')) return; 585 | 586 | self.model.el.hide(); 587 | }, 588 | 589 | // Replace variables for template string 590 | replaceVariables: function(template, variables) { 591 | var formattedString; 592 | 593 | for (var key in variables) { 594 | var value = variables[key]; 595 | var regexp = new RegExp('<%=\\s*' + key + '\\s*%>', 'img'); 596 | 597 | formattedString = (formattedString || template).replace(regexp, value); 598 | } 599 | 600 | return formattedString; 601 | }, 602 | 603 | getPagingData: function(number) { 604 | var pageSize = attributes.pageSize; 605 | var dataSource = attributes.dataSource; 606 | var totalNumber = this.getTotalNumber(); 607 | 608 | var start = pageSize * (number - 1) + 1; 609 | var end = Math.min(number * pageSize, totalNumber); 610 | 611 | return dataSource.slice(start - 1, end); 612 | }, 613 | 614 | getTotalNumber: function() { 615 | return this.model.totalNumber || attributes.totalNumber || 0; 616 | }, 617 | 618 | getTotalPage: function() { 619 | return Math.ceil(this.getTotalNumber() / attributes.pageSize); 620 | }, 621 | 622 | getLocator: function(locator) { 623 | var result; 624 | 625 | if (typeof locator === 'string') { 626 | result = locator; 627 | } else if (typeof locator === 'function') { 628 | result = locator(); 629 | } else { 630 | throwError('"locator" is incorrect. Expect string or function type.'); 631 | } 632 | 633 | return result; 634 | }, 635 | 636 | // Filter data with "locator" 637 | filterDataWithLocator: function(dataSource) { 638 | var locator = this.getLocator(attributes.locator); 639 | var filteredData; 640 | 641 | // Datasource is an Object, use "locator" to locate available data 642 | if (Helpers.isObject(dataSource)) { 643 | try { 644 | $.each(locator.split('.'), function(index, item) { 645 | filteredData = (filteredData ? filteredData : dataSource)[item]; 646 | }); 647 | } 648 | catch (e) { 649 | // ignore 650 | } 651 | 652 | if (!filteredData) { 653 | throwError('dataSource.' + locator + ' is undefined.'); 654 | } else if (!Helpers.isArray(filteredData)) { 655 | throwError('dataSource.' + locator + ' should be an Array.'); 656 | } 657 | } 658 | 659 | return filteredData || dataSource; 660 | }, 661 | 662 | parseDataSource: function(dataSource, callback) { 663 | var self = this; 664 | 665 | if (Helpers.isObject(dataSource)) { 666 | callback(attributes.dataSource = self.filterDataWithLocator(dataSource)); 667 | } else if (Helpers.isArray(dataSource)) { 668 | callback(attributes.dataSource = dataSource); 669 | } else if (typeof dataSource === 'function') { 670 | attributes.dataSource(function(data) { 671 | if (!Helpers.isArray(data)) { 672 | throwError('The parameter of "done" Function should be an Array.'); 673 | } 674 | self.parseDataSource.call(self, data, callback); 675 | }); 676 | } else if (typeof dataSource === 'string') { 677 | if (/^https?|file:/.test(dataSource)) { 678 | attributes.ajaxDataType = 'jsonp'; 679 | } 680 | callback(dataSource); 681 | } else { 682 | throwError('Unexpected dataSource type'); 683 | } 684 | }, 685 | 686 | callHook: function(hook) { 687 | var paginationData = container.data('pagination') || {}; 688 | var result; 689 | 690 | var args = Array.prototype.slice.apply(arguments); 691 | args.shift(); 692 | 693 | if (attributes[hook] && typeof attributes[hook] === 'function') { 694 | if (attributes[hook].apply(global, args) === false) { 695 | result = false; 696 | } 697 | } 698 | 699 | if (paginationData.hooks && paginationData.hooks[hook]) { 700 | $.each(paginationData.hooks[hook], function(index, item) { 701 | if (item.apply(global, args) === false) { 702 | result = false; 703 | } 704 | }); 705 | } 706 | 707 | return result !== false; 708 | }, 709 | 710 | observer: function() { 711 | var self = this; 712 | var el = self.model.el; 713 | 714 | // Go to specified page number 715 | container.on(eventPrefix + 'go', function(event, pageNumber, done) { 716 | if (typeof pageNumber === 'string') { 717 | pageNumber = parseInt(pageNumber.trim()); 718 | } 719 | 720 | if (!pageNumber) return; 721 | 722 | if (typeof pageNumber !== 'number') { 723 | throwError('"pageNumber" is incorrect. (Number)'); 724 | } 725 | 726 | self.go(pageNumber, done); 727 | }); 728 | 729 | // Page number button click listener 730 | el.on('click', '.J-paginationjs-page', function(event) { 731 | var current = $(event.currentTarget); 732 | var pageNumber = current.attr('data-num').trim(); 733 | 734 | if (!pageNumber || current.hasClass(attributes.disableClassName) || current.hasClass(attributes.activeClassName)) return; 735 | 736 | if (self.callHook('beforePageOnClick', event, pageNumber) === false) return false; 737 | 738 | self.go(pageNumber); 739 | 740 | self.callHook('afterPageOnClick', event, pageNumber); 741 | 742 | if (!attributes.pageLink) return false; 743 | }); 744 | 745 | // Previous button click listener 746 | el.on('click', '.J-paginationjs-previous', function(event) { 747 | var current = $(event.currentTarget); 748 | var pageNumber = current.attr('data-num').trim(); 749 | 750 | if (!pageNumber || current.hasClass(attributes.disableClassName)) return; 751 | 752 | if (self.callHook('beforePreviousOnClick', event, pageNumber) === false) return false; 753 | 754 | self.go(pageNumber); 755 | 756 | self.callHook('afterPreviousOnClick', event, pageNumber); 757 | 758 | if (!attributes.pageLink) return false; 759 | }); 760 | 761 | // Next button click listener 762 | el.on('click', '.J-paginationjs-next', function(event) { 763 | var current = $(event.currentTarget); 764 | var pageNumber = current.attr('data-num').trim(); 765 | 766 | if (!pageNumber || current.hasClass(attributes.disableClassName)) return; 767 | 768 | if (self.callHook('beforeNextOnClick', event, pageNumber) === false) return false; 769 | 770 | self.go(pageNumber); 771 | 772 | self.callHook('afterNextOnClick', event, pageNumber); 773 | 774 | if (!attributes.pageLink) return false; 775 | }); 776 | 777 | // Go button click listener 778 | el.on('click', '.J-paginationjs-go-button', function(event) { 779 | var pageNumber = $('.J-paginationjs-go-pagenumber', el).val(); 780 | 781 | if (self.callHook('beforeGoButtonOnClick', event, pageNumber) === false) return false; 782 | 783 | container.trigger(eventPrefix + 'go', pageNumber); 784 | 785 | self.callHook('afterGoButtonOnClick', event, pageNumber); 786 | }); 787 | 788 | // go input enter keyup listener 789 | el.on('keyup', '.J-paginationjs-go-pagenumber', function(event) { 790 | if (event.which === 13) { 791 | var pageNumber = $(event.currentTarget).val(); 792 | 793 | if (self.callHook('beforeGoInputOnEnter', event, pageNumber) === false) return false; 794 | 795 | container.trigger(eventPrefix + 'go', pageNumber); 796 | 797 | // Maintain the cursor 798 | $('.J-paginationjs-go-pagenumber', el).focus(); 799 | 800 | self.callHook('afterGoInputOnEnter', event, pageNumber); 801 | } 802 | }); 803 | 804 | el.on('change', '.J-paginationjs-size-select', function(event) { 805 | var current = $(event.currentTarget); 806 | var size = parseInt(current.val()); 807 | var currentPage = self.model.pageNumber || attributes.pageNumber; 808 | 809 | if (typeof size !== 'number') return; 810 | 811 | if (self.callHook('beforeSizeSelectorChange', event, size) === false) return false; 812 | 813 | attributes.pageSize = size; 814 | self.model.pageSize = size; 815 | self.model.totalPage = self.getTotalPage(); 816 | if (currentPage > self.model.totalPage) { 817 | currentPage = self.model.totalPage; 818 | } 819 | self.go(currentPage); 820 | 821 | self.callHook('afterSizeSelectorChange', event, size); 822 | 823 | if (!attributes.pageLink) return false; 824 | }); 825 | 826 | // Previous page 827 | container.on(eventPrefix + 'previous', function(event, done) { 828 | self.previous(done); 829 | }); 830 | 831 | // Next page 832 | container.on(eventPrefix + 'next', function(event, done) { 833 | self.next(done); 834 | }); 835 | 836 | // Disable 837 | container.on(eventPrefix + 'disable', function() { 838 | self.disable(); 839 | }); 840 | 841 | // Enable 842 | container.on(eventPrefix + 'enable', function() { 843 | self.enable(); 844 | }); 845 | 846 | // Refresh 847 | container.on(eventPrefix + 'refresh', function(event, done) { 848 | self.refresh(done); 849 | }); 850 | 851 | // Show 852 | container.on(eventPrefix + 'show', function() { 853 | self.show(); 854 | }); 855 | 856 | // Hide 857 | container.on(eventPrefix + 'hide', function() { 858 | self.hide(); 859 | }); 860 | 861 | // Destroy 862 | container.on(eventPrefix + 'destroy', function() { 863 | self.destroy(); 864 | }); 865 | 866 | // Whether to load the default page 867 | var validTotalPage = Math.max(self.getTotalPage(), 1) 868 | var defaultPageNumber = attributes.pageNumber; 869 | 870 | // Default pageNumber should be 1 when totalNumber is dynamic 871 | if (self.isDynamicTotalNumber) { 872 | if (attributes.resetPageNumberOnInit) defaultPageNumber = 1; 873 | } 874 | 875 | if (attributes.triggerPagingOnInit) { 876 | container.trigger(eventPrefix + 'go', Math.min(defaultPageNumber, validTotalPage)); 877 | } 878 | } 879 | }; 880 | 881 | // Pagination has been initialized 882 | if (container.data('pagination') && container.data('pagination').initialized === true) { 883 | // Handle events 884 | if (isNumeric(options)) { 885 | // eg: container.pagination(5) 886 | container.trigger.call(this, eventPrefix + 'go', options, arguments[1]); 887 | return this; 888 | } else if (typeof options === 'string') { 889 | var args = Array.prototype.slice.apply(arguments); 890 | args[0] = eventPrefix + args[0]; 891 | 892 | switch (options) { 893 | case 'previous': 894 | case 'next': 895 | case 'go': 896 | case 'disable': 897 | case 'enable': 898 | case 'refresh': 899 | case 'show': 900 | case 'hide': 901 | case 'destroy': 902 | container.trigger.apply(this, args); 903 | break; 904 | case 'getSelectedPageNum': 905 | case 'getCurrentPageNum': 906 | if (container.data('pagination').model) { 907 | return container.data('pagination').model.pageNumber; 908 | } else { 909 | return container.data('pagination').attributes.pageNumber; 910 | } 911 | case 'getTotalPage': 912 | return Math.ceil(container.data('pagination').model.totalNumber / container.data('pagination').model.pageSize); 913 | case 'getSelectedPageData': 914 | case 'getCurrentPageData': 915 | return container.data('pagination').currentPageData; 916 | // Whether pagination has been disabled 917 | case 'isDisabled': 918 | return container.data('pagination').model.disabled === true; 919 | default: 920 | throwError('Unknown action: ' + options); 921 | } 922 | return this; 923 | } else { 924 | // Uninstall the old instance before initializing a new one 925 | uninstallPlugin(container); 926 | } 927 | } else { 928 | if (!Helpers.isObject(options)) throwError('Illegal options'); 929 | } 930 | 931 | // Check parameters 932 | parameterChecker(attributes); 933 | 934 | pagination.initialize(); 935 | 936 | return this; 937 | }; 938 | 939 | // Instance defaults 940 | $.fn[pluginName].defaults = { 941 | 942 | // Data source 943 | // Array | String | Function | Object 944 | //dataSource: '', 945 | 946 | // String | Function 947 | //locator: 'data', 948 | 949 | // Function 950 | //totalNumberLocator: function() {}, 951 | 952 | // Total number of data items 953 | totalNumber: 0, 954 | 955 | // Default page number 956 | pageNumber: 1, 957 | 958 | // Number of data items per page 959 | pageSize: 10, 960 | 961 | // Page range (pages around current page) 962 | pageRange: 2, 963 | 964 | // Whether to display the 'Previous' button 965 | showPrevious: true, 966 | 967 | // Whether to display the 'Next' button 968 | showNext: true, 969 | 970 | // Whether to display the page buttons 971 | showPageNumbers: true, 972 | 973 | showNavigator: false, 974 | 975 | // Whether to display the 'Go' input 976 | showGoInput: false, 977 | 978 | // Whether to display the 'Go' button 979 | showGoButton: false, 980 | 981 | showSizeChanger: false, 982 | 983 | sizeChangerOptions: [10, 20, 50, 100], 984 | 985 | // Page link 986 | pageLink: '', 987 | 988 | // 'Previous' text 989 | prevText: '‹', 990 | 991 | // 'Next' text 992 | nextText: '›', 993 | 994 | // Ellipsis text 995 | ellipsisText: '...', 996 | 997 | // 'Go' button text 998 | goButtonText: 'Go', 999 | 1000 | // Additional class name(s) for the Pagination container 1001 | //className: '', 1002 | 1003 | classPrefix: 'paginationjs', 1004 | 1005 | activeClassName: 'active', 1006 | 1007 | // class name when disabled 1008 | disableClassName: 'disabled', 1009 | 1010 | //ulClassName: '', 1011 | 1012 | //pageClassName: '', 1013 | 1014 | //prevClassName: '', 1015 | 1016 | //nextClassName: '', 1017 | 1018 | formatNavigator: 'Total <%= totalNumber %> items', 1019 | 1020 | formatGoInput: '<%= input %>', 1021 | 1022 | formatGoButton: '<%= button %>', 1023 | 1024 | // position in the container 1025 | position: 'bottom', 1026 | 1027 | // Auto hide previous button when current page is the first 1028 | autoHidePrevious: false, 1029 | 1030 | // Auto hide next button when current page is the last 1031 | autoHideNext: false, 1032 | 1033 | //header: '', 1034 | 1035 | //footer: '', 1036 | 1037 | //alias: {}, 1038 | 1039 | // Whether to trigger pagination at initialization 1040 | triggerPagingOnInit: true, 1041 | 1042 | // Whether to reset page number at initialization, it works only if dataSource is a URL and totalNumberLocator is specified 1043 | resetPageNumberOnInit: true, 1044 | 1045 | // Whether to hide pagination when less than one page 1046 | hideOnlyOnePage: false, 1047 | 1048 | hideFirstOnEllipsisShow: false, 1049 | 1050 | hideLastOnEllipsisShow: false, 1051 | 1052 | // Customize item's innerHTML 1053 | callback: function() {} 1054 | }; 1055 | 1056 | // Hook register 1057 | $.fn[pluginHookMethod] = function(hook, callback) { 1058 | if (arguments.length < 2) { 1059 | throwError('Expect 2 arguments at least.'); 1060 | } 1061 | 1062 | if (typeof callback !== 'function') { 1063 | throwError('callback should be a function.'); 1064 | } 1065 | 1066 | var container = $(this); 1067 | var paginationData = container.data('pagination'); 1068 | 1069 | if (!paginationData) { 1070 | container.data('pagination', {}); 1071 | paginationData = container.data('pagination'); 1072 | } 1073 | 1074 | !paginationData.hooks && (paginationData.hooks = {}); 1075 | 1076 | //paginationData.hooks[hook] = callback; 1077 | paginationData.hooks[hook] = paginationData.hooks[hook] || []; 1078 | paginationData.hooks[hook].push(callback); 1079 | 1080 | }; 1081 | 1082 | // Static method 1083 | $[pluginName] = function(selector, options) { 1084 | if (arguments.length < 2) { 1085 | throwError('Requires two parameters.'); 1086 | } 1087 | 1088 | var container; 1089 | 1090 | // 'selector' is a jQuery object 1091 | if (typeof selector !== 'string' && selector instanceof jQuery) { 1092 | container = selector; 1093 | } else { 1094 | container = $(selector); 1095 | } 1096 | 1097 | if (!container.length) return; 1098 | 1099 | container.pagination(options); 1100 | 1101 | return container; 1102 | }; 1103 | 1104 | // ============================================================ 1105 | // helpers 1106 | // ============================================================ 1107 | 1108 | var Helpers = {}; 1109 | 1110 | // Throw error 1111 | function throwError(content) { 1112 | throw new Error('Pagination: ' + content); 1113 | } 1114 | 1115 | // Check parameters 1116 | function parameterChecker(args) { 1117 | if (!args.dataSource) { 1118 | throwError('"dataSource" is required.'); 1119 | } 1120 | 1121 | if (typeof args.dataSource === 'string') { 1122 | if (args.totalNumberLocator === undefined) { 1123 | if (args.totalNumber === undefined) { 1124 | throwError('"totalNumber" is required.'); 1125 | } else if (!isNumeric(args.totalNumber)) { 1126 | throwError('"totalNumber" is incorrect. Expect numberic type'); 1127 | } 1128 | } else { 1129 | if (typeof args.totalNumberLocator !== 'function') { 1130 | throwError('"totalNumberLocator" should be a Function.'); 1131 | } 1132 | } 1133 | } else if (Helpers.isObject(args.dataSource)) { 1134 | if (typeof args.locator === 'undefined') { 1135 | throwError('"dataSource" is an Object, please specify a "locator".'); 1136 | } else if (typeof args.locator !== 'string' && typeof args.locator !== 'function') { 1137 | throwError('' + args.locator + ' is incorrect. Expect string or function type'); 1138 | } 1139 | } 1140 | 1141 | if (args.formatResult !== undefined && typeof args.formatResult !== 'function') { 1142 | throwError('"formatResult" should be a Function.'); 1143 | } 1144 | 1145 | if (args.onError !== undefined && typeof args.onError !== 'function') { 1146 | throwError('"onError" should be a Function.'); 1147 | } 1148 | } 1149 | 1150 | // uninstall plugin 1151 | function uninstallPlugin(target) { 1152 | var events = ['go', 'previous', 'next', 'disable', 'enable', 'refresh', 'show', 'hide', 'destroy']; 1153 | 1154 | // off all events 1155 | $.each(events, function(index, value) { 1156 | target.off(eventPrefix + value); 1157 | }); 1158 | 1159 | // reset pagination data 1160 | target.data('pagination', {}); 1161 | 1162 | // remove pagination element 1163 | $('.paginationjs', target).remove(); 1164 | } 1165 | 1166 | // Object type detection 1167 | function getObjectType(object, tmp) { 1168 | return ( (tmp = typeof(object)) == "object" ? object == null && "null" || Object.prototype.toString.call(object).slice(8, -1) : tmp ).toLowerCase(); 1169 | } 1170 | 1171 | function isNumeric(n) { 1172 | return !isNaN(parseFloat(n)) && isFinite(n); 1173 | } 1174 | 1175 | $.each(['Object', 'Array', 'String'], function(index, name) { 1176 | Helpers['is' + name] = function(object) { 1177 | return getObjectType(object) === name.toLowerCase(); 1178 | }; 1179 | }); 1180 | 1181 | /* 1182 | * export via AMD or CommonJS 1183 | * */ 1184 | if (typeof define === 'function' && define.amd) { 1185 | define(function() { 1186 | return $; 1187 | }); 1188 | } 1189 | 1190 | })(this, window.jQuery); 1191 | -------------------------------------------------------------------------------- /dist/pagination.less: -------------------------------------------------------------------------------- 1 | @borderColor: #aaa; 2 | @activeBgColor: #aaa; 3 | 4 | @Blue_color_base: #289DE9; 5 | @Blue_color_font: @Blue_color_base; 6 | @Blue_color_border: @Blue_color_base; 7 | @Blue_bgColor_active: @Blue_color_base; 8 | @Blue_bgColor_hover: #E9F4FC; 9 | @Blue_bgColor_buttonHover: #3CA5EA; 10 | 11 | @Green_color_base: #449D44; 12 | @Green_color_font: @Green_color_base; 13 | @Green_color_border: @Green_color_base; 14 | @Green_bgColor_active: @Green_color_base; 15 | @Green_bgColor_hover: #EBF4EB; 16 | @Green_bgColor_buttonHover: #55A555; 17 | 18 | @Yellow_color_base: #EC971F; 19 | @Yellow_color_font: @Yellow_color_base; 20 | @Yellow_color_border: @Yellow_color_base; 21 | @Yellow_bgColor_active: @Yellow_color_base; 22 | @Yellow_bgColor_hover: #FDF5E9; 23 | @Yellow_bgColor_buttonHover: #EEA135; 24 | 25 | @Red_color_base: #C9302C; 26 | @Red_color_font: @Red_color_base; 27 | @Red_color_border: @Red_color_base; 28 | @Red_bgColor_active: @Red_color_base; 29 | @Red_bgColor_hover: #FAEAEA; 30 | @Red_bgColor_buttonHover: #CE4541; 31 | 32 | @S_fontSize: 12px; 33 | @S_minWidth: 26px; 34 | @S_height: 24px; 35 | @S_lineHeight: @S_height; 36 | @S_activeHeight: @S_height + 2; 37 | @S_inputWidth: 26px; 38 | @S_inputHeight: 24px; 39 | @S_buttonMinWidth: 30px; 40 | @S_buttonHeight: 26px; 41 | @S_buttonLineHeight: @S_buttonHeight - 2; 42 | @S_buttonPadding: 0 6px; 43 | @S_navHeight: @S_activeHeight; 44 | 45 | 46 | @N_fontSize: 14px; 47 | @N_minWidth: 30px; 48 | @N_height: 28px; 49 | @N_lineHeight: @N_height; 50 | @N_activeHeight: @N_height + 2; 51 | @N_inputWidth: 30px; 52 | @N_inputHeight: 28px; 53 | @N_buttonMinWidth: 40px; 54 | @N_buttonHeight: 30px; 55 | @N_buttonLineHeight: @N_buttonHeight - 2; 56 | @N_buttonPadding: 0 8px; 57 | @N_navHeight: @N_activeHeight; 58 | 59 | 60 | @B_fontSize: 16px; 61 | @B_minWidth: 36px; 62 | @B_height: 34px; 63 | @B_lineHeight: @B_height; 64 | @B_activeHeight: @B_height + 2; 65 | @B_inputWidth: 36px; 66 | @B_inputHeight: 34px; 67 | @B_buttonMinWidth: 50px; 68 | @B_buttonHeight: 36px; 69 | @B_buttonLineHeight: @B_buttonHeight - 2; 70 | @B_buttonPadding: 0 12px; 71 | @B_navHeight: @B_activeHeight; 72 | 73 | 74 | .paginationjs{ 75 | display: flex; 76 | line-height: 1.6; 77 | font-family: "Marmelad", "Lucida Grande", "Arial", "Hiragino Sans GB", Georgia, sans-serif; 78 | font-size: @N_fontSize; 79 | box-sizing: initial; 80 | &:after{ 81 | display: table; 82 | content: " "; 83 | clear: both; 84 | } 85 | .paginationjs-pages{ 86 | float: left; 87 | margin-left: 10px; 88 | ul{ 89 | float: left; 90 | margin: 0; 91 | padding: 0; 92 | } 93 | li{ 94 | float: left; 95 | border: 1px solid @borderColor; 96 | border-right: none; 97 | list-style: none; 98 | > a{ 99 | min-width: @N_minWidth; 100 | height: @N_height; 101 | line-height: @N_lineHeight; 102 | display: block; 103 | background: #fff; 104 | font-size: @N_fontSize; 105 | color: #333; 106 | text-decoration: none; 107 | text-align: center; 108 | cursor: pointer; 109 | &:hover{ 110 | background: #eee; 111 | } 112 | } 113 | &.active{ 114 | border: none; 115 | > a{ 116 | height: @N_activeHeight; 117 | line-height: @N_activeHeight; 118 | background: @activeBgColor; 119 | color: #fff; 120 | cursor: default; 121 | } 122 | } 123 | &.disabled{ 124 | > a{ 125 | opacity: .3; 126 | cursor: default; 127 | &:hover{ 128 | background: none; 129 | } 130 | } 131 | } 132 | &:first-child{ 133 | border-radius: 3px 0 0 3px; 134 | > a{ 135 | border-radius: 3px 0 0 3px; 136 | } 137 | } 138 | &:last-child{ 139 | border-right: 1px solid @borderColor; 140 | border-radius: 0 3px 3px 0; 141 | > a{ 142 | border-radius: 0 3px 3px 0; 143 | } 144 | } 145 | } 146 | } 147 | .paginationjs-size-changer { 148 | float: left; 149 | font-size: @N_fontSize; 150 | margin-left: 10px; 151 | > select{ 152 | height: @N_inputHeight; 153 | background: #fff; 154 | border-radius: 3px; 155 | border: 1px solid @borderColor; 156 | padding: 0; 157 | font-size: @N_fontSize; 158 | text-align: center; 159 | vertical-align: baseline; 160 | outline: none; 161 | box-shadow: none; 162 | box-sizing: initial; 163 | } 164 | } 165 | .paginationjs-go-input{ 166 | float: left; 167 | margin-left: 10px; 168 | font-size: @N_fontSize; 169 | > input[type="text"]{ 170 | width: @N_inputWidth; 171 | height: @N_inputHeight; 172 | background: #fff; 173 | border-radius: 3px; 174 | border: 1px solid @borderColor; 175 | padding: 0; 176 | font-size: @N_fontSize; 177 | text-align: center; 178 | vertical-align: baseline; 179 | outline: none; 180 | box-shadow: none; 181 | box-sizing: initial; 182 | } 183 | } 184 | .paginationjs-go-button{ 185 | float: left; 186 | margin-left: 10px; 187 | font-size: @N_fontSize; 188 | > input[type="button"]{ 189 | min-width: @N_buttonMinWidth; 190 | height: @N_buttonHeight; 191 | line-height: @N_buttonLineHeight; 192 | background: #fff; 193 | border-radius: 3px; 194 | border: 1px solid @borderColor; 195 | text-align: center; 196 | padding: @N_buttonPadding; 197 | font-size: @N_fontSize; 198 | vertical-align: baseline; 199 | outline: none; 200 | box-shadow: none; 201 | color: #333; 202 | cursor: pointer; 203 | &:hover{ 204 | background-color: #f8f8f8; 205 | } 206 | } 207 | } 208 | .paginationjs-nav{ 209 | float: left; 210 | height: @N_navHeight; 211 | line-height: @N_navHeight; 212 | font-size: @N_fontSize; 213 | } 214 | 215 | &.paginationjs-small{ 216 | font-size: @S_fontSize; 217 | .paginationjs-pages{ 218 | li{ 219 | > a{ 220 | min-width: @S_minWidth; 221 | height: @S_height; 222 | line-height: @S_lineHeight; 223 | font-size: @S_fontSize; 224 | } 225 | &.active{ 226 | > a{ 227 | height: @S_activeHeight; 228 | line-height: @S_activeHeight; 229 | } 230 | } 231 | } 232 | } 233 | .paginationjs-size-changer { 234 | font-size: @S_fontSize; 235 | > select{ 236 | height: @S_inputHeight; 237 | font-size: @S_fontSize; 238 | } 239 | } 240 | .paginationjs-go-input{ 241 | font-size: @S_fontSize; 242 | > input[type="text"]{ 243 | width: @S_inputWidth; 244 | height: @S_inputHeight; 245 | font-size: @S_fontSize; 246 | } 247 | } 248 | .paginationjs-go-button{ 249 | font-size: @S_fontSize; 250 | > input[type="button"]{ 251 | min-width: @S_buttonMinWidth; 252 | height: @S_buttonHeight; 253 | line-height: @S_buttonLineHeight; 254 | padding: @S_buttonPadding; 255 | font-size: @S_fontSize; 256 | } 257 | } 258 | .paginationjs-nav{ 259 | height: 26px; 260 | line-height: 26px; 261 | font-size: @S_fontSize; 262 | } 263 | } 264 | &.paginationjs-big{ 265 | font-size: @B_fontSize; 266 | .paginationjs-pages{ 267 | li{ 268 | > a{ 269 | min-width: @B_minWidth; 270 | height: @B_height; 271 | line-height: @B_lineHeight; 272 | font-size: @B_fontSize; 273 | } 274 | &.active{ 275 | > a{ 276 | height: @B_activeHeight; 277 | line-height: @B_activeHeight; 278 | } 279 | } 280 | } 281 | } 282 | .paginationjs-size-changer { 283 | font-size: @B_fontSize; 284 | > select{ 285 | height: @B_inputHeight; 286 | font-size: @B_fontSize; 287 | } 288 | } 289 | .paginationjs-go-input{ 290 | font-size: @B_fontSize; 291 | > input[type="text"]{ 292 | width: @B_inputWidth; 293 | height: @B_inputHeight; 294 | font-size: @B_fontSize; 295 | } 296 | } 297 | .paginationjs-go-button{ 298 | font-size: @B_fontSize; 299 | > input[type="button"]{ 300 | min-width: @B_buttonMinWidth; 301 | height: @B_buttonHeight; 302 | line-height: @B_buttonLineHeight; 303 | padding: @B_buttonPadding; 304 | font-size: @B_fontSize; 305 | } 306 | } 307 | .paginationjs-nav{ 308 | height: @B_navHeight; 309 | line-height: @B_navHeight; 310 | font-size: @B_fontSize; 311 | } 312 | } 313 | 314 | > :first-child { 315 | margin-left: 0; 316 | } 317 | } 318 | 319 | .paginationjs{ 320 | &.paginationjs-theme-blue{ 321 | .paginationjs-pages{ 322 | li{ 323 | border-color: @Blue_color_border; 324 | > a{ 325 | color: @Blue_color_font; 326 | &:hover{ 327 | background: @Blue_bgColor_hover; 328 | } 329 | } 330 | &.active{ 331 | > a{ 332 | background: @Blue_bgColor_active; 333 | color: #fff; 334 | } 335 | } 336 | &.disabled > a:hover{ 337 | background: none; 338 | } 339 | } 340 | } 341 | .paginationjs-size-changer { 342 | > select{ 343 | border-color: @Blue_color_border; 344 | } 345 | } 346 | .paginationjs-go-input{ 347 | > input[type="text"]{ 348 | border-color: @Blue_color_border; 349 | } 350 | } 351 | .paginationjs-go-button{ 352 | > input[type="button"]{ 353 | background: @Blue_bgColor_active; 354 | border-color: @Blue_color_border; 355 | color: #fff; 356 | &:hover{ 357 | background-color: @Blue_bgColor_buttonHover; 358 | } 359 | } 360 | } 361 | } 362 | } 363 | 364 | .paginationjs{ 365 | &.paginationjs-theme-green{ 366 | .paginationjs-pages{ 367 | li{ 368 | border-color: @Green_color_border; 369 | > a{ 370 | color: @Green_color_font; 371 | &:hover{ 372 | background: @Green_bgColor_hover; 373 | } 374 | } 375 | &.active{ 376 | > a{ 377 | background: @Green_bgColor_active; 378 | color: #fff; 379 | } 380 | } 381 | &.disabled > a:hover{ 382 | background: none; 383 | } 384 | } 385 | } 386 | .paginationjs-size-changer { 387 | > select{ 388 | border-color: @Green_color_border; 389 | } 390 | } 391 | .paginationjs-go-input{ 392 | > input[type="text"]{ 393 | border-color: @Green_color_border; 394 | } 395 | } 396 | .paginationjs-go-button{ 397 | > input[type="button"]{ 398 | background: @Green_bgColor_active; 399 | border-color: @Green_color_border; 400 | color: #fff; 401 | &:hover{ 402 | background-color: @Green_bgColor_buttonHover; 403 | } 404 | } 405 | } 406 | } 407 | } 408 | 409 | .paginationjs{ 410 | &.paginationjs-theme-yellow{ 411 | .paginationjs-pages{ 412 | li{ 413 | border-color: @Yellow_color_border; 414 | > a{ 415 | color: @Yellow_color_font; 416 | &:hover{ 417 | background: @Yellow_bgColor_hover; 418 | } 419 | } 420 | &.active{ 421 | > a{ 422 | background: @Yellow_bgColor_active; 423 | color: #fff; 424 | } 425 | } 426 | &.disabled > a:hover{ 427 | background: none; 428 | } 429 | } 430 | } 431 | .paginationjs-size-changer { 432 | > select{ 433 | border-color: @Yellow_color_border; 434 | } 435 | } 436 | .paginationjs-go-input{ 437 | > input[type="text"]{ 438 | border-color: @Yellow_color_border; 439 | } 440 | } 441 | .paginationjs-go-button{ 442 | > input[type="button"]{ 443 | background: @Yellow_bgColor_active; 444 | border-color: @Yellow_color_border; 445 | color: #fff; 446 | &:hover{ 447 | background-color: @Yellow_bgColor_buttonHover; 448 | } 449 | } 450 | } 451 | } 452 | } 453 | 454 | .paginationjs{ 455 | &.paginationjs-theme-red{ 456 | .paginationjs-pages{ 457 | li{ 458 | border-color: @Red_color_border; 459 | > a{ 460 | color: @Red_color_font; 461 | &:hover{ 462 | background: @Red_bgColor_hover; 463 | } 464 | } 465 | &.active{ 466 | > a{ 467 | background: @Red_bgColor_active; 468 | color: #fff; 469 | } 470 | } 471 | &.disabled > a:hover{ 472 | background: none; 473 | } 474 | } 475 | } 476 | .paginationjs-size-changer { 477 | > select{ 478 | border-color: @Red_color_border; 479 | } 480 | } 481 | .paginationjs-go-input{ 482 | > input[type="text"]{ 483 | border-color: @Red_color_border; 484 | } 485 | } 486 | .paginationjs-go-button{ 487 | > input[type="button"]{ 488 | background: @Red_bgColor_active; 489 | border-color: @Red_color_border; 490 | color: #fff; 491 | &:hover{ 492 | background-color: @Red_bgColor_buttonHover; 493 | } 494 | } 495 | } 496 | } 497 | } 498 | 499 | /* Hacks for IE 6~9 */ 500 | .paginationjs{ 501 | .paginationjs-pages{ 502 | li{ 503 | > a{ 504 | 505 | } 506 | &.paginationjs-next{ 507 | *border-right: 1px solid @borderColor; 508 | border-right: 1px solid #aaa\0; 509 | } 510 | } 511 | } 512 | .paginationjs-size-changer{ 513 | *margin-left: 5px; 514 | margin-left: 5px\0; 515 | > select{ 516 | *line-height: @N_inputHeight; 517 | line-height: 28px\0; 518 | *vertical-align: middle; 519 | vertical-align: middle\0; 520 | } 521 | } 522 | .paginationjs-go-input{ 523 | *margin-left: 5px; 524 | margin-left: 5px\0; 525 | > input[type="text"]{ 526 | *line-height: @N_inputHeight; 527 | line-height: 28px\0; 528 | *vertical-align: middle; 529 | vertical-align: middle\0; 530 | } 531 | } 532 | .paginationjs-go-button{ 533 | *margin-left: 5px; 534 | margin-left: 5px\0; 535 | > input[type="button"]{ 536 | *vertical-align: middle; 537 | vertical-align: middle\0; 538 | } 539 | } 540 | &.paginationjs-big{ 541 | .paginationjs-pages{ 542 | li{ 543 | > a{ 544 | line-height: 36px\0; 545 | } 546 | } 547 | } 548 | .paginationjs-go-input{ 549 | > input[type="text"]{ 550 | *height: 35px; 551 | height: 36px\0; 552 | *line-height: 36px; 553 | line-height: 36px\0; 554 | } 555 | } 556 | } 557 | } 558 | -------------------------------------------------------------------------------- /dist/pagination.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * pagination.js 2.6.0 3 | * A jQuery plugin to provide simple yet fully customisable pagination 4 | * https://github.com/superRaytin/paginationjs 5 | 6 | * Homepage: http://pagination.js.org 7 | * 8 | * Copyright 2014-2100, superRaytin 9 | * Released under the MIT license. 10 | */ 11 | !function(n,u){void 0===u&&l("Pagination requires jQuery.");var r="pagination",s="__pagination-",D=(u.fn.pagination&&l('plugin conflicted, the name "pagination" has been taken by another jQuery plugin.'),u.fn[r]=function(a){if(void 0!==a){var t,c=u(this),J=u.extend({},u.fn[r].defaults,a),e={initialize:function(){var e,t=this;c.data("pagination")||c.data("pagination",{}),!1!==t.callHook("beforeInit")&&(c.data("pagination").initialized&&u(".paginationjs",c).remove(),t.disabled=!!J.disabled,e=t.model={pageRange:J.pageRange,pageSize:J.pageSize},t.parseDataSource(J.dataSource,function(a){t.isAsync=D.isString(a),D.isArray(a)&&(e.totalNumber=J.totalNumber=a.length),t.isDynamicTotalNumber=t.isAsync&&J.totalNumberLocator;a=t.render(!0);J.className&&a.addClass(J.className),e.el=a,c["bottom"===J.position?"append":"prepend"](a),t.observer(),c.data("pagination").initialized=!0,t.callHook("afterInit",a)}))},render:function(a){var e=this,t=e.model,o=t.el||u('
    '),a=!0!==a,t=(e.callHook("beforeRender",a),t.pageNumber||J.pageNumber),i=J.pageRange||0,n=e.getTotalPage(),r=t-i,s=t+i;return(r=n${a}`:`${a}`},generatePageNumbersHTML:function(a){var e,t=a.currentPage,o=this.getTotalPage(),i=this.getPageLinkTag,n=a.rangeStart,r=a.rangeEnd,s="",a=J.ellipsisText,l=J.classPrefix,c=J.pageClassName||"",u=J.activeClassName||"",g=J.disableClassName||"";if(null===J.pageRange)for(e=1;e<=o;e++)s+=e==t?`
  • ${e}
  • `:`
  • ${i(e)}
  • `;else{if(n<=3)for(e=1;e${e}`:`
  • ${i(e)}
  • `;else J.hideFirstOnEllipsisShow||(s+=`
  • ${i(1)}
  • `),s+=`
  • ${a}
  • `;for(e=n;e<=r;e++)s+=e==t?`
  • ${e}
  • `:`
  • ${i(e)}
  • `;if(o-2<=r)for(e=r+1;e<=o;e++)s+=`
  • ${i(e)}
  • `;else s+=`
  • ${a}
  • `,J.hideLastOnEllipsisShow||(s+=`
  • ${i(o)}
  • `)}return s},generateHTML:function(a){var e,t=this,o=a.currentPage,i=t.getTotalPage(),n=t.getPageLinkTag,r=t.getTotalNumber(),s=J.pageSize,l=J.showPrevious,c=J.showNext,u=J.showPageNumbers,g=J.showNavigator,p=J.showSizeChanger,f=J.sizeChangerOptions,d=J.showGoInput,m=J.showGoButton,b=J.prevText,h=J.nextText,v=J.goButtonText,y=J.classPrefix,N=J.disableClassName||"",$=J.ulClassName||"",k=J.prevClassName||"",P=J.nextClassName||"",x="",j='',v=``,T="function"==typeof J.formatSizeChanger?J.formatSizeChanger(o,i,r):J.formatSizeChanger,C="function"==typeof J.formatNavigator?J.formatNavigator(o,i,r):J.formatNavigator,H="function"==typeof J.formatGoInput?J.formatGoInput(S,o,i,r):J.formatGoInput,w="function"==typeof J.formatGoButton?J.formatGoButton(v,o,i,r):J.formatGoButton,O="function"==typeof J.autoHidePrevious?J.autoHidePrevious():J.autoHidePrevious,z="function"==typeof J.autoHideNext?J.autoHideNext():J.autoHideNext,L="function"==typeof J.header?J.header(o,i,r):J.header,E="function"==typeof J.footer?J.footer(o,i,r):J.footer;if(L&&(x+=e=t.replaceVariables(L,{currentPage:o,totalPage:i,totalNumber:r})),g&&C&&(x+=`
    ${e=t.replaceVariables(C,{currentPage:o,totalPage:i,totalNumber:r,rangeStart:(o-1)*s+1,rangeEnd:Math.min(o*s,r)})}
    `),(l||u||c)&&(x=x+'
    '+($?`
      `:"
        "),l&&(o<=1?O||(x+=`
      • ${b}
      • `):x+=`
      • ${n(b)}
      • `),u&&(x+=t.generatePageNumbersHTML(a)),c&&(i<=o?z||(x+=`
      • ${h}
      • `):x+=`
      • ${n(h)}
      • `),x+="
    "),p&&D.isArray(f)){-1===f.indexOf(s)&&(f.unshift(s),f.sort((a,e)=>a-e));for(let a=0;a${f[a]} / page`;e=j+="",x+=`
    ${e=T?t.replaceVariables(T,{length:j,total:r}):e}
    `}return d&&H&&(x+=`
    ${e=t.replaceVariables(H,{currentPage:o,totalPage:i,totalNumber:r,input:S})}
    `),m&&w&&(x+=`
    ${e=t.replaceVariables(w,{currentPage:o,totalPage:i,totalNumber:r,button:v})}
    `),E&&(x+=e=t.replaceVariables(E,{currentPage:o,totalPage:i,totalNumber:r})),x},findTotalNumberFromRemoteResponse:function(a){this.model.totalNumber=J.totalNumberLocator(a)},go:function(a,t){var e,o,i,n,r=this,s=r.model;function l(a){var e;!1!==r.callHook("beforePaging",n)&&(s.direction=void 0===s.pageNumber?0:n>s.pageNumber?1:-1,s.pageNumber=n,r.render(),r.disabled&&r.isAsync&&r.enable(),c.data("pagination").model=s,J.formatResult&&(e=u.extend(!0,[],a),D.isArray(a=J.formatResult(e))||(a=e)),c.data("pagination").currentPageData=a,r.doCallback(a,t),r.callHook("afterPaging",n),1==n?r.callHook("afterIsFirstPage"):n==r.getTotalPage()&&r.callHook("afterIsLastPage"))}r.disabled||(n=a,!(n=parseInt(n)))||n<1||(a=J.pageSize,o=r.getTotalNumber(),i=r.getTotalPage(),0","img"),i=(i||a).replace(t,o);return i},getPagingData:function(a){var e=J.pageSize,t=J.dataSource,o=this.getTotalNumber(),i=e*(a-1)+1,a=Math.min(a*e,o);return t.slice(i-1,a)},getTotalNumber:function(){return this.model.totalNumber||J.totalNumber||0},getTotalPage:function(){return Math.ceil(this.getTotalNumber()/J.pageSize)},getLocator:function(a){var e;return"string"==typeof a?e=a:"function"==typeof a?e=a():l('"locator" is incorrect. Expect string or function type.'),e},filterDataWithLocator:function(t){var o,a=this.getLocator(J.locator);if(D.isObject(t)){try{u.each(a.split("."),function(a,e){o=(o||t)[e]})}catch(a){}o?D.isArray(o)||l("dataSource."+a+" should be an Array."):l("dataSource."+a+" is undefined.")}return o||t},parseDataSource:function(a,e){var t=this;D.isObject(a)?e(J.dataSource=t.filterDataWithLocator(a)):D.isArray(a)?e(J.dataSource=a):"function"==typeof a?J.dataSource(function(a){D.isArray(a)||l('The parameter of "done" Function should be an Array.'),t.parseDataSource.call(t,a,e)}):"string"==typeof a?(/^https?|file:/.test(a)&&(J.ajaxDataType="jsonp"),e(a)):l("Unexpected dataSource type")},callHook:function(a){var t,e=c.data("pagination")||{},o=Array.prototype.slice.apply(arguments);return o.shift(),J[a]&&"function"==typeof J[a]&&!1===J[a].apply(n,o)&&(t=!1),e.hooks&&e.hooks[a]&&u.each(e.hooks[a],function(a,e){!1===e.apply(n,o)&&(t=!1)}),!1!==t},observer:function(){var o=this,t=o.model.el,a=(c.on(s+"go",function(a,e,t){(e="string"==typeof e?parseInt(e.trim()):e)&&("number"!=typeof e&&l('"pageNumber" is incorrect. (Number)'),o.go(e,t))}),t.on("click",".J-paginationjs-page",function(a){var e=u(a.currentTarget),t=e.attr("data-num").trim();if(t&&!e.hasClass(J.disableClassName)&&!e.hasClass(J.activeClassName))return!1!==o.callHook("beforePageOnClick",a,t)&&(o.go(t),o.callHook("afterPageOnClick",a,t),!!J.pageLink)&&void 0}),t.on("click",".J-paginationjs-previous",function(a){var e=u(a.currentTarget),t=e.attr("data-num").trim();if(t&&!e.hasClass(J.disableClassName))return!1!==o.callHook("beforePreviousOnClick",a,t)&&(o.go(t),o.callHook("afterPreviousOnClick",a,t),!!J.pageLink)&&void 0}),t.on("click",".J-paginationjs-next",function(a){var e=u(a.currentTarget),t=e.attr("data-num").trim();if(t&&!e.hasClass(J.disableClassName))return!1!==o.callHook("beforeNextOnClick",a,t)&&(o.go(t),o.callHook("afterNextOnClick",a,t),!!J.pageLink)&&void 0}),t.on("click",".J-paginationjs-go-button",function(a){var e=u(".J-paginationjs-go-pagenumber",t).val();if(!1===o.callHook("beforeGoButtonOnClick",a,e))return!1;c.trigger(s+"go",e),o.callHook("afterGoButtonOnClick",a,e)}),t.on("keyup",".J-paginationjs-go-pagenumber",function(a){if(13===a.which){var e=u(a.currentTarget).val();if(!1===o.callHook("beforeGoInputOnEnter",a,e))return!1;c.trigger(s+"go",e),u(".J-paginationjs-go-pagenumber",t).focus(),o.callHook("afterGoInputOnEnter",a,e)}}),t.on("change",".J-paginationjs-size-select",function(a){var e=u(a.currentTarget),e=parseInt(e.val()),t=o.model.pageNumber||J.pageNumber;if("number"==typeof e)return!1!==o.callHook("beforeSizeSelectorChange",a,e)&&(J.pageSize=e,o.model.pageSize=e,o.model.totalPage=o.getTotalPage(),t>o.model.totalPage&&(t=o.model.totalPage),o.go(t),o.callHook("afterSizeSelectorChange",a,e),!!J.pageLink)&&void 0}),c.on(s+"previous",function(a,e){o.previous(e)}),c.on(s+"next",function(a,e){o.next(e)}),c.on(s+"disable",function(){o.disable()}),c.on(s+"enable",function(){o.enable()}),c.on(s+"refresh",function(a,e){o.refresh(e)}),c.on(s+"show",function(){o.show()}),c.on(s+"hide",function(){o.hide()}),c.on(s+"destroy",function(){o.destroy()}),Math.max(o.getTotalPage(),1)),e=J.pageNumber;o.isDynamicTotalNumber&&J.resetPageNumberOnInit&&(e=1),J.triggerPagingOnInit&&c.trigger(s+"go",Math.min(e,a))}};if(c.data("pagination")&&!0===c.data("pagination").initialized){if(g(a))return c.trigger.call(this,s+"go",a,arguments[1]),this;if("string"==typeof a){var o=Array.prototype.slice.apply(arguments);switch(o[0]=s+o[0],a){case"previous":case"next":case"go":case"disable":case"enable":case"refresh":case"show":case"hide":case"destroy":c.trigger.apply(this,o);break;case"getSelectedPageNum":case"getCurrentPageNum":return(c.data("pagination").model?c.data("pagination").model:c.data("pagination").attributes).pageNumber;case"getTotalPage":return Math.ceil(c.data("pagination").model.totalNumber/c.data("pagination").model.pageSize);case"getSelectedPageData":case"getCurrentPageData":return c.data("pagination").currentPageData;case"isDisabled":return!0===c.data("pagination").model.disabled;default:l("Unknown action: "+a)}return this}t=c,u.each(["go","previous","next","disable","enable","refresh","show","hide","destroy"],function(a,e){t.off(s+e)}),t.data("pagination",{}),u(".paginationjs",t).remove()}else D.isObject(a)||l("Illegal options");var i=J;i.dataSource||l('"dataSource" is required.'),"string"==typeof i.dataSource?void 0===i.totalNumberLocator?void 0===i.totalNumber?l('"totalNumber" is required.'):g(i.totalNumber)||l('"totalNumber" is incorrect. Expect numberic type'):"function"!=typeof i.totalNumberLocator&&l('"totalNumberLocator" should be a Function.'):D.isObject(i.dataSource)&&(void 0===i.locator?l('"dataSource" is an Object, please specify a "locator".'):"string"!=typeof i.locator&&"function"!=typeof i.locator&&l(i.locator+" is incorrect. Expect string or function type")),void 0!==i.formatResult&&"function"!=typeof i.formatResult&&l('"formatResult" should be a Function.'),void 0!==i.onError&&"function"!=typeof i.onError&&l('"onError" should be a Function.'),e.initialize()}return this},u.fn[r].defaults={totalNumber:0,pageNumber:1,pageSize:10,pageRange:2,showPrevious:!0,showNext:!0,showPageNumbers:!0,showNavigator:!1,showGoInput:!1,showGoButton:!1,showSizeChanger:!1,sizeChangerOptions:[10,20,50,100],pageLink:"",prevText:"‹",nextText:"›",ellipsisText:"...",goButtonText:"Go",classPrefix:"paginationjs",activeClassName:"active",disableClassName:"disabled",formatNavigator:"Total <%= totalNumber %> items",formatGoInput:"<%= input %>",formatGoButton:"<%= button %>",position:"bottom",autoHidePrevious:!1,autoHideNext:!1,triggerPagingOnInit:!0,resetPageNumberOnInit:!0,hideOnlyOnePage:!1,hideFirstOnEllipsisShow:!1,hideLastOnEllipsisShow:!1,callback:function(){}},u.fn.addHook=function(a,e){arguments.length<2&&l("Expect 2 arguments at least."),"function"!=typeof e&&l("callback should be a function.");var t=u(this),o=t.data("pagination");o||(t.data("pagination",{}),o=t.data("pagination")),o.hooks||(o.hooks={}),o.hooks[a]=o.hooks[a]||[],o.hooks[a].push(e)},u[r]=function(a,e){var t;if(arguments.length<2&&l("Requires two parameters."),(t="string"!=typeof a&&a instanceof jQuery?a:u(a)).length)return t.pagination(e),t},{});function l(a){throw new Error("Pagination: "+a)}function g(a){return!isNaN(parseFloat(a))&&isFinite(a)}u.each(["Object","Array","String"],function(a,t){D["is"+t]=function(a){return("object"==(e=typeof(a=a))?null==a?"null":Object.prototype.toString.call(a).slice(8,-1):e).toLowerCase()===t.toLowerCase();var e}}),"function"==typeof define&&define.amd&&define(function(){return u})}(this,window.jQuery); -------------------------------------------------------------------------------- /docs/cn.md: -------------------------------------------------------------------------------- 1 | # Constructor 2 | 3 | ## Commonly used 4 | 5 | ### dataSource array | string | object | function 6 | 数据源,最终提供给分页组件的是一个数组 7 | 8 | 数据源支持 4 种格式 9 | 10 | 1. **Array** 11 | 12 | 直接提供一个数组,如: 13 | 14 | ``` 15 | ['1', '2', '3', '4'] 16 | ``` 17 | 18 | 2. **Object** 19 | 20 | 提供一个对象,里面要包含数组,可以通过 `locator: 'data'` 指定这个数组 21 | 22 | ``` 23 | { 24 | data: ['1', '2', '3', '4'] 25 | } 26 | ``` 27 | 28 | 3. **Function** 29 | 30 | 提供一个自定义函数,根据自己的业务逻辑返回数组,自定义程度很高,可以实现上面 2 种方式 31 | 32 | 可以动态组装数据,使用 `done` 返回数据,如: 33 | 34 | ``` 35 | dataSource: function(done){ 36 | var result = []; 37 | 38 | for(var i = 1; i < 196; i++){ 39 | result.push(i); 40 | } 41 | 42 | done(result); 43 | } 44 | ``` 45 | 46 | 也可以发送请求获取数据,使用 `done` 异步返回数据 47 | 48 | ``` 49 | dataSource: function(done){ 50 | $.ajax({ 51 | type: 'GET', 52 | url: '/test.json', 53 | success: function(response){ 54 | done(response); 55 | } 56 | }); 57 | } 58 | ``` 59 | 60 | 4. **URL** 61 | 62 | 提供一个URL,通过 Ajax 返回数据,适用于异步分页,每次请求返回一页的数据,返回的数据也可以通过 `locator` 查找 63 | 64 | 65 | 如果URL为 file, http 或 https 协议,会用 `jsonp` 发送请求,否则为 Ajax 66 | 67 | ``` 68 | /test.json 69 | ``` 70 | 71 | 每次分页发起请求时,会附加两个参数 `pageNumber` 和 `pageSize` ,也可使用 `alias` 来指定参数名 72 | 73 | ``` 74 | /test.json?pageNumber=2&pageSize=10 75 | ``` 76 | 77 | 78 | ### locator string | function 79 | 这个参数与 `dataSource` 相关,一般情况下,`dataSource` 是一个数组,可以直接传给分页组件处理。但如果返回的是 Object,那么就需要指定那个数组,默认为 `data` 80 | 81 | 指定 `locator` 可定位到数据源的位置,支持 2 种方式 82 | 83 | 1. **String** 84 | 85 | ``` 86 | { 87 | data: ['1', '2', '3', '4'] 88 | } 89 | ``` 90 | 91 | 指定 `locator: 'data'` 之后,最终传给分页组件的就是 `['1', '2', '3', '4']` 92 | 93 | 94 | 此外,还支持多层定位,如果 `dataSource` 是如下,则可用 `locator: 'a.b'` 95 | 96 | ``` 97 | { 98 | a: {b: ['1', '2', '3', '4']} 99 | } 100 | ``` 101 | 102 | 2. **Function** 103 | 104 | 提供一个自定义函数,找到数组的位置,并返回 105 | 106 | ``` 107 | locator: function(){ 108 | // find data and return 109 | return 'a.b'; 110 | } 111 | ``` 112 | 113 | 通过 Ajax 获取的数据同样会应用此规则 114 | 115 | 116 | ### totalNumber number (default `0`) 117 | 条目总数,异步分页时必填,模拟分页时为数组的长度 118 | 119 | ### totalNumberLocator function(response) 120 | 远程获取 `totalNumber`,用于异步分页,只在 `dataSource` 为字符串时可用 121 | 122 | 注意: 指定 `totalNumberLocator` 后将会忽略 `totalNumber` 123 | 124 | 查看 [demo](/index.html#totalNumber_locator) 125 | 126 | ### pageNumber number (default `1`) 127 | 指定初始化时加载哪一页的数据 128 | 129 | ### pageSize number (default `10`) 130 | 每页的条目数 131 | 132 | ### pageRange number (default `2`) 133 | 可见的页码范围,即当前页码两边的页码数量。比如当前是第 6 页,设置 pageRange 为 2,则页码条显示为 '1... 4 5 `6` 7 8' 134 | 135 | ### callback function(data, pagination) 136 | 每次翻页时的回调,`callback` 会传入两个参数 137 | 138 | ``` 139 | callback: function(data, pagination){ ... } 140 | ``` 141 | 142 | 参数 | 类型 | 描述 143 | ------------ | ------------- | ------------ 144 | data | array | 当页数据 145 | pagination | object | 包含当页配置信息的对象 146 | 147 | pagination 对象包含以下属性值: 148 | 149 | 属性 | 类型 | 描述 150 | ------------ | ------------- | ------------ 151 | pageNumber | number | 当前页码 152 | pageRange | number | 页码范围 153 | pageSize | number | 每页条目数 154 | totalNumber | number | 总条目数 155 | el | jQueryObject | 分页实例的容器 156 | direction | number | 分页方向,往前翻页时值为 -1,往后翻为 1,初始化时为 0 157 | originalResponse | object | 当数据源是一个 URL 时,每次分页请求的原始响应内容 158 | 159 | ### alias object 160 | 请求的参数别名,用于异步分页,默认为空 161 | 162 | ``` 163 | alias: { 164 | pageNumber: 'pageNum', 165 | pageSize: 'limit' 166 | } 167 | ``` 168 | 169 | 那么通过 Ajax 发起请求时,会替换默认的 `pageNumber` 和 `pageSize` 170 | 171 | ``` 172 | /test.json?pageNum=1&limit=10 173 | ``` 174 | 175 | ## Display control 176 | 177 | ### showPrevious boolean (default `true`) 178 | 是否显示 '上一页' 179 | 180 | ### showNext boolean (default `true`) 181 | 是否显示 '下一页' 182 | 183 | ### showPageNumbers boolean (default `true`) 184 | 是否显示 '页码' 185 | 186 | ### showSizeChanger boolean (default `false`) 187 | 是否显示 pageSize 选择器 188 | 189 | 查看 [demo](/index.html#show_page_size_changer) 190 | 191 | ### sizeChangerOptions array (default `[10, 20, 50, 100]`) 192 | 指定 pageSize 的选项范围,默认是 `[10, 20, 50, 100]`. 193 | 194 | ### showNavigator boolean (default `false`) 195 | 是否显示导航器 196 | 197 | ### showGoInput boolean (default `false`) 198 | 是否显示跳转输入框 199 | 200 | ### showGoButton boolean (default `false`) 201 | 是否显示跳转按钮 202 | 203 | ### hideFirstOnEllipsisShow boolean (default `false`) 204 | 是否在有省略号时显示开始页码 205 | 206 | ``` 207 | hideFirstOnEllipsisShow: true, 208 | pageRange: 1, 209 | totalNumber: 100, 210 | pageSize: 10 211 | ``` 212 | 213 | 如上设置,分页条会显示成这样 '... 4 `5` 6 ... 10' 214 | 215 | ### hideLastOnEllipsisShow boolean (default `false`) 216 | 是否在有省略号时显示结束页码 217 | 218 | ``` 219 | hideLastOnEllipsisShow: true, 220 | pageRange: 1, 221 | totalNumber: 100, 222 | pageSize: 10 223 | ``` 224 | 225 | 如上设置,分页条会显示成这样 '1 ... 4 `5` 6 ...' 226 | 227 | ### autoHidePrevious boolean (default `false`) 228 | 是否在当前显示为第一页时隐藏 '上一页' 按钮 229 | 230 | 查看 [demo](/index.html#auto_hide) 231 | 232 | ### autoHideNext boolean (default `false`) 233 | 是否在当前显示为最后一页时隐藏 '下一页' 按钮 234 | 235 | 查看 [demo](/index.html#auto_hide) 236 | 237 | ## Style 238 | 239 | ### classPrefix string 240 | 样式前缀,默认为 `pagination` 241 | 242 | ### className string 243 | 附加给分页容器的额外样式类,默认为空 244 | 245 | ### activeClassName string 246 | 选中页码的样式类,默认为 `active` 247 | 248 | ### disableClassName string 249 | 不可用页码的样式类,默认为 `disabled` 250 | 251 | ### ulClassName string 252 | 附加给分页容器下的 'ul' 元素的样式类,默认为空 253 | 254 | ### pageClassName string 255 | 页码按钮的样式类。 256 | 257 | ### prevClassName string 258 | 上一页按钮的样式类。 259 | 260 | ### nextClassName string 261 | 下一页按钮的样式类。 262 | 263 | ## Customize 264 | 265 | ### prevText string 266 | '上一页' 的文本,默认为 `«`,即符号 « 267 | 268 | ### nextText string 269 | '下一页' 的文本,默认为 `»`,即符号 » 270 | 271 | ### ellipsisText string 272 | 省略号文本,默认为 `...` 273 | 274 | ### goButtonText string 275 | 跳转按钮文本,默认为 `Go` 276 | 277 | ### formatNavigator string | function(currentPage, totalPage, totalNumber) 278 | 导航器格式化模板,默认为 `<%= currentPage %> / <%= totalPage %>`,也可提供一个自定义函数,返回一个这样的字符串 279 | 280 | 提供 5 个模板变量 281 | 282 | - `currentPage` 当前页码 283 | - `totalPage` 总页数 284 | - `totalNumber` 总条目数 285 | - `rangeStart` 当前页的开始数 286 | - `rangeEnd` 当前页的结束数 287 | 288 | 举个例子,总共 195 条数据,每页 20 条: 289 | 290 | - `<%= rangeStart %>-<%= rangeEnd %> of <%= totalNumber %> items` => `1-20 of 195 items` 291 | - `Total <%= totalNumber %> items` => `Total 195 items` 292 | - `<%= currentPage %> / <%= totalPage %>` => `1 / 10` 293 | 294 | 查看 [demo](/index.html#format_navigator) 295 | 296 | ### formatGoInput string | function(input, currentPage, totalPage, totalNumber) 297 | 跳转输入框格式化模板,默认为 `<%= input %>`,也可提供一个自定义函数,返回一个这样的字符串 298 | 299 | `<%= input %>` 相当于 `` 的一个包装,所以,也可自定义一个输入框标签元素,只需要确保带有 `J-paginationjs-go-pagenumber` 这个class即可 300 | 301 | 提供 4 个模板变量 302 | 303 | - `input` 输入框 304 | - `currentPage` 当前页码 305 | - `totalPage` 总页数 306 | - `totalNumber` 总条目数 307 | 308 | 查看 [demo](/index.html#format_go_input) 309 | 310 | ### formatGoButton string | function(button, currentPage, totalPage, totalNumber) 311 | 跳转按钮格式化模板,默认为 `<%= button %>`,也可提供一个自定义函数,返回一个这样的字符串 312 | 313 | `<%= button %>` 相当于 ``,所以,也可自定义一个跳转按钮的标签元素,只需要确保带有 `J-paginationjs-go-button` 这个class即可 314 | 315 | 提供 4 个模板变量 316 | 317 | - `button` 按钮 318 | - `currentPage` 当前页码 319 | - `totalPage` 总页数 320 | - `totalNumber` 总条目数 321 | 322 | ### header string | function(currentPage, totalPage, totalNumber) 323 | 自定义头部内容,默认为空 324 | 325 | 提供 3 个模板变量 326 | 327 | - `currentPage` 当前页码 328 | - `totalPage` 总页数 329 | - `totalNumber` 总条目数 330 | 331 | ### footer string | function(currentPage, totalPage, totalNumber) 332 | 自定义尾部内容,默认为空 333 | 334 | 提供 3 个模板变量 335 | 336 | - `currentPage` 当前页码 337 | - `totalPage` 总页数 338 | - `totalNumber` 总条目数 339 | 340 | ### pageLink string 341 | 分页的链接,默认为空 342 | 343 | ## Utilities 344 | 345 | ### formatResult function(data) 346 | 提供一个自定义函数,处理每次分页的数组数据,在分页 `callback` 触发之前调用 347 | 348 | 可以返回一个处理后的数组,或者直接在传过来的 `data` 数组里处理 349 | 350 | 查看 [demo](/index.html#formatResult) 351 | 352 | ### formatAjaxError function(jqXHR, textStatus, errorThrown) 353 | 提供一个自定义函数,用于渲染错误信息,默认为空 354 | 355 | ``` 356 | formatAjaxError: function(jqXHR, textStatus, errorThrown){ ... } 357 | ``` 358 | 359 | ### ajax object | function 360 | 针对内置 Ajax 请求方法的参数作更加自定义的配置,参数必须与 `$.ajax` 兼容,适用于异步分页 361 | 362 | 参数 | 类型 | 描述 363 | ------------ | ------------- | ------------ 364 | type | string | 请求的方法类型,默认为 `GET` 365 | dataType | string | 数据格式,比如:`xml`,`json`,`jsonp`,或者其他 jQuery 支持的格式,默认为 `json` 366 | data | object | 默认情况下,分页请求都会被附加 `pageNumber` 和 `pageSize` 两个参数,某些情况下,可能还需要其他的参数,那么就可使用此参数解决,例如:`{ ajax: { data: {dbType: 'oracle'} } }` 367 | cache | boolean | 如果设置为 `false`,将会强制请求不被浏览器缓存,默认为 `true` 368 | async | boolean | 默认所有请求都以异步方式发送,默认为 `true`。如果需要同步方式,设置为 `false` 即可,跨域请求或 `dataType: 'jsonp'` 不支持同步操作。 369 | beforeSend | function | 发起请求之前的回调函数,可用于发送前修改 jqXHR 对象。beforeSend 函数返回 `false` 将取消该请求。 370 | pageNumberStartWithZero | boolean | 默认情况下,分页请求发送的 `pageNumber`(或者其他的别名)会从 1 开始,如果你的服务端是从 0 开始处理分页的,那么只需要设置 `pageNumberStartWithZero: true`。 371 | 372 | 参数的更多信息,请参阅 [JQuery API Documentation](http://api.jquery.com/jquery.ajax/) 373 | 374 | ### ajaxFunction function(settings) 375 | 用于自定义分页的 ajax 函数,会替换默认的 `$.ajax`,此函数接收的参数和 `$.ajax` 相同,函数内部必须调用 `settings.success(response)` 或 `settings.error(jqXHR, textStatus, errorThrown)`,错误函数的参数将传递给 `formatAjaxError` 函数(如果提供了)。这些参数与内置的 Ajax 函数提供的参数保持一致。 376 | 377 | ### triggerPagingOnInit boolean (default `true`) 378 | 是否在初始化时触发默认分页,有些情况下,你可能希望默认触发首次分页,因为你已经用AJAX加载了内容并且内容已显示 379 | 380 | 也有其他的用法,例如:默认加载第二页的数据 381 | 382 | ``` 383 | triggerPagingOnInit: true, 384 | pageNum: 2 385 | ``` 386 | 387 | ### resetPageNumberOnInit boolean (default `true`) 388 | 当 dataSource 是一个 URL,在分页初始化或重新初始化时重置页码为 `1` 389 | 390 | ### hideOnlyOnePage boolean (default `false`) 391 | 是否在只有 1 页时隐藏分页 392 | 393 | ### onError function(errorThrown, errorType) 394 | 在渲染分页发生异常时执行,此函数有 2 个参数:错误对象和错误类型,错误类型见下表。 395 | 396 | ErrorType | 描述 397 | ------------ | ------------- | ------------ 398 | ajaxSuccessHandlerError | 在执行 Ajax 的 `success` 回调函数时发生错误。 399 | 400 | # Methods 401 | 402 | 分页初始化之后,可以使用下面列出的方法来改变分页的行为 403 | 404 | ``` 405 | var container = $('#example1'); 406 | container.pagination({ ... }); 407 | 408 | container.pagination('previous'); 409 | 410 | ``` 411 | 412 | ### previous 413 | 触发上一页 414 | 415 | ### next 416 | 触发下一页 417 | 418 | ### go 419 | 跳转到指定页,有以下 2 种使用方式 420 | 421 | ``` 422 | container.pagination('go', 8) 423 | container.pagination(8) 424 | ``` 425 | 426 | 也支持自定义回调函数,例如: 427 | 428 | ``` 429 | container.pagination('go', 8, function(data, pagination){ 430 | // template method of yourself 431 | }) 432 | ``` 433 | 434 | 注意,设置自定义函数后,就不会再调用分页的回调函数 `callback` 了 435 | 436 | ### disable 437 | 禁用分页,执行后分页不可用,要重新恢复可用需要调用解锁事件 `container.pagination('enable')` 438 | 439 | 每次异步翻页发出请求前,会自动调用此方法,请求成功之后会自动调用 `enable` 解锁 440 | 441 | ### enable 442 | 解锁分页,执行后分页恢复可用 443 | 444 | ### show 445 | 显示分页 446 | 447 | ### hide 448 | 隐藏分页 449 | 450 | ### destroy 451 | 销毁分页实例 452 | 453 | ### getCurrentPageNum number 454 | 获取当前页码 455 | 456 | ### getTotalPage number 457 | 获取总页数 458 | 459 | ### getCurrentPageData array 460 | 获取当前页码的数据 461 | 462 | ### isDisabled function 463 | 当前是否正处在禁用状态 464 | 465 | # Events 466 | 467 | 分页事件的功能接口有 2 种使用方式,分别是 `回调函数` 和 `插件钩子` 468 | 469 | 使用回调函数: 470 | 471 | ``` 472 | var container = $('#example1'); 473 | container.pagination({ 474 | afterRender: function(){ 475 | // function body 476 | } 477 | }); 478 | 479 | ``` 480 | 481 | 使用插件钩子: 482 | 483 | ``` 484 | var container = $('#example2'); 485 | 486 | container.pagination({ 487 | dataSource: [1, 2, 3], 488 | pageSize: 1 489 | }); 490 | 491 | container.addHook('afterRender', function(){ 492 | // function body 493 | }); 494 | 495 | ``` 496 | 497 | 注意,钩子可以在分页初始化之前定义,也可以在初始化之后定义 498 | 499 | ### beforeInit function 500 | 分页实例初始化之前调用,返回 `false` 将阻止初始化 501 | 502 | ### beforeRender function(isForced) 503 | 每次分页时会重新渲染分页条,渲染之前调用。 504 | 505 | 如果渲染是在分页时触发,则 `isForce` 为 `true`,如果是在初始化时触发,则为 `false`。 506 | 507 | ### beforePaging function 508 | 分页之前调用 509 | 510 | ### beforeSizeSelectorChange function 511 | pageSize 改变之前调用 512 | 513 | ### beforeDestroy function 514 | 分页实例销毁之前调用 515 | 516 | ### beforeDisable function 517 | 禁用之前调用 518 | 519 | ### beforeEnable function 520 | 解锁之前调用 521 | 522 | ### beforePreviousOnClick function 523 | 点击上一页之前调用 524 | 525 | ### beforePageOnClick function 526 | 点击页码之前调用 527 | 528 | ### beforeNextOnClick function 529 | 点击下一页之前调用 530 | 531 | ### beforeGoInputOnEnter function 532 | 分页输入框回车之前调用 533 | 534 | ### beforeGoButtonOnClick function 535 | 分页跳转按钮点击之前调用 536 | 537 | 538 | ### afterInit function 539 | 分页实例初始化创建完成之后调用 540 | 541 | ### afterRender function 542 | 每次分页时会重新渲染分页条,渲染之后调用 543 | 544 | ### afterPaging function 545 | 分页之后调用 546 | 547 | ### afterSizeSelectorChange function 548 | pageSize 改变之后调用 549 | 550 | ### afterDestroy function 551 | 分页实例销毁之后调用 552 | 553 | ### afterDisable function 554 | 禁用之后调用 555 | 556 | ### afterEnable function 557 | 解锁之后调用 558 | 559 | ### afterPreviousOnClick function 560 | 点击上一页之后调用 561 | 562 | ### afterPageOnClick function 563 | 点击页码之后调用 564 | 565 | ### afterNextOnClick function 566 | 点击下一页之后调用 567 | 568 | ### afterGoInputOnEnter function 569 | 分页输入框回车之后调用 570 | 571 | ### afterGoButtonOnClick function 572 | 分页跳转按钮点击之后调用 573 | 574 | ### afterIsFirstPage function 575 | 当前是第一页时调用 576 | 577 | ### afterIsLastPage function 578 | 当前是最后一页时调用 579 | 580 | # Theme 581 | 分页组件自带了 5 套默认主题,但你完全可以定制你自己的主题 582 | 583 | 首先,需要在 header 标签内引用 css 文件: 584 | 585 | 586 | 587 | css & less 文件: [pagination.css](../dist/2.6.0/pagination.css) [pagination.less](../dist/2.6.0/pagination.less) 588 | 589 | 例如蓝色主题,可以这样使用: 590 | 591 | ``` 592 | className: 'paginationjs-theme-blue' 593 | ``` 594 | 595 | 小号蓝色主题: 596 | 597 | ``` 598 | className: 'paginationjs-theme-blue paginationjs-small' 599 | ``` 600 | 601 | 大号蓝色主题: 602 | 603 | ``` 604 | className: 'paginationjs-theme-blue paginationjs-big' 605 | ``` 606 | 607 | 如果需要完全地自定义样式,则可以增加 css 类 `custom-paginationjs` 608 | 609 | # Configuring Defaults 610 | 分页可通过 `$.fn.pagination.defaults` 对象来修改默认配置,修改后,将影响所有之后创建的实例 611 | 612 | 例如: 613 | 614 | ``` 615 | $.extend($.fn.pagination.defaults, { 616 | pageSize: 20 617 | }) 618 | ``` 619 | 之后所有新建的分页实例,每页条数都是 20 620 | 621 | --- 622 | 623 | [帮助改进这些文档,新建一个 issue 或 pull request](https://github.com/superRaytin/paginationjs-site/issues) -------------------------------------------------------------------------------- /docs/en.md: -------------------------------------------------------------------------------- 1 | # Constructor 2 | 3 | ## Commonly used 4 | 5 | ### dataSource array | string | object | function 6 | 7 | Provides data items directly. 8 | 9 | `dataSource` can be one of the following 4 formats. 10 | 11 | 1. **Array** 12 | 13 | all the data items, eg: 14 | 15 | ``` 16 | ['1', '2', '3', '4'] 17 | ``` 18 | 19 | 2. **Object** 20 | 21 | an object that contained all the data items, meanwhile, you should specify the array via `locator: 'data'`. 22 | 23 | ``` 24 | { 25 | data: ['1', '2', '3', '4'] 26 | } 27 | ``` 28 | 29 | 3. **Function** 30 | 31 | a function that should indicate the array data via `done` function. 32 | 33 | ``` 34 | dataSource: function(done){ 35 | var result = []; 36 | 37 | for(var i = 1; i < 196; i++){ 38 | result.push(i); 39 | } 40 | 41 | done(result); 42 | } 43 | ``` 44 | 45 | You can also send a request to get your data, and then call `done` to return the array data. 46 | 47 | ``` 48 | dataSource: function(done){ 49 | $.ajax({ 50 | type: 'GET', 51 | url: '/test.json', 52 | success: function(response){ 53 | done(response); 54 | } 55 | }); 56 | } 57 | ``` 58 | 59 | 4. **URL** 60 | 61 | Query data items for each paging from a remote server via Ajax. 62 | 63 | Usually you will use it with a `locator` to specify the location of the array containing data items within the response. The full response of the Ajax request is available as the `originalResponse` property of the `pagination` object passed to `callback`. 64 | 65 | 66 | ``` 67 | /test.json 68 | ``` 69 | 70 | For each pagination request, these two parameters `pageNumber` `pageSize` will be appended to the request url. You can customize their names via `alias`. 71 | 72 | ``` 73 | /test.json?pageNumber=2&pageSize=10 74 | ``` 75 | 76 | 77 | ### locator string | function (default `data`) 78 | When the data source is not an array type, this option is used to indicate the position of the array in the data source. 79 | 80 | Using as a string: 81 | 82 | `locator: 'data'`: 83 | 84 | ```js 85 | { 86 | data: ['1', '2', '3', '4'] 87 | } 88 | ``` 89 | 90 | locator uses [to-function](https://github.com/component/to-function), so you can use dot notation to traverse the result array, such as `locator: 'a.b'`: 91 | 92 | ```js 93 | { 94 | a: {b: ['1', '2', '3', '4']} 95 | } 96 | ``` 97 | 98 | Using as a function: 99 | 100 | Provides a custom function to find the position of the array data. 101 | 102 | ```js 103 | locator: function(){ 104 | // Find the position of the array and return 105 | return 'a.b'; 106 | } 107 | ``` 108 | 109 | The data got via Ajax also follow this rule. 110 | 111 | ### totalNumber number (default `0`) 112 | 113 | When the dataSource is an URL, you should pass a `totalNumber` to specify the total number of data items (or via `totalNumberLocator`). OtherWise, it will not take effect as total number will be calculated automatically. 114 | 115 | ### totalNumberLocator function(response) 116 | Useful when the dataSource is an URL, and you expect specifies one of the field value in the request's response as the `totalNumber`. 117 | 118 | Note: Pagination will ignore `totalNumber` option when `totalNumberLocator` specified. 119 | 120 | See [demo](/index.html#totalNumber_locator) 121 | 122 | ### pageNumber number (default `1`) 123 | Default page number at initialization. 124 | 125 | ### pageSize number (default `10`) 126 | Number of data items per page. 127 | 128 | ### pageRange number (default `2`) 129 | `pageRange` defines a range of pages that should be display around current page. For example, if current page number is `6` and `pageRange` is set to 2, then pagination bar will be displayed as like this '1 ... 4 5`6`7 8 ... 11 12'. 130 | 131 | If you want to show all pages, just set it to `null`. 132 | 133 | ### callback function(data, pagination) 134 | Used to customize item's innerHTML, will be invoked on each paging. 135 | 136 | To make it easier to maintain, you'd better to use templating engine such as [Handlebars](http://handlebarsjs.com/) and [Undercore.template](http://underscorejs.org/#template). 137 | 138 | it takes the resulting data and page number and pageSize as its arguments: 139 | 140 | ```js 141 | callback: function(data, pagination){ ... } 142 | ``` 143 | 144 | Parameter | Type | Description 145 | ------------ | ------------- | ------------ 146 | data | array | item data of current page 147 | pagination | object | pagination data 148 | 149 | `pagination` object contains the following props: 150 | 151 | Property | Type | Description 152 | ------------ | ------------- | ------------ 153 | pageNumber | number | Current page number 154 | pageRange | number | Current page range 155 | pageSize | number | Number of data items per page 156 | totalPage | number | Total page 157 | totalNumber | number | Total number of data items 158 | el | jQuery object | Pagination container element 159 | direction | number | Pagination direction, `-1` means forward, `1` means backward, `0` means current is at initialization. 160 | originalResponse | object | Original response of the request sent by `$.ajax()` when the `dataSource` is an URL. 161 | 162 | ### alias object 163 | Used to customize the name of `pageNumber` and `pageSize` when querying data items of the current page from remote server via Ajax. 164 | 165 | For example: 166 | 167 | ```js 168 | alias: { 169 | pageNumber: 'pageNum', 170 | pageSize: 'limit' 171 | } 172 | ``` 173 | 174 | The Ajax request will be sent with the new query names: 175 | 176 | 177 | /test.json?pageNum=1&limit=10 178 | 179 | ## Display control 180 | 181 | ### showPrevious boolean (default `true`) 182 | Display the `previous` button. 183 | 184 | ### showNext boolean (default `true`) 185 | Display the `next` button. 186 | 187 | ### showPageNumbers boolean (default `true`) 188 | Display page number buttons. 189 | 190 | ### showSizeChanger boolean (default `false`) 191 | Display size changer. 192 | 193 | See [demo](/index.html#show_page_size_changer) 194 | 195 | ### sizeChangerOptions array (default `[10, 20, 50, 100]`) 196 | Specifies options for the size selector. Default is `[10, 20, 50, 100]`. 197 | 198 | ### showNavigator boolean (default `false`) 199 | Display the navigator. 200 | 201 | ### showGoInput boolean (default `false`) 202 | Display the 'Go' input box. 203 | 204 | ### showGoButton boolean (default `false`) 205 | Display the 'Go' button. 206 | 207 | ### hideFirstOnEllipsisShow boolean (default `false`) 208 | To hide the first page number button when ellipsis showed. 209 | 210 | ``` 211 | hideFirstOnEllipsisShow: true, 212 | pageRange: 1, 213 | totalNumber: 100, 214 | pageSize: 10 215 | ``` 216 | 217 | Follow the settings above, the pagination bar will be "... 4 `5` 6 ... 10". 218 | 219 | ### hideLastOnEllipsisShow boolean (default `false`) 220 | To hide the last page number when ellipsis showed. 221 | 222 | ``` 223 | hideLastOnEllipsisShow: true, 224 | pageRange: 1, 225 | totalNumber: 100, 226 | pageSize: 10 227 | ``` 228 | 229 | Follow the settings above, the pagination bar will be "1 ... 4 `5` 6 ...". 230 | 231 | ### autoHidePrevious boolean (default `false`) 232 | To hide the `previous` button when current page number is the first. 233 | 234 | See [demo](/index.html#auto_hide) 235 | 236 | ### autoHideNext boolean (default `false`) 237 | To hide the `next` button when current page number is the last. 238 | 239 | See [demo](/index.html#auto_hide) 240 | 241 | ## Style 242 | 243 | ### classPrefix string 244 | Prefixes class name of pagination elements. Default is `paginationjs`. 245 | 246 | ### className string 247 | Additional css class(es) for the root pagination element. 248 | 249 | ### activeClassName string 250 | CSS class(es) for the active button. Default is `active`. 251 | 252 | ### disableClassName string 253 | CSS class(es) for the disabled buttons. Default is `disabled`. 254 | 255 | ### ulClassName string 256 | CSS class(es) for the inner "ul" element. 257 | 258 | ### pageClassName string 259 | CSS class(es) for the page buttons. 260 | 261 | ### prevClassName string 262 | CSS class(es) for the "Previous" button. 263 | 264 | ### nextClassName string 265 | CSS class(es) for the "Next" button. 266 | 267 | ## Customizable text 268 | 269 | ### prevText string 270 | Custom label for the `Previous` button. Default is `«`. Which is the symbol '«'. 271 | 272 | ### nextText string 273 | Custom label for the `Next` button. Default is `»`. Which is the symbol '»'. 274 | 275 | ### ellipsisText string 276 | Custom label for the ellipsis button. Default is `...`. 277 | 278 | ### goButtonText string 279 | Custom label for the `Go` button. Default is `Go`. 280 | 281 | ### formatNavigator string | function(currentPage, totalPage, totalNumber) 282 | Formats the navigator according to the specified variables. Accepts a `string` or a `function` that return those strings. Default is `<%= currentPage %> / <%= totalPage %>`. 283 | 284 | The following are the available template variables: 285 | 286 | - `currentPage` Current page number. 287 | - `totalPage` Total pages. 288 | - `totalNumber` Total number of data items. 289 | - `rangeStart` Range start of current page. 290 | - `rangeEnd` Range end of current page. 291 | 292 | For example, total 195 data items and 20 items per page: 293 | 294 | - `<%= rangeStart %>-<%= rangeEnd %> of <%= totalNumber %> items` => `1-20 of 195 items` 295 | - `Total <%= totalNumber %> items` => `Total 195 items` 296 | - `<%= currentPage %> / <%= totalPage %>` => `1 / 10` 297 | 298 | See [demo](/index.html#format_navigator) 299 | 300 | ### formatGoInput string | function(input, currentPage, totalPage, totalNumber) 301 | Formats the `Go` input according to the specified variables. Accepts a `string` or a `function` that return those strings. Default is `<%= input %>`. 302 | 303 | `<%= input %>` is equivalent to ``, therefore, you can also customize an input element yourself, just ensure that the class name of the input contains `J-paginationjs-go-pagenumber`. 304 | 305 | The following are the available template variables: 306 | 307 | - `input` 308 | - `currentPage` 309 | - `totalPage` 310 | - `totalNumber` 311 | 312 | See [demo](/index.html#format_go_input) 313 | 314 | ### formatGoButton string | function(button, currentPage, totalPage, totalNumber) 315 | Formats the `Go` button according to the specified variables. Accepts a `string` or a `function` that return those strings. Default is `<%= button %>`. 316 | 317 | `<%= button %>` is equivalent to ``, therefore, you can also customize an button element yourself, just ensure that the class name of the button contains `J-paginationjs-go-button`. 318 | 319 | The following are the available template variables: 320 | 321 | - `button` 322 | - `currentPage` 323 | - `totalPage` 324 | - `totalNumber` 325 | 326 | ### header string | function(currentPage, totalPage, totalNumber) 327 | Prepend extra contents to the pagination buttons. Accepts a `string` or a `function` that will return the extra contents. 328 | 329 | The following are the available template variables: 330 | 331 | - `currentPage` 332 | - `totalPage` 333 | - `totalNumber` 334 | 335 | ### footer string | function(currentPage, totalPage, totalNumber) 336 | Append extra contents to the pagination buttons. Accepts a `string` or a `function` that will return the extra contents. 337 | 338 | The following are the available template variables: 339 | 340 | - `currentPage` 341 | - `totalPage` 342 | - `totalNumber` 343 | 344 | ## Utilities 345 | 346 | ### formatResult function(data) 347 | Formats the data items of current page before `callback` invoked. 348 | 349 | In this function, you should return a result array, you also can process the original `data` directly. 350 | 351 | See [demo](/index.html#formatResult) 352 | 353 | ### formatAjaxError function(jqXHR, textStatus, errorThrown) 354 | 355 | A function to be called if the dataSource is an URL and request fails. 356 | 357 | ``` 358 | formatAjaxError: function(jqXHR, textStatus, errorThrown){ ... } 359 | ``` 360 | 361 | For more info on the parameters, refer to the [JQuery API Documentation](https://api.jquery.com/jquery.ajax/). 362 | 363 | ### ajax object | function 364 | Used to customize configuration for the built-in Ajax function. it must be parameter-compatible with `$.ajax`. Useful when you want to fetch data items from a remote server. 365 | 366 | Parameter | Type | Description 367 | ------------ | ------------- | ------------ 368 | type | string | The type of request to make (e.g. "POST", "GET", "PUT"); Default is `GET`. 369 | dataType | string | Data type for the request. `xml`, `json`, `jsonp`, other formats supported by jQuery. Default is `json`. 370 | data | object | By default, `pageNumber` and `pageSize` will be sent. If you need additional data to be sent to the server. set this option. For example: `{ ajax: { data: {dbType: 'oracle'} } }`. 371 | cache | boolean | If set to `false`, it will force requested pages not to be cached by the browser. Default is `true`. 372 | async | boolean | By default, all requests are sent asynchronously. If you need synchronous requests, set this option to `false`. Default is `true`. 373 | beforeSend | function | A pre-request callback function that can be used to modify the jqXHR object before it is sent. Returning false in the beforeSend function will cancel the request. 374 | pageNumberStartWithZero | boolean | By default, the passed `pageNumber`(or a alias if specified) will be `1`. If your backend indexes pages starting with zero rather than 1, just set `pageNumberStartWithZero: true`. 375 | 376 | For more info on the parameters, refer to the [JQuery API Documentation](https://api.jquery.com/jquery.ajax/). 377 | 378 | ### ajaxFunction function(settings) 379 | A function to use as a replacement for `$.ajax()`. This function will be called with a single object parameter containing the same parameters as $.ajax(). Use this to implement a custom ajax function for pagination. The provided function must call either `settings.success(response)` where `response` is the returned data array or `settings.error(jqXHR, textStatus, errorThrown)`. The parameters for the error function are passed to the `formatAjaxError` function if one is provided. These are the same parameters provided by the built-in Ajax function. 380 | 381 | ### triggerPagingOnInit boolean (default `true`) 382 | Determines whether to trigger the default pagination at initialization. 383 | 384 | If you have already set innerHTML for the first page before Pagination initialization, you can set this option to `false` to prevent unnecessary paging once. 385 | 386 | ### resetPageNumberOnInit boolean (default `true`) 387 | Reset page number to `1` when Pagination initialized/reinitialized and dataSource is an URL. 388 | 389 | ### hideOnlyOnePage boolean (default `false`) 390 | Determines whether to hide pagination when there is only one page. 391 | 392 | ### onError function(errorThrown, errorType) 393 | A function to be called if error thrown when rendering pagination. The function gets passed two arguments: The error object and the error type. 394 | 395 | ErrorType | Description 396 | ------------ | ------------- | ------------ 397 | ajaxSuccessHandlerError | error occurred while executing the `success` callback of Ajax. 398 | 399 | 400 | # Methods 401 | After Pagination intialized, you can change the behavior of the `.pagination` through the following supported methods. 402 | 403 | ```js 404 | var container = $('#example1'); 405 | container.pagination({ ... }); 406 | 407 | container.pagination('previous'); 408 | ``` 409 | 410 | ### previous 411 | Go to the previous page. 412 | 413 | ### next 414 | Go to the next page. 415 | 416 | ### go 417 | Go to the custom page. There is 2 ways: 418 | 419 | ```js 420 | container.pagination('go', 8) 421 | container.pagination(8) 422 | ``` 423 | 424 | you can also provide a callback to customize item's innerHTML of the target page. For example: 425 | 426 | ```js 427 | container.pagination('go', 8, function(data, pagination){ 428 | // template method of yourself 429 | }) 430 | ``` 431 | 432 | Follow the code above, Pagination will use your callback function instead of the default `callback` function on this paging. 433 | 434 | ### disable 435 | To disable the pagination. 436 | 437 | Note: If the dataSource is an URL, Pagination will be automatically set to disabled before sending the request, and `enable` will be automatically invoked after the request completed. 438 | 439 | ### enable 440 | To enable the pagination. 441 | 442 | ### show 443 | To display the pagination. 444 | 445 | ### hide 446 | To hide the pagination. 447 | 448 | ### destroy 449 | To destroy the pagination. 450 | 451 | ### getCurrentPageNum number 452 | Get current page number. 453 | 454 | ### getTotalPage number 455 | Get total page. 456 | 457 | ### getCurrentPageData array 458 | Get data items of current page. 459 | 460 | ### isDisabled function 461 | Whether pagination has been disabled. 462 | 463 | 464 | # Events 465 | Pagination allows you to register all events for the lifetime of a paging behavior. 466 | 467 | There are 2 ways: as callbacks or as plugin hooks. 468 | 469 | Register events as callbacks: 470 | 471 | ```js 472 | var container = $('#example1'); 473 | container.pagination({ 474 | afterRender: function(){ 475 | // function body 476 | } 477 | }); 478 | ``` 479 | 480 | Register events as plugin hooks: 481 | 482 | ```js 483 | var container = $('#example2'); 484 | 485 | container.pagination({ 486 | dataSource: [1, 2, 3], 487 | pageSize: 1 488 | }); 489 | 490 | container.addHook('afterRender', function(){ 491 | // function body 492 | }); 493 | ``` 494 | 495 | In this way, the hook can be added before Pagination initialized. 496 | 497 | ### beforeInit function 498 | Fired before Pagination instance initialized. Return `false` will stop the initialization. 499 | 500 | ### beforeRender function(isForced) 501 | Fired before Pagination bar rendering. Parameters: 502 | 503 | `isForced` is `true` if the rendering is triggered on paging and `false` if it is triggered at initialization. 504 | 505 | ### beforePaging function 506 | Fired before paging. 507 | 508 | ### beforeSizeSelectorChange function 509 | Fired before the size selector changed. 510 | 511 | ### beforeDestroy function 512 | Fired before pagination destroyed. 513 | 514 | ### beforeDisable function 515 | Fired before pagination disabled. 516 | 517 | ### beforeEnable function 518 | Fired before pagination enabled. 519 | 520 | ### beforePreviousOnClick function 521 | Fired before the 'previous' button clicked. 522 | 523 | ### beforePageOnClick function 524 | Fired before page button clicked. 525 | 526 | ### beforeNextOnClick function 527 | Fired before the 'next' button clicked. 528 | 529 | ### beforeGoInputOnEnter function 530 | Fired before `Enter` pressed on the 'Go' input. 531 | 532 | ### beforeGoButtonOnClick function 533 | Fired before the 'Go' button clicked. 534 | 535 | ### afterInit function 536 | Fired after Pagination initialized. 537 | 538 | ### afterRender function 539 | Fired after Pagination bar rendered. Parameters: 540 | 541 | `isForced` is `true` if the rendering is triggered on paging and `false` if it is triggered at initialization. 542 | 543 | ### afterPaging function 544 | Fired after paging. 545 | 546 | ### afterSizeSelectorChange function 547 | Fired after the size selector changed. 548 | 549 | ### afterDestroy function 550 | Fired after pagination destroyed. 551 | 552 | ### afterDisable function 553 | Fired after pagination disabled. 554 | 555 | ### afterEnable function 556 | Fired after pagination enabled. 557 | 558 | ### afterPreviousOnClick function 559 | Fired after the 'previous' button clicked. 560 | 561 | ### afterPageOnClick function 562 | Fired after page button clicked. 563 | 564 | ### afterNextOnClick function 565 | Fired after the 'next' button clicked. 566 | 567 | ### afterGoInputOnEnter function 568 | Fired after `Enter` pressed on the 'Go' input. 569 | 570 | ### afterGoButtonOnClick function 571 | Fired after the 'Go' button clicked. 572 | 573 | ### afterIsFirstPage function 574 | Fired after current page number is the first. 575 | 576 | ### afterIsLastPage function 577 | Fired after current page number is the last. 578 | 579 | # Theme 580 | 581 | Pagination comes with 5 sets of default themes, but you can fully customize your own theme. 582 | 583 | First, you should link the css file in the header tag of HTML: 584 | 585 | 586 | 587 | css & less file: [pagination.css](../dist/2.6.0/pagination.css) [pagination.less](../dist/2.6.0/pagination.less) 588 | 589 | For example, the blue theme: 590 | 591 | ``` 592 | className: 'paginationjs-theme-blue' 593 | ``` 594 | 595 | small & blue: 596 | 597 | ``` 598 | className: 'paginationjs-theme-blue paginationjs-small' 599 | ``` 600 | 601 | big & blue: 602 | 603 | ``` 604 | className: 'paginationjs-theme-blue paginationjs-big' 605 | ``` 606 | 607 | If you want to fully customize the style, you can add `custom-paginationjs` to the `className` option. 608 | 609 | # Configuring Defaults 610 | Pagination.js exposes its default options via the `$.fn.pagination.defaults` object. Properties changed in this object (same properties configurable through the constructor) will take effect for every instance created after the change. 611 | 612 | For example: 613 | 614 | ```js 615 | $.extend($.fn.pagination.defaults, { 616 | pageSize: 20 617 | }) 618 | ``` 619 | 620 | After the change, all the new pagination instances's `pageSize` will be set to 20. 621 | 622 | --- 623 | 624 | [Help improve these docs. Open an issue or pull request.](https://github.com/superRaytin/paginationjs-site/issues) -------------------------------------------------------------------------------- /examples/images/paginationjs_record.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superRaytin/paginationjs/d64b08c8d6e9ba0b5092f6d41ac62bcd1752f89f/examples/images/paginationjs_record.gif -------------------------------------------------------------------------------- /examples/pagination.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Paginationjs example 5 | 6 | 7 | 33 | 34 | 35 | 36 |
    37 |
    38 |
    39 |
    40 |
    41 |
    42 |
    43 |
    44 |
    45 |
    46 | 47 | 48 | 49 | 173 | 174 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "paginationjs", 3 | "version": "2.6.0", 4 | "description": "A jQuery plugin to provide simple yet fully customisable pagination", 5 | "main": "dist/pagination.min.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "build": "grunt", 11 | "postpublish": "PACKAGE_VERSION=$(cat package.json | grep \\\"version\\\" | head -1 | awk -F: '{ print $2 }' | sed 's/[\",]//g' | tr -d '[[:space:]]') && git tag $PACKAGE_VERSION && git push --tags", 12 | "test": "echo \"Error: no test specified\" && exit 1" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/superRaytin/paginationjs" 17 | }, 18 | "keywords": [ 19 | "paginationjs", 20 | "pagination.js", 21 | "pagination", 22 | "jquery.pagination", 23 | "jquery pagination" 24 | ], 25 | "files": [ 26 | "dist" 27 | ], 28 | "author": "superRaytin", 29 | "license": "MIT", 30 | "bugs": { 31 | "url": "https://github.com/superRaytin/paginationjs/issues" 32 | }, 33 | "homepage": "http://pagination.js.org", 34 | "devDependencies": { 35 | "grunt": "~0.4.5", 36 | "grunt-contrib-uglify": "~5.2.2", 37 | "grunt-contrib-copy": "~0.8.2", 38 | "grunt-contrib-less": "~1.0.1", 39 | "grunt-contrib-cssmin": "~0.14.0" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/pagination.js: -------------------------------------------------------------------------------- 1 | /* 2 | * pagination.js 2.6.0 3 | * A jQuery plugin to provide simple yet fully customisable pagination. 4 | * https://github.com/superRaytin/paginationjs 5 | * 6 | * Homepage: http://pagination.js.org 7 | * 8 | * Copyright 2014-2100, superRaytin 9 | * Released under the MIT license. 10 | */ 11 | 12 | (function(global, $) { 13 | 14 | if (typeof $ === 'undefined') { 15 | throwError('Pagination requires jQuery.'); 16 | } 17 | 18 | var pluginName = 'pagination'; 19 | 20 | var pluginHookMethod = 'addHook'; 21 | 22 | var eventPrefix = '__pagination-'; 23 | 24 | if ($.fn.pagination) { 25 | throwError('plugin conflicted, the name "pagination" has been taken by another jQuery plugin.'); 26 | } 27 | 28 | $.fn[pluginName] = function(options) { 29 | 30 | if (typeof options === 'undefined') { 31 | return this; 32 | } 33 | 34 | var container = $(this); 35 | 36 | var attributes = $.extend({}, $.fn[pluginName].defaults, options); 37 | 38 | var pagination = { 39 | 40 | initialize: function() { 41 | var self = this; 42 | 43 | // Cache data for current instance 44 | if (!container.data('pagination')) { 45 | container.data('pagination', {}); 46 | } 47 | 48 | if (self.callHook('beforeInit') === false) return; 49 | 50 | // Pagination has been initialized, destroy it 51 | if (container.data('pagination').initialized) { 52 | $('.paginationjs', container).remove(); 53 | } 54 | 55 | // Whether to disable Pagination at the initialization 56 | self.disabled = !!attributes.disabled; 57 | 58 | // Model will be passed to the callback function 59 | var model = self.model = { 60 | pageRange: attributes.pageRange, 61 | pageSize: attributes.pageSize 62 | }; 63 | 64 | // Parse dataSource to find available paging data 65 | self.parseDataSource(attributes.dataSource, function(dataSource) { 66 | 67 | // Asynchronous mode 68 | self.isAsync = Helpers.isString(dataSource); 69 | if (Helpers.isArray(dataSource)) { 70 | model.totalNumber = attributes.totalNumber = dataSource.length; 71 | } 72 | 73 | // Asynchronous mode and a 'totalNumberLocator' has been specified 74 | self.isDynamicTotalNumber = self.isAsync && attributes.totalNumberLocator; 75 | 76 | var el = self.render(true); 77 | 78 | // Add extra className to the pagination element 79 | if (attributes.className) { 80 | el.addClass(attributes.className); 81 | } 82 | 83 | model.el = el; 84 | 85 | // Append / prepend pagination element to the container 86 | container[attributes.position === 'bottom' ? 'append' : 'prepend'](el); 87 | 88 | // Bind events 89 | self.observer(); 90 | 91 | // Mark pagination has been initialized 92 | container.data('pagination').initialized = true; 93 | 94 | // Call hook after initialization 95 | self.callHook('afterInit', el); 96 | }); 97 | }, 98 | 99 | render: function(isBoot) { 100 | var self = this; 101 | var model = self.model; 102 | var el = model.el || $('
    '); 103 | var isForced = isBoot !== true; 104 | 105 | self.callHook('beforeRender', isForced); 106 | 107 | var currentPage = model.pageNumber || attributes.pageNumber; 108 | var pageRange = attributes.pageRange || 0; 109 | var totalPage = self.getTotalPage(); 110 | 111 | var rangeStart = currentPage - pageRange; 112 | var rangeEnd = currentPage + pageRange; 113 | 114 | if (rangeEnd > totalPage) { 115 | rangeEnd = totalPage; 116 | rangeStart = totalPage - pageRange * 2; 117 | rangeStart = rangeStart < 1 ? 1 : rangeStart; 118 | } 119 | 120 | if (rangeStart <= 1) { 121 | rangeStart = 1; 122 | rangeEnd = Math.min(pageRange * 2 + 1, totalPage); 123 | } 124 | 125 | el.html(self.generateHTML({ 126 | currentPage: currentPage, 127 | pageRange: pageRange, 128 | rangeStart: rangeStart, 129 | rangeEnd: rangeEnd 130 | })); 131 | 132 | // Whether to hide pagination when there is only one page 133 | if (attributes.hideOnlyOnePage) { 134 | el[totalPage <= 1 ? 'hide' : 'show'](); 135 | } 136 | 137 | self.callHook('afterRender', isForced); 138 | 139 | return el; 140 | }, 141 | 142 | getPageLinkTag: function(index) { 143 | var pageLink = attributes.pageLink; 144 | return pageLink ? `${index}` : `${index}`; 145 | }, 146 | 147 | // Generate HTML for page numbers 148 | generatePageNumbersHTML: function(args) { 149 | var self = this; 150 | var currentPage = args.currentPage; 151 | var totalPage = self.getTotalPage(); 152 | var getPageLinkTag = self.getPageLinkTag; 153 | var rangeStart = args.rangeStart; 154 | var rangeEnd = args.rangeEnd; 155 | var html = ''; 156 | var i; 157 | 158 | var ellipsisText = attributes.ellipsisText; 159 | 160 | var classPrefix = attributes.classPrefix; 161 | var pageClassName = attributes.pageClassName || ''; 162 | var activeClassName = attributes.activeClassName || ''; 163 | var disableClassName = attributes.disableClassName || ''; 164 | 165 | // Display all page numbers if page range disabled 166 | if (attributes.pageRange === null) { 167 | for (i = 1; i <= totalPage; i++) { 168 | if (i == currentPage) { 169 | html += `
  • ${i}
  • `; 170 | } else { 171 | html += `
  • ${getPageLinkTag(i)}
  • `; 172 | } 173 | } 174 | return html; 175 | } 176 | 177 | if (rangeStart <= 3) { 178 | for (i = 1; i < rangeStart; i++) { 179 | if (i == currentPage) { 180 | html += `
  • ${i}
  • `; 181 | } else { 182 | html += `
  • ${getPageLinkTag(i)}
  • `; 183 | } 184 | } 185 | } else { 186 | if (!attributes.hideFirstOnEllipsisShow) { 187 | html += `
  • ${getPageLinkTag(1)}
  • `; 188 | } 189 | html += `
  • ${ellipsisText}
  • `; 190 | } 191 | 192 | for (i = rangeStart; i <= rangeEnd; i++) { 193 | if (i == currentPage) { 194 | html += `
  • ${i}
  • `; 195 | } else { 196 | html += `
  • ${getPageLinkTag(i)}
  • `; 197 | } 198 | } 199 | 200 | if (rangeEnd >= totalPage - 2) { 201 | for (i = rangeEnd + 1; i <= totalPage; i++) { 202 | html += `
  • ${getPageLinkTag(i)}
  • `; 203 | } 204 | } else { 205 | html += `
  • ${ellipsisText}
  • `; 206 | 207 | if (!attributes.hideLastOnEllipsisShow) { 208 | html += `
  • ${getPageLinkTag(totalPage)}
  • `; 209 | } 210 | } 211 | 212 | return html; 213 | }, 214 | 215 | // Generate HTML content 216 | generateHTML: function(args) { 217 | var self = this; 218 | var currentPage = args.currentPage; 219 | var totalPage = self.getTotalPage(); 220 | var getPageLinkTag = self.getPageLinkTag; 221 | 222 | var totalNumber = self.getTotalNumber(); 223 | 224 | var pageSize = attributes.pageSize; 225 | var showPrevious = attributes.showPrevious; 226 | var showNext = attributes.showNext; 227 | var showPageNumbers = attributes.showPageNumbers; 228 | var showNavigator = attributes.showNavigator; 229 | var showSizeChanger = attributes.showSizeChanger; 230 | var sizeChangerOptions = attributes.sizeChangerOptions; 231 | var showGoInput = attributes.showGoInput; 232 | var showGoButton = attributes.showGoButton; 233 | 234 | var prevText = attributes.prevText; 235 | var nextText = attributes.nextText; 236 | var goButtonText = attributes.goButtonText; 237 | 238 | var classPrefix = attributes.classPrefix; 239 | var disableClassName = attributes.disableClassName || ''; 240 | var ulClassName = attributes.ulClassName || ''; 241 | var prevClassName = attributes.prevClassName || ''; 242 | var nextClassName = attributes.nextClassName || ''; 243 | 244 | var html = ''; 245 | var sizeSelect = `'; 247 | var goButton = ``; 248 | var formattedString; 249 | 250 | var formatSizeChanger = typeof attributes.formatSizeChanger === 'function' ? attributes.formatSizeChanger(currentPage, totalPage, totalNumber) : attributes.formatSizeChanger; 251 | var formatNavigator = typeof attributes.formatNavigator === 'function' ? attributes.formatNavigator(currentPage, totalPage, totalNumber) : attributes.formatNavigator; 252 | var formatGoInput = typeof attributes.formatGoInput === 'function' ? attributes.formatGoInput(goInput, currentPage, totalPage, totalNumber) : attributes.formatGoInput; 253 | var formatGoButton = typeof attributes.formatGoButton === 'function' ? attributes.formatGoButton(goButton, currentPage, totalPage, totalNumber) : attributes.formatGoButton; 254 | 255 | var autoHidePrevious = typeof attributes.autoHidePrevious === 'function' ? attributes.autoHidePrevious() : attributes.autoHidePrevious; 256 | var autoHideNext = typeof attributes.autoHideNext === 'function' ? attributes.autoHideNext() : attributes.autoHideNext; 257 | 258 | var header = typeof attributes.header === 'function' ? attributes.header(currentPage, totalPage, totalNumber) : attributes.header; 259 | var footer = typeof attributes.footer === 'function' ? attributes.footer(currentPage, totalPage, totalNumber) : attributes.footer; 260 | 261 | // Prepend extra contents to the pagination buttons 262 | if (header) { 263 | formattedString = self.replaceVariables(header, { 264 | currentPage: currentPage, 265 | totalPage: totalPage, 266 | totalNumber: totalNumber 267 | }); 268 | html += formattedString; 269 | } 270 | 271 | // Whether to display navigator 272 | if (showNavigator) { 273 | if (formatNavigator) { 274 | formattedString = self.replaceVariables(formatNavigator, { 275 | currentPage: currentPage, 276 | totalPage: totalPage, 277 | totalNumber: totalNumber, 278 | rangeStart: (currentPage - 1) * pageSize + 1, 279 | rangeEnd: Math.min(currentPage * pageSize, totalNumber) 280 | }); 281 | html += `
    ${formattedString}
    `; 282 | } 283 | } 284 | 285 | if (showPrevious || showPageNumbers || showNext) { 286 | html += '
    '; 287 | 288 | if (ulClassName) { 289 | html += `
      `; 290 | } else { 291 | html += '
        '; 292 | } 293 | 294 | // Whether to display Previous button 295 | if (showPrevious) { 296 | if (currentPage <= 1) { 297 | if (!autoHidePrevious) { 298 | html += `
      • ${prevText}
      • `; 299 | } 300 | } else { 301 | html += `
      • ${getPageLinkTag(prevText)}
      • `; 302 | } 303 | } 304 | 305 | // Whether to display page numbers 306 | if (showPageNumbers) { 307 | html += self.generatePageNumbersHTML(args); 308 | } 309 | 310 | // Whether to display Next button 311 | if (showNext) { 312 | if (currentPage >= totalPage) { 313 | if (!autoHideNext) { 314 | html += `
      • ${nextText}
      • `; 315 | } 316 | } else { 317 | html += `
      • ${getPageLinkTag(nextText)}
      • `; 318 | } 319 | } 320 | html += `
    `; 321 | } 322 | 323 | if (showSizeChanger) { 324 | if (Helpers.isArray(sizeChangerOptions)) { 325 | if (sizeChangerOptions.indexOf(pageSize) === -1) { 326 | sizeChangerOptions.unshift(pageSize); 327 | sizeChangerOptions.sort((a, b) => a - b); 328 | } 329 | for (let i = 0; i < sizeChangerOptions.length; i++) { 330 | sizeSelect += ``; 331 | } 332 | sizeSelect += ``; 333 | formattedString = sizeSelect; 334 | 335 | if (formatSizeChanger) { 336 | formattedString = self.replaceVariables(formatSizeChanger, { 337 | length: sizeSelect, 338 | total: totalNumber 339 | }); 340 | } 341 | html += `
    ${formattedString}
    `; 342 | } 343 | } 344 | 345 | // Whether to display Go input 346 | if (showGoInput) { 347 | if (formatGoInput) { 348 | formattedString = self.replaceVariables(formatGoInput, { 349 | currentPage: currentPage, 350 | totalPage: totalPage, 351 | totalNumber: totalNumber, 352 | input: goInput 353 | }); 354 | html += `
    ${formattedString}
    `; 355 | } 356 | } 357 | 358 | // Whether to display Go button 359 | if (showGoButton) { 360 | if (formatGoButton) { 361 | formattedString = self.replaceVariables(formatGoButton, { 362 | currentPage: currentPage, 363 | totalPage: totalPage, 364 | totalNumber: totalNumber, 365 | button: goButton 366 | }); 367 | html += `
    ${formattedString}
    `; 368 | } 369 | } 370 | 371 | // Append extra contents to the pagination buttons 372 | if (footer) { 373 | formattedString = self.replaceVariables(footer, { 374 | currentPage: currentPage, 375 | totalPage: totalPage, 376 | totalNumber: totalNumber 377 | }); 378 | html += formattedString; 379 | } 380 | 381 | return html; 382 | }, 383 | 384 | // dataSource is a request URL and a 'totalNumberLocator' function specified 385 | // execute it to find out 'totalNumber' from the response 386 | findTotalNumberFromRemoteResponse: function(response) { 387 | var self = this; 388 | self.model.totalNumber = attributes.totalNumberLocator(response); 389 | }, 390 | 391 | // Go to the specified page 392 | go: function(number, callback) { 393 | var self = this; 394 | var model = self.model; 395 | 396 | if (self.disabled) return; 397 | 398 | var pageNumber = number; 399 | pageNumber = parseInt(pageNumber); 400 | 401 | if (!pageNumber || pageNumber < 1) return; 402 | 403 | var pageSize = attributes.pageSize; 404 | var totalNumber = self.getTotalNumber(); 405 | var totalPage = self.getTotalPage(); 406 | 407 | if (totalNumber > 0 && pageNumber > totalPage) return; 408 | 409 | // Pick paging data in synchronous mode 410 | if (!self.isAsync) { 411 | render(self.getPagingData(pageNumber)); 412 | return; 413 | } 414 | 415 | var postData = {}; 416 | var alias = attributes.alias || {}; 417 | var pageSizeName = alias.pageSize ? alias.pageSize : 'pageSize'; 418 | var pageNumberName = alias.pageNumber ? alias.pageNumber : 'pageNumber'; 419 | postData[pageSizeName] = pageSize; 420 | postData[pageNumberName] = pageNumber; 421 | 422 | var ajaxParams = typeof attributes.ajax === 'function' ? attributes.ajax() : attributes.ajax; 423 | 424 | // If the pageNumber's value starts with 0 via Ajax 425 | if (ajaxParams && ajaxParams.pageNumberStartWithZero) { 426 | postData[pageNumberName] = pageNumber - 1; 427 | } 428 | 429 | var formatAjaxParams = { 430 | type: 'get', 431 | cache: false, 432 | data: {}, 433 | contentType: 'application/x-www-form-urlencoded; charset=UTF-8', 434 | dataType: 'json', 435 | async: true 436 | }; 437 | 438 | $.extend(true, formatAjaxParams, ajaxParams); 439 | $.extend(formatAjaxParams.data, postData); 440 | 441 | formatAjaxParams.url = attributes.dataSource; 442 | formatAjaxParams.success = function(response) { 443 | try { 444 | self.model.originalResponse = response; 445 | if (self.isDynamicTotalNumber) { 446 | self.findTotalNumberFromRemoteResponse(response); 447 | } else { 448 | self.model.totalNumber = attributes.totalNumber; 449 | } 450 | 451 | var finalData = self.filterDataWithLocator(response); 452 | render(finalData); 453 | } catch (e) { 454 | if(typeof attributes.onError === 'function') { 455 | attributes.onError(e, 'ajaxSuccessHandlerError'); 456 | } else { 457 | throw e; 458 | } 459 | } 460 | }; 461 | formatAjaxParams.error = function(jqXHR, textStatus, errorThrown) { 462 | attributes.formatAjaxError && attributes.formatAjaxError(jqXHR, textStatus, errorThrown); 463 | self.enable(); 464 | }; 465 | 466 | self.disable(); 467 | 468 | if (attributes.ajaxFunction) { 469 | attributes.ajaxFunction(formatAjaxParams); 470 | } else { 471 | $.ajax(formatAjaxParams); 472 | } 473 | 474 | function render(data) { 475 | if (self.callHook('beforePaging', pageNumber) === false) return false; 476 | 477 | // Pagination direction 478 | model.direction = typeof model.pageNumber === 'undefined' ? 0 : (pageNumber > model.pageNumber ? 1 : -1); 479 | 480 | model.pageNumber = pageNumber; 481 | 482 | self.render(); 483 | 484 | if (self.disabled && self.isAsync) { 485 | // enable pagination 486 | self.enable(); 487 | } 488 | 489 | // cache model data 490 | container.data('pagination').model = model; 491 | 492 | // format result data before callback invoked 493 | if (attributes.formatResult) { 494 | var cloneData = $.extend(true, [], data); 495 | if (!Helpers.isArray(data = attributes.formatResult(cloneData))) { 496 | data = cloneData; 497 | } 498 | } 499 | 500 | container.data('pagination').currentPageData = data; 501 | 502 | self.doCallback(data, callback); 503 | 504 | self.callHook('afterPaging', pageNumber); 505 | 506 | if (pageNumber == 1) { 507 | self.callHook('afterIsFirstPage'); 508 | } else if (pageNumber == self.getTotalPage()) { 509 | self.callHook('afterIsLastPage'); 510 | } 511 | } 512 | }, 513 | 514 | doCallback: function(data, customCallback) { 515 | var self = this; 516 | var model = self.model; 517 | 518 | if (typeof customCallback === 'function') { 519 | customCallback(data, model); 520 | } else if (typeof attributes.callback === 'function') { 521 | attributes.callback(data, model); 522 | } 523 | }, 524 | 525 | destroy: function() { 526 | if (this.callHook('beforeDestroy') === false) return; 527 | 528 | this.model.el.remove(); 529 | container.off(); 530 | 531 | // Remove style element 532 | $('#paginationjs-style').remove(); 533 | 534 | this.callHook('afterDestroy'); 535 | }, 536 | 537 | previous: function(callback) { 538 | this.go(this.model.pageNumber - 1, callback); 539 | }, 540 | 541 | next: function(callback) { 542 | this.go(this.model.pageNumber + 1, callback); 543 | }, 544 | 545 | disable: function() { 546 | var self = this; 547 | var source = self.isAsync ? 'async' : 'sync'; 548 | 549 | if (self.callHook('beforeDisable', source) === false) return; 550 | 551 | self.disabled = true; 552 | self.model.disabled = true; 553 | 554 | self.callHook('afterDisable', source); 555 | }, 556 | 557 | enable: function() { 558 | var self = this; 559 | var source = self.isAsync ? 'async' : 'sync'; 560 | 561 | if (self.callHook('beforeEnable', source) === false) return; 562 | 563 | self.disabled = false; 564 | self.model.disabled = false; 565 | 566 | self.callHook('afterEnable', source); 567 | }, 568 | 569 | refresh: function(callback) { 570 | this.go(this.model.pageNumber, callback); 571 | }, 572 | 573 | show: function() { 574 | var self = this; 575 | 576 | if (self.model.el.is(':visible')) return; 577 | 578 | self.model.el.show(); 579 | }, 580 | 581 | hide: function() { 582 | var self = this; 583 | 584 | if (!self.model.el.is(':visible')) return; 585 | 586 | self.model.el.hide(); 587 | }, 588 | 589 | // Replace variables for template string 590 | replaceVariables: function(template, variables) { 591 | var formattedString; 592 | 593 | for (var key in variables) { 594 | var value = variables[key]; 595 | var regexp = new RegExp('<%=\\s*' + key + '\\s*%>', 'img'); 596 | 597 | formattedString = (formattedString || template).replace(regexp, value); 598 | } 599 | 600 | return formattedString; 601 | }, 602 | 603 | getPagingData: function(number) { 604 | var pageSize = attributes.pageSize; 605 | var dataSource = attributes.dataSource; 606 | var totalNumber = this.getTotalNumber(); 607 | 608 | var start = pageSize * (number - 1) + 1; 609 | var end = Math.min(number * pageSize, totalNumber); 610 | 611 | return dataSource.slice(start - 1, end); 612 | }, 613 | 614 | getTotalNumber: function() { 615 | return this.model.totalNumber || attributes.totalNumber || 0; 616 | }, 617 | 618 | getTotalPage: function() { 619 | return Math.ceil(this.getTotalNumber() / attributes.pageSize); 620 | }, 621 | 622 | getLocator: function(locator) { 623 | var result; 624 | 625 | if (typeof locator === 'string') { 626 | result = locator; 627 | } else if (typeof locator === 'function') { 628 | result = locator(); 629 | } else { 630 | throwError('"locator" is incorrect. Expect string or function type.'); 631 | } 632 | 633 | return result; 634 | }, 635 | 636 | // Filter data with "locator" 637 | filterDataWithLocator: function(dataSource) { 638 | var locator = this.getLocator(attributes.locator); 639 | var filteredData; 640 | 641 | // Datasource is an Object, use "locator" to locate available data 642 | if (Helpers.isObject(dataSource)) { 643 | try { 644 | $.each(locator.split('.'), function(index, item) { 645 | filteredData = (filteredData ? filteredData : dataSource)[item]; 646 | }); 647 | } 648 | catch (e) { 649 | // ignore 650 | } 651 | 652 | if (!filteredData) { 653 | throwError('dataSource.' + locator + ' is undefined.'); 654 | } else if (!Helpers.isArray(filteredData)) { 655 | throwError('dataSource.' + locator + ' should be an Array.'); 656 | } 657 | } 658 | 659 | return filteredData || dataSource; 660 | }, 661 | 662 | parseDataSource: function(dataSource, callback) { 663 | var self = this; 664 | 665 | if (Helpers.isObject(dataSource)) { 666 | callback(attributes.dataSource = self.filterDataWithLocator(dataSource)); 667 | } else if (Helpers.isArray(dataSource)) { 668 | callback(attributes.dataSource = dataSource); 669 | } else if (typeof dataSource === 'function') { 670 | attributes.dataSource(function(data) { 671 | if (!Helpers.isArray(data)) { 672 | throwError('The parameter of "done" Function should be an Array.'); 673 | } 674 | self.parseDataSource.call(self, data, callback); 675 | }); 676 | } else if (typeof dataSource === 'string') { 677 | if (/^https?|file:/.test(dataSource)) { 678 | attributes.ajaxDataType = 'jsonp'; 679 | } 680 | callback(dataSource); 681 | } else { 682 | throwError('Unexpected dataSource type'); 683 | } 684 | }, 685 | 686 | callHook: function(hook) { 687 | var paginationData = container.data('pagination') || {}; 688 | var result; 689 | 690 | var args = Array.prototype.slice.apply(arguments); 691 | args.shift(); 692 | 693 | if (attributes[hook] && typeof attributes[hook] === 'function') { 694 | if (attributes[hook].apply(global, args) === false) { 695 | result = false; 696 | } 697 | } 698 | 699 | if (paginationData.hooks && paginationData.hooks[hook]) { 700 | $.each(paginationData.hooks[hook], function(index, item) { 701 | if (item.apply(global, args) === false) { 702 | result = false; 703 | } 704 | }); 705 | } 706 | 707 | return result !== false; 708 | }, 709 | 710 | observer: function() { 711 | var self = this; 712 | var el = self.model.el; 713 | 714 | // Go to specified page number 715 | container.on(eventPrefix + 'go', function(event, pageNumber, done) { 716 | if (typeof pageNumber === 'string') { 717 | pageNumber = parseInt(pageNumber.trim()); 718 | } 719 | 720 | if (!pageNumber) return; 721 | 722 | if (typeof pageNumber !== 'number') { 723 | throwError('"pageNumber" is incorrect. (Number)'); 724 | } 725 | 726 | self.go(pageNumber, done); 727 | }); 728 | 729 | // Page number button click listener 730 | el.on('click', '.J-paginationjs-page', function(event) { 731 | var current = $(event.currentTarget); 732 | var pageNumber = current.attr('data-num').trim(); 733 | 734 | if (!pageNumber || current.hasClass(attributes.disableClassName) || current.hasClass(attributes.activeClassName)) return; 735 | 736 | if (self.callHook('beforePageOnClick', event, pageNumber) === false) return false; 737 | 738 | self.go(pageNumber); 739 | 740 | self.callHook('afterPageOnClick', event, pageNumber); 741 | 742 | if (!attributes.pageLink) return false; 743 | }); 744 | 745 | // Previous button click listener 746 | el.on('click', '.J-paginationjs-previous', function(event) { 747 | var current = $(event.currentTarget); 748 | var pageNumber = current.attr('data-num').trim(); 749 | 750 | if (!pageNumber || current.hasClass(attributes.disableClassName)) return; 751 | 752 | if (self.callHook('beforePreviousOnClick', event, pageNumber) === false) return false; 753 | 754 | self.go(pageNumber); 755 | 756 | self.callHook('afterPreviousOnClick', event, pageNumber); 757 | 758 | if (!attributes.pageLink) return false; 759 | }); 760 | 761 | // Next button click listener 762 | el.on('click', '.J-paginationjs-next', function(event) { 763 | var current = $(event.currentTarget); 764 | var pageNumber = current.attr('data-num').trim(); 765 | 766 | if (!pageNumber || current.hasClass(attributes.disableClassName)) return; 767 | 768 | if (self.callHook('beforeNextOnClick', event, pageNumber) === false) return false; 769 | 770 | self.go(pageNumber); 771 | 772 | self.callHook('afterNextOnClick', event, pageNumber); 773 | 774 | if (!attributes.pageLink) return false; 775 | }); 776 | 777 | // Go button click listener 778 | el.on('click', '.J-paginationjs-go-button', function(event) { 779 | var pageNumber = $('.J-paginationjs-go-pagenumber', el).val(); 780 | 781 | if (self.callHook('beforeGoButtonOnClick', event, pageNumber) === false) return false; 782 | 783 | container.trigger(eventPrefix + 'go', pageNumber); 784 | 785 | self.callHook('afterGoButtonOnClick', event, pageNumber); 786 | }); 787 | 788 | // go input enter keyup listener 789 | el.on('keyup', '.J-paginationjs-go-pagenumber', function(event) { 790 | if (event.which === 13) { 791 | var pageNumber = $(event.currentTarget).val(); 792 | 793 | if (self.callHook('beforeGoInputOnEnter', event, pageNumber) === false) return false; 794 | 795 | container.trigger(eventPrefix + 'go', pageNumber); 796 | 797 | // Maintain the cursor 798 | $('.J-paginationjs-go-pagenumber', el).focus(); 799 | 800 | self.callHook('afterGoInputOnEnter', event, pageNumber); 801 | } 802 | }); 803 | 804 | el.on('change', '.J-paginationjs-size-select', function(event) { 805 | var current = $(event.currentTarget); 806 | var size = parseInt(current.val()); 807 | var currentPage = self.model.pageNumber || attributes.pageNumber; 808 | 809 | if (typeof size !== 'number') return; 810 | 811 | if (self.callHook('beforeSizeSelectorChange', event, size) === false) return false; 812 | 813 | attributes.pageSize = size; 814 | self.model.pageSize = size; 815 | self.model.totalPage = self.getTotalPage(); 816 | if (currentPage > self.model.totalPage) { 817 | currentPage = self.model.totalPage; 818 | } 819 | self.go(currentPage); 820 | 821 | self.callHook('afterSizeSelectorChange', event, size); 822 | 823 | if (!attributes.pageLink) return false; 824 | }); 825 | 826 | // Previous page 827 | container.on(eventPrefix + 'previous', function(event, done) { 828 | self.previous(done); 829 | }); 830 | 831 | // Next page 832 | container.on(eventPrefix + 'next', function(event, done) { 833 | self.next(done); 834 | }); 835 | 836 | // Disable 837 | container.on(eventPrefix + 'disable', function() { 838 | self.disable(); 839 | }); 840 | 841 | // Enable 842 | container.on(eventPrefix + 'enable', function() { 843 | self.enable(); 844 | }); 845 | 846 | // Refresh 847 | container.on(eventPrefix + 'refresh', function(event, done) { 848 | self.refresh(done); 849 | }); 850 | 851 | // Show 852 | container.on(eventPrefix + 'show', function() { 853 | self.show(); 854 | }); 855 | 856 | // Hide 857 | container.on(eventPrefix + 'hide', function() { 858 | self.hide(); 859 | }); 860 | 861 | // Destroy 862 | container.on(eventPrefix + 'destroy', function() { 863 | self.destroy(); 864 | }); 865 | 866 | // Whether to load the default page 867 | var validTotalPage = Math.max(self.getTotalPage(), 1) 868 | var defaultPageNumber = attributes.pageNumber; 869 | 870 | // Default pageNumber should be 1 when totalNumber is dynamic 871 | if (self.isDynamicTotalNumber) { 872 | if (attributes.resetPageNumberOnInit) defaultPageNumber = 1; 873 | } 874 | 875 | if (attributes.triggerPagingOnInit) { 876 | container.trigger(eventPrefix + 'go', Math.min(defaultPageNumber, validTotalPage)); 877 | } 878 | } 879 | }; 880 | 881 | // Pagination has been initialized 882 | if (container.data('pagination') && container.data('pagination').initialized === true) { 883 | // Handle events 884 | if (isNumeric(options)) { 885 | // eg: container.pagination(5) 886 | container.trigger.call(this, eventPrefix + 'go', options, arguments[1]); 887 | return this; 888 | } else if (typeof options === 'string') { 889 | var args = Array.prototype.slice.apply(arguments); 890 | args[0] = eventPrefix + args[0]; 891 | 892 | switch (options) { 893 | case 'previous': 894 | case 'next': 895 | case 'go': 896 | case 'disable': 897 | case 'enable': 898 | case 'refresh': 899 | case 'show': 900 | case 'hide': 901 | case 'destroy': 902 | container.trigger.apply(this, args); 903 | break; 904 | case 'getSelectedPageNum': 905 | case 'getCurrentPageNum': 906 | if (container.data('pagination').model) { 907 | return container.data('pagination').model.pageNumber; 908 | } else { 909 | return container.data('pagination').attributes.pageNumber; 910 | } 911 | case 'getTotalPage': 912 | return Math.ceil(container.data('pagination').model.totalNumber / container.data('pagination').model.pageSize); 913 | case 'getSelectedPageData': 914 | case 'getCurrentPageData': 915 | return container.data('pagination').currentPageData; 916 | // Whether pagination has been disabled 917 | case 'isDisabled': 918 | return container.data('pagination').model.disabled === true; 919 | default: 920 | throwError('Unknown action: ' + options); 921 | } 922 | return this; 923 | } else { 924 | // Uninstall the old instance before initializing a new one 925 | uninstallPlugin(container); 926 | } 927 | } else { 928 | if (!Helpers.isObject(options)) throwError('Illegal options'); 929 | } 930 | 931 | // Check parameters 932 | parameterChecker(attributes); 933 | 934 | pagination.initialize(); 935 | 936 | return this; 937 | }; 938 | 939 | // Instance defaults 940 | $.fn[pluginName].defaults = { 941 | 942 | // Data source 943 | // Array | String | Function | Object 944 | //dataSource: '', 945 | 946 | // String | Function 947 | //locator: 'data', 948 | 949 | // Function 950 | //totalNumberLocator: function() {}, 951 | 952 | // Total number of data items 953 | totalNumber: 0, 954 | 955 | // Default page number 956 | pageNumber: 1, 957 | 958 | // Number of data items per page 959 | pageSize: 10, 960 | 961 | // Page range (pages around current page) 962 | pageRange: 2, 963 | 964 | // Whether to display the 'Previous' button 965 | showPrevious: true, 966 | 967 | // Whether to display the 'Next' button 968 | showNext: true, 969 | 970 | // Whether to display the page buttons 971 | showPageNumbers: true, 972 | 973 | showNavigator: false, 974 | 975 | // Whether to display the 'Go' input 976 | showGoInput: false, 977 | 978 | // Whether to display the 'Go' button 979 | showGoButton: false, 980 | 981 | showSizeChanger: false, 982 | 983 | sizeChangerOptions: [10, 20, 50, 100], 984 | 985 | // Page link 986 | pageLink: '', 987 | 988 | // 'Previous' text 989 | prevText: '‹', 990 | 991 | // 'Next' text 992 | nextText: '›', 993 | 994 | // Ellipsis text 995 | ellipsisText: '...', 996 | 997 | // 'Go' button text 998 | goButtonText: 'Go', 999 | 1000 | // Additional class name(s) for the Pagination container 1001 | //className: '', 1002 | 1003 | classPrefix: 'paginationjs', 1004 | 1005 | activeClassName: 'active', 1006 | 1007 | // class name when disabled 1008 | disableClassName: 'disabled', 1009 | 1010 | //ulClassName: '', 1011 | 1012 | //pageClassName: '', 1013 | 1014 | //prevClassName: '', 1015 | 1016 | //nextClassName: '', 1017 | 1018 | formatNavigator: 'Total <%= totalNumber %> items', 1019 | 1020 | formatGoInput: '<%= input %>', 1021 | 1022 | formatGoButton: '<%= button %>', 1023 | 1024 | // position in the container 1025 | position: 'bottom', 1026 | 1027 | // Auto hide previous button when current page is the first 1028 | autoHidePrevious: false, 1029 | 1030 | // Auto hide next button when current page is the last 1031 | autoHideNext: false, 1032 | 1033 | //header: '', 1034 | 1035 | //footer: '', 1036 | 1037 | //alias: {}, 1038 | 1039 | // Whether to trigger pagination at initialization 1040 | triggerPagingOnInit: true, 1041 | 1042 | // Whether to reset page number at initialization, it works only if dataSource is a URL and totalNumberLocator is specified 1043 | resetPageNumberOnInit: true, 1044 | 1045 | // Whether to hide pagination when less than one page 1046 | hideOnlyOnePage: false, 1047 | 1048 | hideFirstOnEllipsisShow: false, 1049 | 1050 | hideLastOnEllipsisShow: false, 1051 | 1052 | // Customize item's innerHTML 1053 | callback: function() {} 1054 | }; 1055 | 1056 | // Hook register 1057 | $.fn[pluginHookMethod] = function(hook, callback) { 1058 | if (arguments.length < 2) { 1059 | throwError('Expect 2 arguments at least.'); 1060 | } 1061 | 1062 | if (typeof callback !== 'function') { 1063 | throwError('callback should be a function.'); 1064 | } 1065 | 1066 | var container = $(this); 1067 | var paginationData = container.data('pagination'); 1068 | 1069 | if (!paginationData) { 1070 | container.data('pagination', {}); 1071 | paginationData = container.data('pagination'); 1072 | } 1073 | 1074 | !paginationData.hooks && (paginationData.hooks = {}); 1075 | 1076 | //paginationData.hooks[hook] = callback; 1077 | paginationData.hooks[hook] = paginationData.hooks[hook] || []; 1078 | paginationData.hooks[hook].push(callback); 1079 | 1080 | }; 1081 | 1082 | // Static method 1083 | $[pluginName] = function(selector, options) { 1084 | if (arguments.length < 2) { 1085 | throwError('Requires two parameters.'); 1086 | } 1087 | 1088 | var container; 1089 | 1090 | // 'selector' is a jQuery object 1091 | if (typeof selector !== 'string' && selector instanceof jQuery) { 1092 | container = selector; 1093 | } else { 1094 | container = $(selector); 1095 | } 1096 | 1097 | if (!container.length) return; 1098 | 1099 | container.pagination(options); 1100 | 1101 | return container; 1102 | }; 1103 | 1104 | // ============================================================ 1105 | // helpers 1106 | // ============================================================ 1107 | 1108 | var Helpers = {}; 1109 | 1110 | // Throw error 1111 | function throwError(content) { 1112 | throw new Error('Pagination: ' + content); 1113 | } 1114 | 1115 | // Check parameters 1116 | function parameterChecker(args) { 1117 | if (!args.dataSource) { 1118 | throwError('"dataSource" is required.'); 1119 | } 1120 | 1121 | if (typeof args.dataSource === 'string') { 1122 | if (args.totalNumberLocator === undefined) { 1123 | if (args.totalNumber === undefined) { 1124 | throwError('"totalNumber" is required.'); 1125 | } else if (!isNumeric(args.totalNumber)) { 1126 | throwError('"totalNumber" is incorrect. Expect numberic type'); 1127 | } 1128 | } else { 1129 | if (typeof args.totalNumberLocator !== 'function') { 1130 | throwError('"totalNumberLocator" should be a Function.'); 1131 | } 1132 | } 1133 | } else if (Helpers.isObject(args.dataSource)) { 1134 | if (typeof args.locator === 'undefined') { 1135 | throwError('"dataSource" is an Object, please specify a "locator".'); 1136 | } else if (typeof args.locator !== 'string' && typeof args.locator !== 'function') { 1137 | throwError('' + args.locator + ' is incorrect. Expect string or function type'); 1138 | } 1139 | } 1140 | 1141 | if (args.formatResult !== undefined && typeof args.formatResult !== 'function') { 1142 | throwError('"formatResult" should be a Function.'); 1143 | } 1144 | 1145 | if (args.onError !== undefined && typeof args.onError !== 'function') { 1146 | throwError('"onError" should be a Function.'); 1147 | } 1148 | } 1149 | 1150 | // uninstall plugin 1151 | function uninstallPlugin(target) { 1152 | var events = ['go', 'previous', 'next', 'disable', 'enable', 'refresh', 'show', 'hide', 'destroy']; 1153 | 1154 | // off all events 1155 | $.each(events, function(index, value) { 1156 | target.off(eventPrefix + value); 1157 | }); 1158 | 1159 | // reset pagination data 1160 | target.data('pagination', {}); 1161 | 1162 | // remove pagination element 1163 | $('.paginationjs', target).remove(); 1164 | } 1165 | 1166 | // Object type detection 1167 | function getObjectType(object, tmp) { 1168 | return ( (tmp = typeof(object)) == "object" ? object == null && "null" || Object.prototype.toString.call(object).slice(8, -1) : tmp ).toLowerCase(); 1169 | } 1170 | 1171 | function isNumeric(n) { 1172 | return !isNaN(parseFloat(n)) && isFinite(n); 1173 | } 1174 | 1175 | $.each(['Object', 'Array', 'String'], function(index, name) { 1176 | Helpers['is' + name] = function(object) { 1177 | return getObjectType(object) === name.toLowerCase(); 1178 | }; 1179 | }); 1180 | 1181 | /* 1182 | * export via AMD or CommonJS 1183 | * */ 1184 | if (typeof define === 'function' && define.amd) { 1185 | define(function() { 1186 | return $; 1187 | }); 1188 | } 1189 | 1190 | })(this, window.jQuery); 1191 | -------------------------------------------------------------------------------- /src/pagination.less: -------------------------------------------------------------------------------- 1 | @borderColor: #aaa; 2 | @activeBgColor: #aaa; 3 | 4 | @Blue_color_base: #289DE9; 5 | @Blue_color_font: @Blue_color_base; 6 | @Blue_color_border: @Blue_color_base; 7 | @Blue_bgColor_active: @Blue_color_base; 8 | @Blue_bgColor_hover: #E9F4FC; 9 | @Blue_bgColor_buttonHover: #3CA5EA; 10 | 11 | @Green_color_base: #449D44; 12 | @Green_color_font: @Green_color_base; 13 | @Green_color_border: @Green_color_base; 14 | @Green_bgColor_active: @Green_color_base; 15 | @Green_bgColor_hover: #EBF4EB; 16 | @Green_bgColor_buttonHover: #55A555; 17 | 18 | @Yellow_color_base: #EC971F; 19 | @Yellow_color_font: @Yellow_color_base; 20 | @Yellow_color_border: @Yellow_color_base; 21 | @Yellow_bgColor_active: @Yellow_color_base; 22 | @Yellow_bgColor_hover: #FDF5E9; 23 | @Yellow_bgColor_buttonHover: #EEA135; 24 | 25 | @Red_color_base: #C9302C; 26 | @Red_color_font: @Red_color_base; 27 | @Red_color_border: @Red_color_base; 28 | @Red_bgColor_active: @Red_color_base; 29 | @Red_bgColor_hover: #FAEAEA; 30 | @Red_bgColor_buttonHover: #CE4541; 31 | 32 | @S_fontSize: 12px; 33 | @S_minWidth: 26px; 34 | @S_height: 24px; 35 | @S_lineHeight: @S_height; 36 | @S_activeHeight: @S_height + 2; 37 | @S_inputWidth: 26px; 38 | @S_inputHeight: 24px; 39 | @S_buttonMinWidth: 30px; 40 | @S_buttonHeight: 26px; 41 | @S_buttonLineHeight: @S_buttonHeight - 2; 42 | @S_buttonPadding: 0 6px; 43 | @S_navHeight: @S_activeHeight; 44 | 45 | 46 | @N_fontSize: 14px; 47 | @N_minWidth: 30px; 48 | @N_height: 28px; 49 | @N_lineHeight: @N_height; 50 | @N_activeHeight: @N_height + 2; 51 | @N_inputWidth: 30px; 52 | @N_inputHeight: 28px; 53 | @N_buttonMinWidth: 40px; 54 | @N_buttonHeight: 30px; 55 | @N_buttonLineHeight: @N_buttonHeight - 2; 56 | @N_buttonPadding: 0 8px; 57 | @N_navHeight: @N_activeHeight; 58 | 59 | 60 | @B_fontSize: 16px; 61 | @B_minWidth: 36px; 62 | @B_height: 34px; 63 | @B_lineHeight: @B_height; 64 | @B_activeHeight: @B_height + 2; 65 | @B_inputWidth: 36px; 66 | @B_inputHeight: 34px; 67 | @B_buttonMinWidth: 50px; 68 | @B_buttonHeight: 36px; 69 | @B_buttonLineHeight: @B_buttonHeight - 2; 70 | @B_buttonPadding: 0 12px; 71 | @B_navHeight: @B_activeHeight; 72 | 73 | 74 | .paginationjs{ 75 | display: flex; 76 | line-height: 1.6; 77 | font-family: "Marmelad", "Lucida Grande", "Arial", "Hiragino Sans GB", Georgia, sans-serif; 78 | font-size: @N_fontSize; 79 | box-sizing: initial; 80 | &:after{ 81 | display: table; 82 | content: " "; 83 | clear: both; 84 | } 85 | .paginationjs-pages{ 86 | float: left; 87 | margin-left: 10px; 88 | ul{ 89 | float: left; 90 | margin: 0; 91 | padding: 0; 92 | } 93 | li{ 94 | display: inline-block; 95 | border: 1px solid @borderColor; 96 | border-right: none; 97 | list-style: none; 98 | > a{ 99 | min-width: @N_minWidth; 100 | height: @N_height; 101 | line-height: @N_lineHeight; 102 | display: block; 103 | background: #fff; 104 | font-size: @N_fontSize; 105 | color: #333; 106 | text-decoration: none; 107 | text-align: center; 108 | cursor: pointer; 109 | &:hover{ 110 | background: #eee; 111 | } 112 | } 113 | &.active{ 114 | border: none; 115 | > a{ 116 | height: @N_activeHeight; 117 | line-height: @N_activeHeight; 118 | background: @activeBgColor; 119 | color: #fff; 120 | cursor: default; 121 | } 122 | } 123 | &.disabled{ 124 | > a{ 125 | opacity: .3; 126 | cursor: default; 127 | &:hover{ 128 | background: none; 129 | } 130 | } 131 | } 132 | &:first-child{ 133 | border-radius: 3px 0 0 3px; 134 | > a{ 135 | border-radius: 3px 0 0 3px; 136 | } 137 | } 138 | &:last-child{ 139 | border-right: 1px solid @borderColor; 140 | border-radius: 0 3px 3px 0; 141 | > a{ 142 | border-radius: 0 3px 3px 0; 143 | } 144 | } 145 | } 146 | } 147 | .paginationjs-size-changer { 148 | display: inline-block; 149 | font-size: @N_fontSize; 150 | margin-left: 10px; 151 | > select{ 152 | height: @N_inputHeight; 153 | background: #fff; 154 | border-radius: 3px; 155 | border: 1px solid @borderColor; 156 | padding: 0; 157 | font-size: @N_fontSize; 158 | text-align: center; 159 | vertical-align: baseline; 160 | outline: none; 161 | box-shadow: none; 162 | box-sizing: initial; 163 | } 164 | } 165 | .paginationjs-go-input{ 166 | display: inline-block; 167 | margin-left: 10px; 168 | font-size: @N_fontSize; 169 | > input[type="text"]{ 170 | width: @N_inputWidth; 171 | height: @N_inputHeight; 172 | background: #fff; 173 | border-radius: 3px; 174 | border: 1px solid @borderColor; 175 | padding: 0; 176 | font-size: @N_fontSize; 177 | text-align: center; 178 | vertical-align: baseline; 179 | outline: none; 180 | box-shadow: none; 181 | box-sizing: initial; 182 | } 183 | } 184 | .paginationjs-go-button{ 185 | display: inline-block; 186 | margin-left: 10px; 187 | font-size: @N_fontSize; 188 | > input[type="button"]{ 189 | min-width: @N_buttonMinWidth; 190 | height: @N_buttonHeight; 191 | line-height: @N_buttonLineHeight; 192 | background: #fff; 193 | border-radius: 3px; 194 | border: 1px solid @borderColor; 195 | text-align: center; 196 | padding: @N_buttonPadding; 197 | font-size: @N_fontSize; 198 | vertical-align: baseline; 199 | outline: none; 200 | box-shadow: none; 201 | color: #333; 202 | cursor: pointer; 203 | &:hover{ 204 | background-color: #f8f8f8; 205 | } 206 | } 207 | } 208 | .paginationjs-nav{ 209 | float: left; 210 | height: @N_navHeight; 211 | line-height: @N_navHeight; 212 | font-size: @N_fontSize; 213 | } 214 | 215 | &.paginationjs-small{ 216 | font-size: @S_fontSize; 217 | .paginationjs-pages{ 218 | li{ 219 | > a{ 220 | min-width: @S_minWidth; 221 | height: @S_height; 222 | line-height: @S_lineHeight; 223 | font-size: @S_fontSize; 224 | } 225 | &.active{ 226 | > a{ 227 | height: @S_activeHeight; 228 | line-height: @S_activeHeight; 229 | } 230 | } 231 | } 232 | } 233 | .paginationjs-size-changer { 234 | font-size: @S_fontSize; 235 | > select{ 236 | height: @S_inputHeight; 237 | font-size: @S_fontSize; 238 | } 239 | } 240 | .paginationjs-go-input{ 241 | font-size: @S_fontSize; 242 | > input[type="text"]{ 243 | width: @S_inputWidth; 244 | height: @S_inputHeight; 245 | font-size: @S_fontSize; 246 | } 247 | } 248 | .paginationjs-go-button{ 249 | font-size: @S_fontSize; 250 | > input[type="button"]{ 251 | min-width: @S_buttonMinWidth; 252 | height: @S_buttonHeight; 253 | line-height: @S_buttonLineHeight; 254 | padding: @S_buttonPadding; 255 | font-size: @S_fontSize; 256 | } 257 | } 258 | .paginationjs-nav{ 259 | height: 26px; 260 | line-height: 26px; 261 | font-size: @S_fontSize; 262 | } 263 | } 264 | &.paginationjs-big{ 265 | font-size: @B_fontSize; 266 | .paginationjs-pages{ 267 | li{ 268 | > a{ 269 | min-width: @B_minWidth; 270 | height: @B_height; 271 | line-height: @B_lineHeight; 272 | font-size: @B_fontSize; 273 | } 274 | &.active{ 275 | > a{ 276 | height: @B_activeHeight; 277 | line-height: @B_activeHeight; 278 | } 279 | } 280 | } 281 | } 282 | .paginationjs-size-changer { 283 | font-size: @B_fontSize; 284 | > select{ 285 | height: @B_inputHeight; 286 | font-size: @B_fontSize; 287 | } 288 | } 289 | .paginationjs-go-input{ 290 | font-size: @B_fontSize; 291 | > input[type="text"]{ 292 | width: @B_inputWidth; 293 | height: @B_inputHeight; 294 | font-size: @B_fontSize; 295 | } 296 | } 297 | .paginationjs-go-button{ 298 | font-size: @B_fontSize; 299 | > input[type="button"]{ 300 | min-width: @B_buttonMinWidth; 301 | height: @B_buttonHeight; 302 | line-height: @B_buttonLineHeight; 303 | padding: @B_buttonPadding; 304 | font-size: @B_fontSize; 305 | } 306 | } 307 | .paginationjs-nav{ 308 | height: @B_navHeight; 309 | line-height: @B_navHeight; 310 | font-size: @B_fontSize; 311 | } 312 | } 313 | 314 | > :first-child { 315 | margin-left: 0; 316 | } 317 | } 318 | 319 | .paginationjs{ 320 | &.paginationjs-theme-blue{ 321 | .paginationjs-pages{ 322 | li{ 323 | border-color: @Blue_color_border; 324 | > a{ 325 | color: @Blue_color_font; 326 | &:hover{ 327 | background: @Blue_bgColor_hover; 328 | } 329 | } 330 | &.active{ 331 | > a{ 332 | background: @Blue_bgColor_active; 333 | color: #fff; 334 | } 335 | } 336 | &.disabled > a:hover{ 337 | background: none; 338 | } 339 | } 340 | } 341 | .paginationjs-size-changer { 342 | > select{ 343 | border-color: @Blue_color_border; 344 | } 345 | } 346 | .paginationjs-go-input{ 347 | > input[type="text"]{ 348 | border-color: @Blue_color_border; 349 | } 350 | } 351 | .paginationjs-go-button{ 352 | > input[type="button"]{ 353 | background: @Blue_bgColor_active; 354 | border-color: @Blue_color_border; 355 | color: #fff; 356 | &:hover{ 357 | background-color: @Blue_bgColor_buttonHover; 358 | } 359 | } 360 | } 361 | } 362 | } 363 | 364 | .paginationjs{ 365 | &.paginationjs-theme-green{ 366 | .paginationjs-pages{ 367 | li{ 368 | border-color: @Green_color_border; 369 | > a{ 370 | color: @Green_color_font; 371 | &:hover{ 372 | background: @Green_bgColor_hover; 373 | } 374 | } 375 | &.active{ 376 | > a{ 377 | background: @Green_bgColor_active; 378 | color: #fff; 379 | } 380 | } 381 | &.disabled > a:hover{ 382 | background: none; 383 | } 384 | } 385 | } 386 | .paginationjs-size-changer { 387 | > select{ 388 | border-color: @Green_color_border; 389 | } 390 | } 391 | .paginationjs-go-input{ 392 | > input[type="text"]{ 393 | border-color: @Green_color_border; 394 | } 395 | } 396 | .paginationjs-go-button{ 397 | > input[type="button"]{ 398 | background: @Green_bgColor_active; 399 | border-color: @Green_color_border; 400 | color: #fff; 401 | &:hover{ 402 | background-color: @Green_bgColor_buttonHover; 403 | } 404 | } 405 | } 406 | } 407 | } 408 | 409 | .paginationjs{ 410 | &.paginationjs-theme-yellow{ 411 | .paginationjs-pages{ 412 | li{ 413 | border-color: @Yellow_color_border; 414 | > a{ 415 | color: @Yellow_color_font; 416 | &:hover{ 417 | background: @Yellow_bgColor_hover; 418 | } 419 | } 420 | &.active{ 421 | > a{ 422 | background: @Yellow_bgColor_active; 423 | color: #fff; 424 | } 425 | } 426 | &.disabled > a:hover{ 427 | background: none; 428 | } 429 | } 430 | } 431 | .paginationjs-size-changer { 432 | > select{ 433 | border-color: @Yellow_color_border; 434 | } 435 | } 436 | .paginationjs-go-input{ 437 | > input[type="text"]{ 438 | border-color: @Yellow_color_border; 439 | } 440 | } 441 | .paginationjs-go-button{ 442 | > input[type="button"]{ 443 | background: @Yellow_bgColor_active; 444 | border-color: @Yellow_color_border; 445 | color: #fff; 446 | &:hover{ 447 | background-color: @Yellow_bgColor_buttonHover; 448 | } 449 | } 450 | } 451 | } 452 | } 453 | 454 | .paginationjs{ 455 | &.paginationjs-theme-red{ 456 | .paginationjs-pages{ 457 | li{ 458 | border-color: @Red_color_border; 459 | > a{ 460 | color: @Red_color_font; 461 | &:hover{ 462 | background: @Red_bgColor_hover; 463 | } 464 | } 465 | &.active{ 466 | > a{ 467 | background: @Red_bgColor_active; 468 | color: #fff; 469 | } 470 | } 471 | &.disabled > a:hover{ 472 | background: none; 473 | } 474 | } 475 | } 476 | .paginationjs-size-changer { 477 | > select{ 478 | border-color: @Red_color_border; 479 | } 480 | } 481 | .paginationjs-go-input{ 482 | > input[type="text"]{ 483 | border-color: @Red_color_border; 484 | } 485 | } 486 | .paginationjs-go-button{ 487 | > input[type="button"]{ 488 | background: @Red_bgColor_active; 489 | border-color: @Red_color_border; 490 | color: #fff; 491 | &:hover{ 492 | background-color: @Red_bgColor_buttonHover; 493 | } 494 | } 495 | } 496 | } 497 | } 498 | 499 | /* Hacks for IE 6~9 */ 500 | .paginationjs{ 501 | .paginationjs-pages{ 502 | li{ 503 | > a{ 504 | 505 | } 506 | &.paginationjs-next{ 507 | *border-right: 1px solid @borderColor; 508 | border-right: 1px solid #aaa\0; 509 | } 510 | } 511 | } 512 | .paginationjs-size-changer{ 513 | *margin-left: 5px; 514 | margin-left: 5px\0; 515 | > select{ 516 | *line-height: @N_inputHeight; 517 | line-height: 28px\0; 518 | *vertical-align: middle; 519 | vertical-align: middle\0; 520 | } 521 | } 522 | .paginationjs-go-input{ 523 | *margin-left: 5px; 524 | margin-left: 5px\0; 525 | > input[type="text"]{ 526 | *line-height: @N_inputHeight; 527 | line-height: 28px\0; 528 | *vertical-align: middle; 529 | vertical-align: middle\0; 530 | } 531 | } 532 | .paginationjs-go-button{ 533 | *margin-left: 5px; 534 | margin-left: 5px\0; 535 | > input[type="button"]{ 536 | *vertical-align: middle; 537 | vertical-align: middle\0; 538 | } 539 | } 540 | &.paginationjs-big{ 541 | .paginationjs-pages{ 542 | li{ 543 | > a{ 544 | line-height: 36px\0; 545 | } 546 | } 547 | } 548 | .paginationjs-go-input{ 549 | > input[type="text"]{ 550 | *height: 35px; 551 | height: 36px\0; 552 | *line-height: 36px; 553 | line-height: 36px\0; 554 | } 555 | } 556 | } 557 | } 558 | --------------------------------------------------------------------------------