├── .gitignore ├── Readme.md ├── bower.json ├── index.html └── mithril.paginate.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | bower_components -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Mithril Pagination module 2 | 3 | A small pagination module for mithril. Pass in an array of items and it paginates based on the options provided. 4 | 5 | ## How to use 6 | 7 | // Mock some data 8 | var items = []; 9 | 10 | for (var i = 0; i<15; i++) { 11 | items.push({'name':'Item #'+i}) 12 | } 13 | 14 | /** 15 | * Your Module 16 | */ 17 | 18 | var app = {}, 19 | options = { 20 | perPage : 5, 21 | data : items, 22 | limit : 10, 23 | ellipsis : '…', 24 | edges : 2 25 | }; 26 | 27 | /* Controller */ 28 | app.controller = function(){ 29 | 30 | 31 | this.paginate = new mpaginate.controller(options) 32 | 33 | } 34 | 35 | 36 | /* View */ 37 | app.view = function(ctrl){ 38 | return [ 39 | mpaginate.view(ctrl.paginate) 40 | ] 41 | } 42 | 43 | 44 | 45 | /* Initialize the app */ 46 | 47 | m.module(document.getElementById('paginate'), app) 48 | 49 | 50 | ## Options 51 | 52 | { 53 | perPage : 10, 54 | page : 1, 55 | data : Array, 56 | limit : 10 // Page number limit when should ellipsis text be display 57 | ellipsis : '…', 58 | edges : 2 // Number of pages before and after the current page 59 | } 60 | 61 | ## Todo 62 | 63 | 1. Support Async loading of items 64 | 2. Support large sets of items - Done -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mithril-paginate", 3 | "version": "0.0.0", 4 | "authors": [ 5 | "Vinay " 6 | ], 7 | "license": "MIT", 8 | "ignore": [ 9 | "**/.*", 10 | "node_modules", 11 | "bower_components", 12 | "test", 13 | "tests" 14 | ], 15 | "devDependencies": { 16 | "mithril": "~0.1.27" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mithril paginate 6 | 23 | 24 | 25 | 26 | 27 |
28 | 29 |
30 | 31 | 32 | 33 | 74 | 75 | -------------------------------------------------------------------------------- /mithril.paginate.js: -------------------------------------------------------------------------------- 1 | /* Module */ 2 | 3 | var mpaginate = (function(app){ 4 | 5 | var defaultOptions = { 6 | perPage : 10, 7 | page : 1, 8 | limit : 10, 9 | ellipsis : '…', 10 | edges : 2 11 | } 12 | 13 | /** 14 | * Extend 15 | */ 16 | var extend = function(obj, extObj) { 17 | if (arguments.length > 2) { 18 | for (var a = 1; a < arguments.length; a++) { 19 | extend(obj, arguments[a]); 20 | } 21 | } else { 22 | for (var i in extObj) { 23 | obj[i] = extObj[i]; 24 | } 25 | } 26 | return obj; 27 | }; 28 | 29 | /** 30 | * Controller 31 | * @return {[type]} [description] 32 | */ 33 | app.controller = function(options){ 34 | 35 | 36 | /* Extend options */ 37 | 38 | this.options = extend(defaultOptions, options); 39 | 40 | this.perPage = m.prop(this.options.perPage) 41 | 42 | this.page = m.prop(this.options.page - 1); 43 | 44 | 45 | /* Items */ 46 | 47 | this.items = m.prop(this.options.data || []); 48 | 49 | /* Total pages */ 50 | 51 | this.totalPages = m.prop(Math.ceil(this.items().length/this.perPage())) 52 | 53 | 54 | /** 55 | * Page list 56 | */ 57 | 58 | this.pageList = function(){ 59 | 60 | var p = [], 61 | start = 0, 62 | end = this.totalPages(), 63 | left = Math.max(parseInt(this.page()) - this.options.edges, 0), 64 | right = Math.min(parseInt(this.page()) + this.options.edges, this.totalPages()) 65 | 66 | for(var i = start; i < end; i ++){ 67 | 68 | if( i == 0 69 | || i == parseInt(this.totalPages()) - 1 70 | || this.totalPages() < this.options.limit){ 71 | 72 | p.push(i) 73 | 74 | } else{ 75 | 76 | if(i == (right + 1) || i == (left - 1)) p.push(this.options.ellipsis) 77 | 78 | if( i <= right && i >= left) p.push(i) 79 | } 80 | } 81 | 82 | return p; 83 | 84 | }.bind(this) 85 | 86 | 87 | 88 | /** 89 | * Next page 90 | */ 91 | 92 | this.nextPage = function(){ 93 | 94 | var current = this.page(); 95 | 96 | ++current; 97 | 98 | if(current > (this.totalPages() - 1)){ 99 | current = (this.totalPages() - 1); 100 | } 101 | 102 | this.page(current) 103 | 104 | }.bind(this) 105 | 106 | /** 107 | * Prev page 108 | */ 109 | 110 | this.prevPage = function(){ 111 | 112 | var current = this.page(); 113 | 114 | --current; 115 | 116 | if(current < 0){ 117 | current = 0; 118 | } 119 | 120 | this.page(current) 121 | 122 | 123 | }.bind(this) 124 | 125 | 126 | /** 127 | * Change perPage 128 | */ 129 | 130 | this.changePerPage = function(value){ 131 | 132 | this.perPage(value) 133 | 134 | /* Recalculate total pages */ 135 | 136 | this.totalPages(Math.ceil(this.items().length/this.perPage())) 137 | 138 | /* Jump to page 1 */ 139 | 140 | this.page(0); 141 | 142 | }.bind(this) 143 | } 144 | 145 | /** 146 | * View 147 | * @return {[type]} [description] 148 | */ 149 | app.view = function(ctrl){ 150 | return [ 151 | m('ul.items', [ 152 | ctrl.items() 153 | .slice(ctrl.page() * ctrl.perPage(), (parseInt(ctrl.page()) + 1) * ctrl.perPage()) 154 | .map(function(item){ 155 | return m('li', item.name) 156 | }) 157 | ]), 158 | 159 | m('nav.pages', [ 160 | m('a', { 161 | onclick: ctrl.prevPage, 162 | class: ctrl.page() == 0? 'disabled': '' 163 | }, 'Previous page'), 164 | ctrl.pageList().map(function(page){ 165 | 166 | switch(page){ 167 | 168 | case ctrl.options.ellipsis: 169 | return m('span.page-ellipsis', m.trust(page)) 170 | break; 171 | 172 | default: 173 | return m('a', { 174 | onclick : m.withAttr('data-page', ctrl.page), 175 | 'data-page' : page, 176 | className: page == ctrl.page()? 'page-current': '' 177 | }, parseInt(page) + 1) 178 | break; 179 | 180 | } 181 | 182 | }), 183 | m('a', { 184 | onclick: ctrl.nextPage, 185 | class: ctrl.page() == (ctrl.totalPages() - 1)? 'disabled': '' 186 | }, 'Next page'), 187 | ]), 188 | m('label', 'Per page: '), 189 | m('select', { 190 | onchange: m.withAttr('value', ctrl.changePerPage) 191 | }, [ 192 | m('option', 5), 193 | m('option', 10), 194 | m('option', 15) 195 | ]) 196 | ] 197 | 198 | } 199 | 200 | 201 | return app; 202 | 203 | })(mpaginate || {}); --------------------------------------------------------------------------------