spine_paginator 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gruntfile.coffee CHANGED
@@ -13,6 +13,8 @@ module.exports = (grunt) ->
13
13
  all:
14
14
  files:
15
15
  'dist/spine.paginator.js': 'src/spine.paginator.coffee'
16
+ 'dist/spine.pagination_controller.js': 'src/spine.pagination_controller.coffee'
17
+ 'examples/spine_pagination.js': 'examples/spine_pagination.coffee'
16
18
 
17
19
  concat:
18
20
  all:
@@ -20,7 +22,8 @@ module.exports = (grunt) ->
20
22
  banner: '<%= meta.banner %>'
21
23
  files:
22
24
  'dist/spine.paginator.js': 'dist/spine.paginator.js'
23
-
25
+ 'dist/spine.pagination_controller.js': 'dist/spine.pagination_controller.js'
26
+
24
27
  uglify:
25
28
  all:
26
29
  options:
@@ -28,17 +31,27 @@ module.exports = (grunt) ->
28
31
  report: 'gzip'
29
32
  files:
30
33
  'dist/spine.paginator.min.js': 'dist/spine.paginator.js'
34
+ 'dist/spine.pagination_controller.min.js': 'dist/spine.pagination_controller.js'
31
35
 
32
36
  jasmine:
33
37
  all:
34
- src: 'dist/spine.paginator.js'
38
+ src: 'dist/*.js'
35
39
  options:
36
40
  specs: 'spec/spine.paginator/**/*.js'
37
41
  helpers: 'spec/lib/**/*.js'
42
+
43
+ slim:
44
+ all:
45
+ files:
46
+ 'examples/spine_pagination.html': 'examples/spine_pagination.slim'
47
+ sass:
48
+ all:
49
+ files:
50
+ 'examples/spine_pagination.css': 'examples/spine_pagination.scss'
38
51
 
39
52
  watch:
40
53
  all:
41
- files: 'src/spine.paginator.coffee'
54
+ files: ['src/*.coffee', 'examples/*.coffee', 'examples/*.slim', 'examples/*.scss']
42
55
  tasks: ['build', 'spec']
43
56
 
44
57
  grunt.loadNpmTasks 'grunt-contrib-coffee'
@@ -46,7 +59,9 @@ module.exports = (grunt) ->
46
59
  grunt.loadNpmTasks 'grunt-contrib-uglify'
47
60
  grunt.loadNpmTasks 'grunt-contrib-jasmine'
48
61
  grunt.loadNpmTasks 'grunt-contrib-watch'
62
+ grunt.loadNpmTasks 'grunt-slim'
63
+ grunt.loadNpmTasks 'grunt-contrib-sass'
49
64
 
50
65
  grunt.registerTask 'default', ['watch']
51
66
  grunt.registerTask 'spec', ['jasmine']
52
- grunt.registerTask 'build', ['coffee', 'concat', 'uglify']
67
+ grunt.registerTask 'build', ['coffee', 'concat', 'uglify', 'slim', 'sass']
data/README.md CHANGED
@@ -1,29 +1,27 @@
1
1
  # SpinePaginator
2
2
 
3
- TODO: Write a gem description
3
+ Paginator for [Spine](https://github.com/spine/spine).
4
+
4
5
 
5
6
  ## Installation
6
7
 
8
+ ### Rails
9
+
7
10
  Add this line to your application's Gemfile:
8
11
 
9
12
  gem 'spine_paginator'
10
13
 
11
- And then execute:
12
-
13
- $ bundle
14
14
 
15
- Or install it yourself as:
15
+ ## Usage
16
16
 
17
- $ gem install spine_paginator
17
+ ### Rails
18
18
 
19
- ## Usage
19
+ Add the following to your `app/assets/javascripts/application.js` file.
20
20
 
21
- TODO: Write usage instructions here
21
+ //= require spine
22
+ //= require handlebars
23
+ //= require spine.paginator
24
+ //= require spine.pagination_controller
22
25
 
23
- ## Contributing
26
+ Then, see https://github.com/vkill/spine_paginator/examples/spine_pagination.coffee
24
27
 
25
- 1. Fork it
26
- 2. Create your feature branch (`git checkout -b my-new-feature`)
27
- 3. Commit your changes (`git commit -am 'Add some feature'`)
28
- 4. Push to the branch (`git push origin my-new-feature`)
29
- 5. Create new Pull Request
@@ -0,0 +1,142 @@
1
+ // spine.paginator.js
2
+ // version: 0.1.0
3
+ // author: vkill
4
+ // license: MIT
5
+ (function() {
6
+ var Spine,
7
+ __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
8
+ __hasProp = {}.hasOwnProperty,
9
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
10
+
11
+ Spine = this.Spine || require('spine');
12
+
13
+ /*
14
+
15
+ Usage
16
+
17
+ see https://github.com/vkill/spine_paginator/examples/spine_pagination.coffee
18
+ */
19
+
20
+
21
+ Spine.PaginationController = (function(_super) {
22
+ __extends(PaginationController, _super);
23
+
24
+ PaginationController.MODEL = null;
25
+
26
+ PaginationController.PER_PAGES = [10, 20, 30, 40];
27
+
28
+ PaginationController.PAGINATE_EVENT = "paginate";
29
+
30
+ PaginationController.PAGE = 1;
31
+
32
+ PaginationController.PER_PAGE = null;
33
+
34
+ PaginationController.PAGINATION = null;
35
+
36
+ function PaginationController() {
37
+ this.templateHtmlDataEmpty = __bind(this.templateHtmlDataEmpty, this);
38
+ this.render = __bind(this.render, this); PaginationController.__super__.constructor.apply(this, arguments);
39
+ if (this.constructor.MODEL == null) {
40
+ throw new Error("please defined class variable MODEL");
41
+ }
42
+ this.constructor.PER_PAGE = this.constructor.PER_PAGES[0];
43
+ if (this.constructor.PER_PAGE == null) {
44
+ throw new Error("please defined class variable PER_PAGES");
45
+ }
46
+ this.constructor.MODEL.bind(this.constructor.PAGINATE_EVENT, this.render);
47
+ }
48
+
49
+ PaginationController.refresh = function() {
50
+ this.PAGE = 1;
51
+ return this.load();
52
+ };
53
+
54
+ PaginationController.toPage = function(page) {
55
+ this.PAGE = page;
56
+ return this.load();
57
+ };
58
+
59
+ PaginationController.load = function() {
60
+ var pagination;
61
+
62
+ pagination = this.MODEL.page(this.PAGE, {
63
+ perPage: this.PER_PAGE
64
+ });
65
+ this.PAGINATION = pagination;
66
+ return this.MODEL.trigger(this.PAGINATE_EVENT);
67
+ };
68
+
69
+ PaginationController.prototype.render = function() {
70
+ var pagination;
71
+
72
+ pagination = this.constructor.PAGINATION;
73
+ if (pagination.records.length > 0) {
74
+ return this.html(this.templateHtml());
75
+ } else {
76
+ return this.html(this.templateHtmlDataEmpty());
77
+ }
78
+ };
79
+
80
+ PaginationController.prototype.events = {
81
+ 'click a[data-page]': 'clickPage'
82
+ };
83
+
84
+ PaginationController.prototype.clickPage = function(e) {
85
+ var page;
86
+
87
+ e.preventDefault();
88
+ page = this.getPageFromE(e);
89
+ if (page == null) {
90
+ return;
91
+ }
92
+ return this.constructor.toPage(page);
93
+ };
94
+
95
+ PaginationController.prototype.getPageFromE = function(e) {
96
+ var $node, page, _page;
97
+
98
+ $node = $(e.target);
99
+ if ($node.parent('.disabled, .active').length > 0) {
100
+ return null;
101
+ }
102
+ _page = $node.data('page');
103
+ page = null;
104
+ switch (_page) {
105
+ case 'first':
106
+ page = this.constructor.PAGINATION.firstPage();
107
+ break;
108
+ case 'prev':
109
+ page = this.constructor.PAGINATION.currentPage() - 1;
110
+ break;
111
+ case 'next':
112
+ page = this.constructor.PAGINATION.currentPage() + 1;
113
+ break;
114
+ case 'last':
115
+ page = this.constructor.PAGINATION.lastPage();
116
+ break;
117
+ case 'gap':
118
+ page = null;
119
+ break;
120
+ default:
121
+ page = _page;
122
+ }
123
+ return page;
124
+ };
125
+
126
+ PaginationController.prototype.templateHtmlDataEmpty = function() {
127
+ return "";
128
+ };
129
+
130
+ PaginationController.prototype.templateHtml = function() {
131
+ var pagination, source;
132
+
133
+ pagination = this.constructor.PAGINATION;
134
+ source = "<div class=\"pagination pagination-small pull-right\">\n <ul>\n <li {{#unless hasFirst}}class=\"disabled\"{{/unless}}>\n <a href=\"javascript:void(0);\" data-page=\"first\">first</a>\n </li>\n <li {{#unless hasPrev}}class=\"disabled\"{{/unless}}>\n <a href=\"javascript:void(0);\" data-page=\"prev\">prev</a>\n </li>\n {{#each pages}}\n {{#if this.gap}}\n <li class=\"disabled\">\n <a href=\"javascript:void(0);\" data-page='gap'>...</a>\n </li>\n {{else}}\n <li {{#if this.current}}class=\"active\"{{/if}}>\n <a href=\"javascript:void(0);\" data-page={{this.number}}>{{this.number}}</a>\n </li>\n {{/if}}\n {{/each}}\n <li {{#unless hasNext}}class=\"disabled\"{{/unless}}>\n <a href='javascript:void(0);' data-page=\"next\">next</a>\n </li>\n <li {{#unless hasLast}}class=\"disabled\"{{/unless}}>\n <a href='javascript:void(0);' data-page=\"last\">last</a>\n </li>\n </ul>\n</div>";
135
+ return Handlebars.compile(source)(pagination.locals);
136
+ };
137
+
138
+ return PaginationController;
139
+
140
+ })(Spine.Controller);
141
+
142
+ }).call(this);
@@ -0,0 +1,5 @@
1
+ // spine.paginator.js
2
+ // version: 0.1.0
3
+ // author: vkill
4
+ // license: MIT
5
+ (function(){var t,s=function(t,s){return function(){return t.apply(s,arguments)}},e={}.hasOwnProperty,i=function(t,s){function i(){this.constructor=t}for(var r in s)e.call(s,r)&&(t[r]=s[r]);return i.prototype=s.prototype,t.prototype=new i,t.__super__=s.prototype,t};t=this.Spine||require("spine"),t.PaginationController=function(t){function e(){if(this.templateHtmlDataEmpty=s(this.templateHtmlDataEmpty,this),this.render=s(this.render,this),e.__super__.constructor.apply(this,arguments),null==this.constructor.MODEL)throw Error("please defined class variable MODEL");if(this.constructor.PER_PAGE=this.constructor.PER_PAGES[0],null==this.constructor.PER_PAGE)throw Error("please defined class variable PER_PAGES");this.constructor.MODEL.bind(this.constructor.PAGINATE_EVENT,this.render)}return i(e,t),e.MODEL=null,e.PER_PAGES=[10,20,30,40],e.PAGINATE_EVENT="paginate",e.PAGE=1,e.PER_PAGE=null,e.PAGINATION=null,e.refresh=function(){return this.PAGE=1,this.load()},e.toPage=function(t){return this.PAGE=t,this.load()},e.load=function(){var t;return t=this.MODEL.page(this.PAGE,{perPage:this.PER_PAGE}),this.PAGINATION=t,this.MODEL.trigger(this.PAGINATE_EVENT)},e.prototype.render=function(){var t;return t=this.constructor.PAGINATION,t.records.length>0?this.html(this.templateHtml()):this.html(this.templateHtmlDataEmpty())},e.prototype.events={"click a[data-page]":"clickPage"},e.prototype.clickPage=function(t){var s;return t.preventDefault(),s=this.getPageFromE(t),null!=s?this.constructor.toPage(s):void 0},e.prototype.getPageFromE=function(t){var s,e,i;if(s=$(t.target),s.parent(".disabled, .active").length>0)return null;switch(i=s.data("page"),e=null,i){case"first":e=this.constructor.PAGINATION.firstPage();break;case"prev":e=this.constructor.PAGINATION.currentPage()-1;break;case"next":e=this.constructor.PAGINATION.currentPage()+1;break;case"last":e=this.constructor.PAGINATION.lastPage();break;case"gap":e=null;break;default:e=i}return e},e.prototype.templateHtmlDataEmpty=function(){return""},e.prototype.templateHtml=function(){var t,s;return t=this.constructor.PAGINATION,s='<div class="pagination pagination-small pull-right">\n <ul>\n <li {{#unless hasFirst}}class="disabled"{{/unless}}>\n <a href="javascript:void(0);" data-page="first">first</a>\n </li>\n <li {{#unless hasPrev}}class="disabled"{{/unless}}>\n <a href="javascript:void(0);" data-page="prev">prev</a>\n </li>\n {{#each pages}}\n {{#if this.gap}}\n <li class="disabled">\n <a href="javascript:void(0);" data-page=\'gap\'>...</a>\n </li>\n {{else}}\n <li {{#if this.current}}class="active"{{/if}}>\n <a href="javascript:void(0);" data-page={{this.number}}>{{this.number}}</a>\n </li>\n {{/if}}\n {{/each}}\n <li {{#unless hasNext}}class="disabled"{{/unless}}>\n <a href=\'javascript:void(0);\' data-page="next">next</a>\n </li>\n <li {{#unless hasLast}}class="disabled"{{/unless}}>\n <a href=\'javascript:void(0);\' data-page="last">last</a>\n </li>\n </ul>\n</div>',Handlebars.compile(s)(t.locals)},e}(t.Controller)}).call(this);
@@ -2,12 +2,19 @@
2
2
  // version: 0.1.0
3
3
  // author: vkill
4
4
  // license: MIT
5
- (function() {
6
- var Extend, Model, Paginator, Spine;
5
+ /*
6
+ Usage
7
+
8
+ data = ({name: String.fromCharCode(num)} for num in ['a'.charCodeAt(0)..'z'.charCodeAt(0)])
9
+ pagination = new Paginator(data, 2, {perPage: 3})
10
+ pagination.records
11
+ pagination.locals
12
+ pagination.buttons
13
+ */
7
14
 
8
- Spine = this.Spine || require('spine');
9
15
 
10
- Model = Spine.Model;
16
+ (function() {
17
+ var Paginator, Spine, isArray;
11
18
 
12
19
  Paginator = (function() {
13
20
  Paginator.DEFAULT_PER_PAGE = 25;
@@ -22,6 +29,15 @@
22
29
 
23
30
  Paginator.RIGHT = 0;
24
31
 
32
+ Paginator.PAGE_TEXTS = {
33
+ first: 'first',
34
+ prev: 'prev',
35
+ current: 'current',
36
+ next: 'next',
37
+ last: 'last',
38
+ gap: 'gap'
39
+ };
40
+
25
41
  function Paginator(records, _page, options) {
26
42
  var outer_window;
27
43
 
@@ -29,6 +45,11 @@
29
45
  if (options == null) {
30
46
  options = {};
31
47
  }
48
+ if (!isArray(records)) {
49
+ records = [records];
50
+ }
51
+ this.originalRecords = records;
52
+ this.totalCount = this.originalRecords.length;
32
53
  this._page = parseInt(this._page);
33
54
  if (isNaN(this._page) || this._page <= 0) {
34
55
  this._page = 1;
@@ -50,8 +71,6 @@
50
71
  if (this.right === 0) {
51
72
  this.right = outer_window;
52
73
  }
53
- this.originalRecords = this.cloneArray(records);
54
- this.totalCount = this.originalRecords.length;
55
74
  this.skipbuildButtonsAndLocals = options.skipbuildButtonsAndLocals;
56
75
  this.records = [];
57
76
  this.buttons = [];
@@ -103,35 +122,6 @@
103
122
  return this.currentPage() >= this.lastPage();
104
123
  };
105
124
 
106
- Paginator.prototype.pages = function() {
107
- var currentPage, firstPage, last, lastPage, page, result, _i, _pages;
108
-
109
- currentPage = this.currentPage();
110
- firstPage = this.firstPage();
111
- lastPage = this.lastPage();
112
- _pages = [];
113
- last = null;
114
- for (page = _i = firstPage; firstPage <= lastPage ? _i <= lastPage : _i >= lastPage; page = firstPage <= lastPage ? ++_i : --_i) {
115
- result = this.buildPage(page, last, currentPage, firstPage, lastPage);
116
- if (result.isLeftOuter || result.isRightOuter || result.isInsideWindow) {
117
- last = null;
118
- } else {
119
- last = 'gap';
120
- }
121
- _pages.push(result);
122
- }
123
- return _pages;
124
- };
125
-
126
- Paginator.prototype.curPage = function() {
127
- var currentPage, firstPage, lastPage;
128
-
129
- currentPage = this.currentPage();
130
- firstPage = this.firstPage();
131
- lastPage = this.lastPage();
132
- return this.buildPage(currentPage, null, currentPage, firstPage, lastPage);
133
- };
134
-
135
125
  Paginator.prototype.limitValue = function() {
136
126
  if (this.perPage > this.totalCount) {
137
127
  this.perPage = this.totalCount;
@@ -163,10 +153,39 @@
163
153
  isLeftOuter: page <= this.left,
164
154
  isRightOuter: (lastPage - page) < this.right,
165
155
  isInsideWindow: Math.abs(currentPage - page) <= this.window,
166
- isWasTruncated: last === 'gap'
156
+ isWasTruncated: last === this.constructor.PAGE_TEXTS['gap']
167
157
  };
168
158
  };
169
159
 
160
+ Paginator.prototype.curPage = function() {
161
+ var currentPage, firstPage, lastPage;
162
+
163
+ currentPage = this.currentPage();
164
+ firstPage = this.firstPage();
165
+ lastPage = this.lastPage();
166
+ return this.buildPage(currentPage, null, currentPage, firstPage, lastPage);
167
+ };
168
+
169
+ Paginator.prototype.pages = function() {
170
+ var currentPage, firstPage, last, lastPage, page, result, _i, _pages;
171
+
172
+ currentPage = this.currentPage();
173
+ firstPage = this.firstPage();
174
+ lastPage = this.lastPage();
175
+ _pages = [];
176
+ last = null;
177
+ for (page = _i = firstPage; firstPage <= lastPage ? _i <= lastPage : _i >= lastPage; page = firstPage <= lastPage ? ++_i : --_i) {
178
+ result = this.buildPage(page, last, currentPage, firstPage, lastPage);
179
+ if (result.isLeftOuter || result.isRightOuter || result.isInsideWindow) {
180
+ last = null;
181
+ } else {
182
+ last = this.constructor.PAGE_TEXTS['gap'];
183
+ }
184
+ _pages.push(result);
185
+ }
186
+ return _pages;
187
+ };
188
+
170
189
  Paginator.prototype.buildButtonsAndLocals = function() {
171
190
  var curPage, page, pages, _buttons, _i, _len, _locals;
172
191
 
@@ -175,13 +194,13 @@
175
194
  curPage = this.curPage();
176
195
  pages = this.pages();
177
196
  if (!curPage.isFirst) {
178
- _buttons.push('first');
197
+ _buttons.push(this.constructor.PAGE_TEXTS['first']);
179
198
  _locals.hasFirst = true;
180
199
  } else {
181
200
  _locals.hasFirst = false;
182
201
  }
183
202
  if (!curPage.isFirst) {
184
- _buttons.push('prev');
203
+ _buttons.push(this.constructor.PAGE_TEXTS['prev']);
185
204
  _locals.hasPrev = true;
186
205
  } else {
187
206
  _locals.hasPrev = false;
@@ -191,7 +210,7 @@
191
210
  page = pages[_i];
192
211
  if (page.isLeftOuter || page.isRightOuter || page.isInsideWindow) {
193
212
  if (page.isCurrent) {
194
- _buttons.push('current');
213
+ _buttons.push(this.constructor.PAGE_TEXTS['current']);
195
214
  _locals.pages.push({
196
215
  number: page.number,
197
216
  current: true
@@ -204,7 +223,7 @@
204
223
  });
205
224
  }
206
225
  } else if (!page.isWasTruncated) {
207
- _buttons.push('gap');
226
+ _buttons.push(this.constructor.PAGE_TEXTS['gap']);
208
227
  _locals.pages.push({
209
228
  number: page.number,
210
229
  gap: true
@@ -212,13 +231,13 @@
212
231
  }
213
232
  }
214
233
  if (!curPage.isLast) {
215
- _buttons.push('next');
234
+ _buttons.push(this.constructor.PAGE_TEXTS['next']);
216
235
  _locals.hasNext = true;
217
236
  } else {
218
237
  _locals.hasNext = false;
219
238
  }
220
239
  if (!curPage.isLast) {
221
- _buttons.push('last');
240
+ _buttons.push(this.constructor.PAGE_TEXTS['last']);
222
241
  _locals.hasLast = true;
223
242
  } else {
224
243
  _locals.hasLast = false;
@@ -233,39 +252,58 @@
233
252
  return this.locals = _locals;
234
253
  };
235
254
 
236
- Paginator.prototype.cloneArray = function(array) {
237
- var value, _i, _len, _results;
238
-
239
- _results = [];
240
- for (_i = 0, _len = array.length; _i < _len; _i++) {
241
- value = array[_i];
242
- _results.push(value.clone());
243
- }
244
- return _results;
245
- };
246
-
247
255
  return Paginator;
248
256
 
249
257
  })();
250
258
 
251
- Extend = {
252
- _perPaginateRecords: function() {
253
- return this.records;
254
- },
255
- page: function(n, options) {
256
- if (options == null) {
257
- options = {};
258
- }
259
- return new Paginator(this._perPaginateRecords(), n, options);
260
- }
261
- };
262
-
263
- Model.Paginator = {
264
- extended: function() {
265
- return this.extend(Extend);
266
- }
259
+ isArray = function(value) {
260
+ return Object.prototype.toString.call(value) === '[object Array]';
267
261
  };
268
262
 
269
- Spine.Paginator = Paginator;
263
+ Paginator.isArray = isArray;
264
+
265
+ if (this.MyPaginatorName != null) {
266
+ this[this.MyPaginatorName] = Paginator;
267
+ }
268
+
269
+ if (this.Spine != null) {
270
+ /*
271
+ # Spine Usage
272
+
273
+ App = {}
274
+
275
+ class App.User extends Spine.Model
276
+ @configure 'User', 'name'
277
+ @extend Spine.Model.Paginator
278
+
279
+ data = ({name: String.fromCharCode(num)} for num in ['a'.charCodeAt(0)..'z'.charCodeAt(0)])
280
+
281
+ App.User.refresh(data)
282
+ pagination = App.User.page(2).per(5) #or App.User.page(2, {perPage: 5})
283
+ pagination.records
284
+ pagination.locals
285
+ pagination.buttons
286
+ App.User.PAGINATION = pagination
287
+ */
288
+
289
+ Paginator.SpineModelExtend = {
290
+ page: function(n, options) {
291
+ if (options == null) {
292
+ options = {};
293
+ }
294
+ return new Paginator(this._perPaginateRecords(), n, options);
295
+ },
296
+ _perPaginateRecords: function() {
297
+ return this.all();
298
+ }
299
+ };
300
+ Spine = this.Spine;
301
+ Spine.Paginator = Paginator;
302
+ Spine.Model.Paginator = {
303
+ extended: function() {
304
+ return this.extend(Paginator.SpineModelExtend);
305
+ }
306
+ };
307
+ }
270
308
 
271
309
  }).call(this);