9e1490ab by Adam Heath

Initial version of files.

1 parent 5a981a88
1 .*.swp
2 .tmp/
3 dist/
4 node_modules/
5 src/lib/
6 .grunt/
7 _SpecRunner.html
1 /* global module */
2
3 module.exports = function (grunt) {
4 /* global require */
5 'use strict';
6
7 var config = {};
8 config.base = 'src';
9 config.jshint = {
10 options: {
11 },
12 browserOptions: {
13 },
14 };
15 config.jscs = {
16 options: {
17 validateIndentation: 4,
18 reporter: 'console',
19 maxErrors: -1,
20 },
21 };
22 config.bower = {
23 directory: 'lib/bower',
24 };
25 config.jasmine = {
26 withCoverage: true,
27 };
28 var montyPython = require('grunt-monty-python')(grunt);
29 montyPython.createConfig(config);
30 };
1 {
2 "name": "search-tools",
3 "version": "2016.07.26-0",
4 "authors": [
5 "Adam Heath <doogie@brainfood.com>"
6 ],
7 "main": [
8 "src/scripts/search-tools/*.js"
9 ],
10 "ignore": [
11 "**/.*",
12 "node_modules",
13 "src/lib",
14 "src/scripts/**/*.spec.js",
15 "src/scripts/config.js",
16 "src/scripts/main.js"
17 ],
18 "dependencies": {
19 "backbone": "",
20 "jquery": "",
21 "requirejs": "",
22 "underscore": ""
23 }
24 }
1 {
2 "name": "search-tools",
3 "version": "2016.07.26-0",
4 "dependencies": {
5 "requirejs": ""
6 },
7 "devDependencies": {
8 "grunt": "~0",
9 "grunt-monty-python": "git+http://gitlab.brainfood.com/brainfood/grunt-monty-python.git",
10 "rivets": ""
11 },
12 "engines": {
13 "node": ">=0.8.0"
14 }
15 }
16
1 /* global require:true */
2 var require;
3 require = (function() {
4 'use strict';
5
6 var require = {
7 baseUrl: 'scripts',
8 config: {
9 },
10 shim: {
11 backbone: {
12 deps: ['underscore'],
13 exports: 'Backbone',
14 },
15 underscore: {
16 exports: '_',
17 },
18 },
19 paths: {
20 backbone: '../lib/bower/backbone/backbone',
21 jquery: '../lib/bower/jquery/dist/jquery',
22 underscore: '../lib/bower/underscore/underscore',
23 },
24 };
25
26 return require;
27 })();
1 /* global require */
2 define(function(require) {
3 'use strict';
4 });
1 define(function(require) {
2 'use strict';
3 var _ = require('underscore');
4 var Backbone = require('backbone');
5 var Util = require('./Util');
6
7 var Paginator = Backbone.Model.extend({
8 defaults: function defaults() {
9 return {
10 hasNext: false,
11 hasNextJump: undefined,
12 hasPrevious: false,
13 hasPreviousJump: undefined,
14 leadingPageCount: 4,
15 nextJumpPage: undefined,
16 nextPage: undefined,
17 pages: [],
18 pageJump: 5,
19 previousJumpPage: undefined,
20 previousPage: undefined,
21 totalPages: 0,
22 trailingPageCount: 5,
23 };
24 },
25 initialize: function(data, options) {
26 var buildPages = _.bind(function buildPages() {
27 var source = this.get('source');
28 if (!source) {
29 return;
30 }
31 var currentPage = parseInt(source.get('currentPage'));
32 var pageSize = parseInt(source.get('pageSize'));
33 var totalCount = parseInt(source.get('totalCount'));
34 if (!totalCount) {
35 return;
36 }
37 var pages = [];
38 var totalPages = Math.floor((totalCount + pageSize - 1) / pageSize);
39 if (currentPage < 0) {
40 source.set('currentPage', 1);
41 return;
42 } else if (currentPage > totalPages) {
43 source.set('currentPage', totalPages);
44 return;
45 }
46 function addPage(self, i) {
47 pages.push({
48 current: i === currentPage,
49 jump: _.bind(function() {
50 this.get('source').set('currentPage', i);
51 return true;
52 }, self),
53 number: i,
54 });
55 }
56 var startAt = currentPage - this.get('leadingPageCount'), endAt = currentPage + this.get('trailingPageCount');
57 if (startAt < 1) {
58 endAt += (1 - startAt);
59 }
60 if (endAt > totalPages) {
61 startAt -= endAt - totalPages - 1;
62 endAt = totalPages + 1;
63 }
64 if (startAt < 1) {
65 startAt = 1;
66 }
67
68 for (var i = startAt; i < endAt; i++) {
69 addPage(this, i);
70 }
71 var hasPrevious = currentPage > 1;
72 var hasNext = currentPage < totalPages;
73 var pageJump = this.get('pageJump');
74 var nextJumpPage, previousJumpPage, hasNextJump, hasPreviousJump;
75 if (pageJump) {
76 nextJumpPage = currentPage + pageJump;
77 previousJumpPage = currentPage - pageJump;
78 hasNextJump = nextJumpPage < totalPages;
79 hasPreviousJump = previousJumpPage > 0;
80 } else {
81 hasNextJump = false;
82 hasPreviousJump = false;
83 }
84 this.set({
85 hasNext: hasNext,
86 hasNextJump: hasNextJump,
87 hasPrevious: hasPrevious,
88 hasPreviousJump: hasPreviousJump,
89 nextJumpPage: hasNextJump ? nextJumpPage : undefined,
90 nextPage: hasNext ? currentPage + 1 : undefined,
91 pages: pages,
92 previousJumpPage: hasNextJump ? previousJumpPage : undefined,
93 previousPage: hasPrevious ? currentPage - 1 : undefined,
94 totalPages: totalPages,
95 });
96 }, this);
97 this.on('change:leadingPageCount change:trailingPageCount', buildPages);
98 var installActions = _.bind(function installActions(eventName, nextName, actNextName, hasNextName, previousName, actPreviousName, hasPreviousName, pageCount) {
99 this.on(eventName, function() {
100 var hasNext = this.get(hasNextName);
101 var hasPrevious = this.get(hasPreviousName);
102 var next, previous;
103 if (hasNext) {
104 next = _.bind(function(e) {
105 Util.preventDefault(e);
106 var source = this.get('source');
107 source.set('currentPage', source.get('currentPage') + pageCount);
108 return false;
109 }, this);
110 } else {
111 next = Util.eventFalse;
112 }
113 if (hasPrevious) {
114 previous = _.bind(function(e) {
115 Util.preventDefault(e);
116 var source = this.get('source');
117 source.set('currentPage', source.get('currentPage') - pageCount);
118 return false;
119 }, this);
120 } else {
121 previous = Util.eventFalse;
122 }
123 this.set(nextName, next);
124 this.set(previousName, previous);
125 }, this);
126 this[actNextName] = _.bind(function() {
127 return this.get(nextName)();
128 }, this);
129 this[actPreviousName] = _.bind(function() {
130 return this.get(previousName)();
131 }, this);
132 this.trigger(eventName.split(' ')[0]);
133 }, this);
134 this.on('change:pageJump', function() {
135 var pageJump = this.get('pageJump');
136 installActions('change:hasNextJump change:hasPreviousJump', 'nextJump', 'actNextJump', 'hasNextJump', 'previousJump', 'actPreviousJump', 'hasPreviousJump', pageJump);
137 }, this);
138 installActions('change:hasNext change:hasPrevious', 'next', 'actNext', 'hasNext', 'previous', 'actPrevious', 'hasPrevious', 1);
139 this.on('change:source', function() {
140 var oldSource = this.previous('source');
141 if (oldSource) {
142 this.stopListening(oldSource);
143 }
144 this.listenTo(this.get('source'), 'change:pageSize change:currentPage change:totalCount', buildPages);
145 });
146 var r = Paginator.__super__.initialize.apply(this, arguments);
147 buildPages();
148 this.trigger('change:pageJump');
149 this.trigger('change:source');
150 return r;
151 }
152 });
153 return Paginator;
154 });
1 define(function(require) {
2 'use strict';
3 var _ = require('underscore');
4 var Backbone = require('backbone');
5 var Paginator = require('search-tools/Paginator');
6
7 describe('Paginator', function() {
8 it('loads', function() {
9 expect(Paginator).toBeDefined();
10 });
11 describe(':pages', function() {
12 it('default value is not shared globally', function() {
13 var p1 = new Paginator(), p2 = new Paginator();
14 expect(p1.get('pages')).not.toBe(p2.get('pages'));
15 });
16 });
17 describe('singleton', function() {
18 var p, source;
19
20 function checkHas(hasNext, hasNextJump, hasPrevious, hasPreviousJump) {
21 var wanted = {
22 hasNext: hasNext,
23 hasNextJump: hasNextJump,
24 hasPrevious: hasPrevious,
25 hasPreviousJump: hasPreviousJump,
26 };
27 it('has', function() {
28 var got = {
29 hasNext: p.get('hasNext'),
30 hasNextJump: p.get('hasNextJump'),
31 hasPrevious: p.get('hasPrevious'),
32 hasPreviousJump: p.get('hasPreviousJump'),
33 };
34 expect(got).toEqual(wanted);
35 });
36 }
37 function checkPages(wantedLength, offset, currentPage) {
38 var pages;
39 beforeEach(function() {
40 pages = p.get('pages');
41 });
42 //console.log(JSON.stringify(pages));
43 var wanted = { length: wantedLength, pages: [] };
44 for (var i = 0; i < wantedLength; i++) {
45 wanted.pages[i] = { current: i + 1 === currentPage, number: i + 1 + offset };
46 }
47 it('pages', function() {
48 pages = p.get('pages');
49 var got = { length: pages.length, pages: [] };
50 for (var i = 0; i < pages.length; i++) {
51 var page = pages[i];
52 got.pages[i] = { current: page.current, number: page.number };
53 }
54 expect(got).toEqual(wanted);
55 });
56 }
57
58 beforeEach(function() {
59 source = new Backbone.Model({currentPage: 1, pageSize: 10, totalCount: 0});
60 p = new Paginator({source: source});
61 });
62 describe('default settings', function() {
63 checkHas(false, undefined, false, undefined);
64 checkPages(0, 0, 1);
65 });
66 describe('35 items', function() {
67 beforeEach(function() {
68 source.set({totalCount:35});
69 });
70 describe('initial settings', function() {
71 checkHas(true, false, false, false);
72 checkPages(4, 0, 1);
73 });
74 describe('clamping', function() {
75 describe('set currentPage=5', function() {
76 beforeEach(function() {
77 source.set({currentPage: 5});
78 });
79 checkHas(false, false, true, false);
80 checkPages(4, 0, 4);
81 });
82 describe('set currentPage=-1', function() {
83 beforeEach(function() {
84 source.set({currentPage: -1});
85 });
86 checkHas(true, false, false, false);
87 checkPages(4, 0, 1);
88 });
89 });
90 describe('next[1]', function() {
91 beforeEach(function() {
92 p.actNext();
93 });
94 checkPages(4, 0, 2);
95 describe('previous', function() {
96 beforeEach(function() {
97 p.actPrevious();
98 });
99 checkHas(true, false, false, false);
100 checkPages(4, 0, 1);
101 });
102 describe('next[2]', function() {
103 beforeEach(function() {
104 p.actNext();
105 p.actNext();
106 });
107 checkHas(false, false, true, false);
108 checkPages(4, 0, 4);
109 describe('next[1] - clamp', function() {
110 beforeEach(function() {
111 p.actNext();
112 });
113 checkHas(false, false, true, false);
114 checkPages(4, 0, 4);
115 });
116 describe('page[0].jump', function() {
117 beforeEach(function() {
118 p.get('pages')[0].jump();
119 });
120 checkHas(true, false, false, false);
121 checkPages(4, 0, 1);
122 });
123 describe('page[3].jump', function() {
124 beforeEach(function() {
125 p.get('pages')[3].jump();
126 });
127 checkHas(false, false, true, false);
128 checkPages(4, 0, 4);
129 });
130 describe('decrease to 25 items', function() {
131 beforeEach(function() {
132 source.set({totalCount:25});
133 });
134 checkHas(false, false, true, false);
135 checkPages(3, 0, 3);
136 describe('increase to 150 items', function() {
137 beforeEach(function() {
138 source.set({totalCount:150});
139 });
140 checkHas(true, true, true, false);
141 checkPages(9, 0, 3);
142 });
143 });
144 });
145 });
146 describe('previous[1]', function() {
147 beforeEach(function() {
148 p.actPrevious();
149 });
150 checkHas(true, false, false, false);
151 checkPages(4, 0, 1);
152 });
153 });
154 describe('150 items', function() {
155 beforeEach(function() {
156 source.set({totalCount:150});
157 });
158 checkHas(true, true, false, false);
159 checkPages(9, 0, 1);
160 describe('page[7].jump', function() {
161 beforeEach(function() {
162 p.get('pages')[7].jump();
163 });
164 checkHas(true, true, true, true);
165 checkPages(9, 3, 5);
166 describe('previousJump', function() {
167 beforeEach(function() {
168 p.actPreviousJump();
169 });
170 checkHas(true, true, true, false);
171 checkPages(9, 0, 3);
172 });
173 });
174 });
175 describe('no page jump', function() {
176 beforeEach(function() {
177 p.set({pageJump: false});
178 source.set({totalCount:150});
179 });
180 checkHas(true, false, false, false);
181 checkPages(9, 0, 1);
182 });
183 });
184 });
185 });
1 define(function(require) {
2 'use strict';
3
4 function preventDefault(e) {
5 if (e) {
6 e.preventDefault();
7 }
8 }
9
10 function eventFalse(e) {
11 preventDefault(e);
12 return false;
13 }
14 return {
15 preventDefault: preventDefault,
16 eventFalse: eventFalse,
17 };
18 });
1 define(function(require) {
2 'use strict';
3 var _ = require('underscore');
4 var Util = require('search-tools/Util');
5
6 describe('Util', function() {
7 it('loads', function() {
8 expect(Util).toBeDefined();
9 });
10
11 it('exported items', function() {
12 var keys = {};
13 _.each(Util, function(value, key) {
14 keys[key] = true;
15 });
16 expect(keys).toEqual({
17 preventDefault: true,
18 eventFalse: true,
19 });
20 });
21 describe('methods', function() {
22 var e;
23 beforeEach(function() {
24 e = {preventDefault: jasmine.createSpy('preventDefault')};
25 });
26 it('preventDefault(null)', function() {
27 var r = Util.preventDefault(null);
28 expect(r).toBe(undefined);
29 expect(e.preventDefault).not.toHaveBeenCalled();
30 });
31 it('preventDefault(undefined)', function() {
32 var r = Util.preventDefault(undefined);
33 expect(r).toBe(undefined);
34 expect(e.preventDefault).not.toHaveBeenCalled();
35 });
36 it('preventDefault(e)', function() {
37 var r = Util.preventDefault(e);
38 expect(r).toBe(undefined);
39 expect(e.preventDefault).toHaveBeenCalled();
40 });
41 it('eventFalse(null)', function() {
42 var r = Util.eventFalse(null);
43 expect(r).toBe(false);
44 expect(e.preventDefault).not.toHaveBeenCalled();
45 });
46 it('eventFalse(undefined)', function() {
47 var r = Util.eventFalse(undefined);
48 expect(r).toBe(false);
49 expect(e.preventDefault).not.toHaveBeenCalled();
50 });
51 it('preventDefault(e)', function() {
52 var r = Util.eventFalse(e);
53 expect(r).toBe(false);
54 expect(e.preventDefault).toHaveBeenCalled();
55 });
56 });
57 });
58 });