spine_paginator 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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);