backgridjs-rails 0.2.6 → 0.3.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +6 -14
- data/lib/backgridjs-rails/version.rb +1 -1
- data/vendor/assets/javascripts/backgrid-extensions/backgrid-filter.js +192 -49
- data/vendor/assets/javascripts/backgrid-extensions/backgrid-moment-cell.js +15 -5
- data/vendor/assets/javascripts/backgrid-extensions/backgrid-paginator.js +341 -112
- data/vendor/assets/javascripts/backgrid-extensions/backgrid-select-all.js +109 -32
- data/vendor/assets/javascripts/backgrid-extensions/backgrid-select2-cell.js +42 -14
- data/vendor/assets/javascripts/backgrid-extensions/backgrid-text-cell.js +18 -9
- data/vendor/assets/javascripts/backgrid.js +689 -336
- data/vendor/assets/stylesheets/backgrid-extensions/backgrid-filter.css +181 -7
- data/vendor/assets/stylesheets/backgrid-extensions/backgrid-moment-cell.css +2 -1
- data/vendor/assets/stylesheets/backgrid-extensions/backgrid-paginator.css +5 -5
- data/vendor/assets/stylesheets/backgrid-extensions/backgrid-select-all.css +2 -1
- data/vendor/assets/stylesheets/backgrid-extensions/backgrid-select2-cell.css +1 -1
- data/vendor/assets/stylesheets/backgrid-extensions/backgrid-text-cell.css +3 -3
- data/vendor/assets/stylesheets/backgrid.css +35 -10
- metadata +18 -21
- data/lib/backgridjs-rails.rb~ +0 -2
- data/lib/backgridjs-rails/engine.rb~ +0 -8
- data/lib/backgridjs-rails/version.rb~ +0 -3
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
metadata.gz: !binary |-
|
9
|
-
MWY3MDhiNDhjNDkyOTQ1ZTBiNDM5MTQ0YWUwYWUwMDhmOWNkNjQ4YmFhNTdm
|
10
|
-
NTljZGUyYzMxNzM4NDg0MGIyNDJjY2RkZmM4OGEzOThjNjc2OTcwYThlNTNj
|
11
|
-
Y2FlYjc5ZDRhYzM2MDg3ODQ3ODg1MDc0ODA4ODFiYjAzMzMzMTU=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
YzNlNjQ4MTg5YTg1N2Q5ZDE4YTkyYmJkOGE1N2ZmODEwMjg1NDJjMDc2MDc2
|
14
|
-
MDk5MzY3ZTRjYTU1OWU0M2FhYzc2YjZiMmJhMmEzMWE5NWY5MGIxODQ2NzQy
|
15
|
-
N2Y4ZDIwY2E3YWY1YWQ0Y2MyNTMxMjMzOWQ4MWQ0NTg2YjkwMDk=
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1ab7aafbde55ffeca00bdf228fce029974a92330
|
4
|
+
data.tar.gz: b800be2fe7b2eba3a228ee2cd1b3a17991dc89c5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c78c96f141e13784f227aac7c34d99e8a14a382c20304de71986a45f04b2f14cd52481fec128e8b2ccfa44e490dc9bd099a412ab1825e7076f9d6c48180c140a
|
7
|
+
data.tar.gz: 4f0f4a01bf087193b623468ca02634e6ca426bb09aecb37a9660c3f1a1f82028098a9031a8383fd7804a47e0045d10f0c80e4a199527ebf0b0061c90f7740642
|
@@ -5,8 +5,25 @@
|
|
5
5
|
Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors
|
6
6
|
Licensed under the MIT @license.
|
7
7
|
*/
|
8
|
-
|
9
|
-
|
8
|
+
(function (root, factory) {
|
9
|
+
|
10
|
+
// CommonJS
|
11
|
+
if (typeof exports == "object") {
|
12
|
+
(function () {
|
13
|
+
var lunr;
|
14
|
+
try { lunr = require("lunr"); } catch (e) {}
|
15
|
+
module.exports = factory(require("underscore"),
|
16
|
+
require("backbone"),
|
17
|
+
require("backgrid"),
|
18
|
+
lunr);
|
19
|
+
}());
|
20
|
+
}
|
21
|
+
// Browser
|
22
|
+
else {
|
23
|
+
factory(root._, root.Backbone, root.Backgrid, root.lunr);
|
24
|
+
}
|
25
|
+
|
26
|
+
}(this, function (_, Backbone, Backgrid, lunr) {
|
10
27
|
|
11
28
|
"use strict";
|
12
29
|
|
@@ -25,62 +42,140 @@
|
|
25
42
|
className: "backgrid-filter form-search",
|
26
43
|
|
27
44
|
/** @property {function(Object, ?Object=): string} template */
|
28
|
-
template: _.template('<
|
45
|
+
template: _.template('<span class="search"> </span><input type="search" <% if (placeholder) { %> placeholder="<%- placeholder %>" <% } %> name="<%- name %>" <% if (value) { %> value="<%- value %>" <% } %>/><a class="clear" data-backgrid-action="clear" href="#">×</a>', null, {variable: null}),
|
29
46
|
|
30
47
|
/** @property */
|
31
48
|
events: {
|
32
|
-
"
|
49
|
+
"keyup input[type=search]": "showClearButtonMaybe",
|
50
|
+
"click a[data-backgrid-action=clear]": "clear",
|
33
51
|
"submit": "search"
|
34
52
|
},
|
35
53
|
|
36
54
|
/** @property {string} [name='q'] Query key */
|
37
55
|
name: "q",
|
38
56
|
|
39
|
-
/** @property
|
57
|
+
/** @property {string} [value] The search box value. */
|
58
|
+
value: null,
|
59
|
+
|
60
|
+
/**
|
61
|
+
@property {string} [placeholder] The HTML5 placeholder to appear beneath
|
62
|
+
the search box.
|
63
|
+
*/
|
40
64
|
placeholder: null,
|
41
65
|
|
42
66
|
/**
|
43
67
|
@param {Object} options
|
44
68
|
@param {Backbone.Collection} options.collection
|
45
|
-
@param {
|
46
|
-
@param {
|
69
|
+
@param {string} [options.name]
|
70
|
+
@param {string} [options.value]
|
71
|
+
@param {string} [options.placeholder]
|
72
|
+
@param {function(Object): string} [options.template]
|
47
73
|
*/
|
48
74
|
initialize: function (options) {
|
49
|
-
|
50
|
-
Backbone.View.prototype.initialize.apply(this, arguments);
|
75
|
+
ServerSideFilter.__super__.initialize.apply(this, arguments);
|
51
76
|
this.name = options.name || this.name;
|
77
|
+
this.value = options.value || this.value;
|
52
78
|
this.placeholder = options.placeholder || this.placeholder;
|
79
|
+
this.template = options.template || this.template;
|
53
80
|
|
81
|
+
// Persist the query on pagination
|
54
82
|
var collection = this.collection, self = this;
|
55
83
|
if (Backbone.PageableCollection &&
|
56
84
|
collection instanceof Backbone.PageableCollection &&
|
57
85
|
collection.mode == "server") {
|
58
86
|
collection.queryParams[this.name] = function () {
|
59
|
-
return self
|
87
|
+
return self.searchBox().val() || null;
|
60
88
|
};
|
61
89
|
}
|
62
90
|
},
|
63
91
|
|
92
|
+
/**
|
93
|
+
Event handler. Clear the search box and reset the internal search value.
|
94
|
+
*/
|
95
|
+
clearSearchBox: function() {
|
96
|
+
this.value = null;
|
97
|
+
this.searchBox().val(null);
|
98
|
+
this.showClearButtonMaybe();
|
99
|
+
},
|
100
|
+
|
101
|
+
/**
|
102
|
+
Event handler. Show the clear button when the search box has text, hide
|
103
|
+
it otherwise.
|
104
|
+
*/
|
105
|
+
showClearButtonMaybe: function () {
|
106
|
+
var $clearButton = this.clearButton();
|
107
|
+
var searchTerms = this.searchBox().val();
|
108
|
+
if (searchTerms) $clearButton.show();
|
109
|
+
else $clearButton.hide();
|
110
|
+
},
|
111
|
+
|
112
|
+
/**
|
113
|
+
Returns the search input box.
|
114
|
+
*/
|
115
|
+
searchBox: function () {
|
116
|
+
return this.$el.find("input[type=search]");
|
117
|
+
},
|
118
|
+
|
119
|
+
/**
|
120
|
+
Returns the clear button.
|
121
|
+
*/
|
122
|
+
clearButton: function () {
|
123
|
+
return this.$el.find("a[data-backgrid-action=clear]");
|
124
|
+
},
|
125
|
+
|
126
|
+
|
127
|
+
/**
|
128
|
+
Returns the current search query.
|
129
|
+
*/
|
130
|
+
query: function() {
|
131
|
+
this.value = this.searchBox().val();
|
132
|
+
return this.value;
|
133
|
+
},
|
134
|
+
|
64
135
|
/**
|
65
136
|
Upon search form submission, this event handler constructs a query
|
66
137
|
parameter object and pass it to Collection#fetch for server-side
|
67
138
|
filtering.
|
139
|
+
|
140
|
+
If the collection is a PageableCollection, searching will go back to the
|
141
|
+
first page.
|
68
142
|
*/
|
69
143
|
search: function (e) {
|
70
144
|
if (e) e.preventDefault();
|
145
|
+
|
71
146
|
var data = {};
|
72
|
-
|
73
|
-
this.
|
147
|
+
var query = this.query();
|
148
|
+
if (query) data[this.name] = query;
|
149
|
+
|
150
|
+
var collection = this.collection;
|
151
|
+
|
152
|
+
// go back to the first page on search
|
153
|
+
if (Backbone.PageableCollection &&
|
154
|
+
collection instanceof Backbone.PageableCollection) {
|
155
|
+
collection.getFirstPage({data: data, reset: true, fetch: true});
|
156
|
+
}
|
157
|
+
else collection.fetch({data: data, reset: true});
|
74
158
|
},
|
75
159
|
|
76
160
|
/**
|
77
|
-
Event handler for the
|
161
|
+
Event handler for the clear button. Clears the search box and refetch the
|
78
162
|
collection.
|
163
|
+
|
164
|
+
If the collection is a PageableCollection, clearing will go back to the
|
165
|
+
first page.
|
79
166
|
*/
|
80
167
|
clear: function (e) {
|
81
168
|
if (e) e.preventDefault();
|
82
|
-
this
|
83
|
-
|
169
|
+
this.clearSearchBox();
|
170
|
+
|
171
|
+
var collection = this.collection;
|
172
|
+
|
173
|
+
// go back to the first page on clear
|
174
|
+
if (Backbone.PageableCollection &&
|
175
|
+
collection instanceof Backbone.PageableCollection) {
|
176
|
+
collection.getFirstPage({reset: true, fetch: true});
|
177
|
+
}
|
178
|
+
else collection.fetch({reset: true});
|
84
179
|
},
|
85
180
|
|
86
181
|
/**
|
@@ -93,6 +188,7 @@
|
|
93
188
|
placeholder: this.placeholder,
|
94
189
|
value: this.value
|
95
190
|
}));
|
191
|
+
this.showClearButtonMaybe();
|
96
192
|
this.delegateEvents();
|
97
193
|
return this;
|
98
194
|
}
|
@@ -110,27 +206,26 @@
|
|
110
206
|
var ClientSideFilter = Backgrid.Extension.ClientSideFilter = ServerSideFilter.extend({
|
111
207
|
|
112
208
|
/** @property */
|
113
|
-
events: {
|
114
|
-
"click
|
209
|
+
events: _.extend({}, ServerSideFilter.prototype.events, {
|
210
|
+
"click a[data-backgrid-action=clear]": function (e) {
|
115
211
|
e.preventDefault();
|
116
212
|
this.clear();
|
117
213
|
},
|
118
|
-
"
|
119
|
-
"keyup input[type=text]": "search",
|
214
|
+
"keydown input[type=search]": "search",
|
120
215
|
"submit": function (e) {
|
121
216
|
e.preventDefault();
|
122
217
|
this.search();
|
123
218
|
}
|
124
|
-
},
|
219
|
+
}),
|
125
220
|
|
126
221
|
/**
|
127
|
-
@property {?Array.<string>} A list of model field names to
|
128
|
-
for matches. If null, all of the fields will be searched.
|
222
|
+
@property {?Array.<string>} [fields] A list of model field names to
|
223
|
+
search for matches. If null, all of the fields will be searched.
|
129
224
|
*/
|
130
225
|
fields: null,
|
131
226
|
|
132
227
|
/**
|
133
|
-
@property wait The time in milliseconds to wait since
|
228
|
+
@property [wait=149] The time in milliseconds to wait since the last
|
134
229
|
change to the search box's value before searching. This value can be
|
135
230
|
adjusted depending on how often the search box is used and how large the
|
136
231
|
search index is.
|
@@ -143,23 +238,20 @@
|
|
143
238
|
|
144
239
|
@param {Object} options
|
145
240
|
@param {Backbone.Collection} options.collection
|
146
|
-
@param {
|
147
|
-
@param {
|
148
|
-
@param {
|
241
|
+
@param {string} [options.placeholder]
|
242
|
+
@param {string} [options.fields]
|
243
|
+
@param {string} [options.wait=149]
|
149
244
|
*/
|
150
245
|
initialize: function (options) {
|
151
|
-
|
246
|
+
ClientSideFilter.__super__.initialize.apply(this, arguments);
|
152
247
|
|
153
248
|
this.fields = options.fields || this.fields;
|
154
249
|
this.wait = options.wait || this.wait;
|
155
250
|
|
156
251
|
this._debounceMethods(["search", "clear"]);
|
157
252
|
|
158
|
-
var collection = this.collection;
|
253
|
+
var collection = this.collection = this.collection.fullCollection || this.collection;
|
159
254
|
var shadowCollection = this.shadowCollection = collection.clone();
|
160
|
-
shadowCollection.url = collection.url;
|
161
|
-
shadowCollection.sync = collection.sync;
|
162
|
-
shadowCollection.parse = collection.parse;
|
163
255
|
|
164
256
|
this.listenTo(collection, "add", function (model, collection, options) {
|
165
257
|
shadowCollection.add(model, options);
|
@@ -167,9 +259,14 @@
|
|
167
259
|
this.listenTo(collection, "remove", function (model, collection, options) {
|
168
260
|
shadowCollection.remove(model, options);
|
169
261
|
});
|
170
|
-
this.listenTo(collection, "sort
|
262
|
+
this.listenTo(collection, "sort", function (col) {
|
263
|
+
if (!this.searchBox().val()) shadowCollection.reset(col.models);
|
264
|
+
});
|
265
|
+
this.listenTo(collection, "reset", function (col, options) {
|
171
266
|
options = _.extend({reindex: true}, options || {});
|
172
|
-
if (options.reindex
|
267
|
+
if (options.reindex && options.from == null && options.to == null) {
|
268
|
+
shadowCollection.reset(col.models);
|
269
|
+
}
|
173
270
|
});
|
174
271
|
},
|
175
272
|
|
@@ -187,22 +284,47 @@
|
|
187
284
|
this.delegateEvents();
|
188
285
|
},
|
189
286
|
|
287
|
+
/**
|
288
|
+
Constructs a Javascript regular expression object for #makeMatcher.
|
289
|
+
|
290
|
+
This default implementation takes a query string and returns a Javascript
|
291
|
+
RegExp object that matches any of the words contained in the query string
|
292
|
+
case-insensitively. Override this method to return a different regular
|
293
|
+
expression matcher if this behavior is not desired.
|
294
|
+
|
295
|
+
@param {string} query The search query in the search box.
|
296
|
+
@return {RegExp} A RegExp object to match against model #fields.
|
297
|
+
*/
|
298
|
+
makeRegExp: function (query) {
|
299
|
+
return new RegExp(query.trim().split(/\s+/).join("|"), "i");
|
300
|
+
},
|
301
|
+
|
190
302
|
/**
|
191
303
|
This default implementation takes a query string and returns a matcher
|
192
304
|
function that looks for matches in the model's #fields or all of its
|
193
305
|
fields if #fields is null, for any of the words in the query
|
194
|
-
case-insensitively
|
306
|
+
case-insensitively using the regular expression object returned from
|
307
|
+
#makeRegExp.
|
308
|
+
|
309
|
+
Most of time, you'd want to override the regular expression used for
|
310
|
+
matching. If so, please refer to the #makeRegExp documentation,
|
311
|
+
otherwise, you can override this method to return a custom matching
|
312
|
+
function.
|
195
313
|
|
196
314
|
Subclasses overriding this method must take care to conform to the
|
197
|
-
signature of the matcher function.
|
198
|
-
|
199
|
-
|
315
|
+
signature of the matcher function. The matcher function is a function
|
316
|
+
that takes a model as paramter and returns true if the model matches a
|
317
|
+
search, or false otherwise.
|
318
|
+
|
319
|
+
In addition, when the matcher function is called, its context will be
|
320
|
+
bound to this ClientSideFilter object so it has access to the filter's
|
321
|
+
attributes and methods.
|
200
322
|
|
201
323
|
@param {string} query The search query in the search box.
|
202
324
|
@return {function(Backbone.Model):boolean} A matching function.
|
203
325
|
*/
|
204
326
|
makeMatcher: function (query) {
|
205
|
-
var regexp =
|
327
|
+
var regexp = this.makeRegExp(query);
|
206
328
|
return function (model) {
|
207
329
|
var keys = this.fields || model.keys();
|
208
330
|
for (var i = 0, l = keys.length; i < l; i++) {
|
@@ -216,18 +338,28 @@
|
|
216
338
|
Takes the query from the search box, constructs a matcher with it and
|
217
339
|
loops through collection looking for matches. Reset the given collection
|
218
340
|
when all the matches have been found.
|
341
|
+
|
342
|
+
If the collection is a PageableCollection, searching will go back to the
|
343
|
+
first page.
|
219
344
|
*/
|
220
345
|
search: function () {
|
221
|
-
var matcher = _.bind(this.makeMatcher(this
|
222
|
-
this.collection
|
346
|
+
var matcher = _.bind(this.makeMatcher(this.query()), this);
|
347
|
+
var col = this.collection;
|
348
|
+
if (col.pageableCollection) col.pageableCollection.getFirstPage({silent: true});
|
349
|
+
col.reset(this.shadowCollection.filter(matcher), {reindex: false});
|
223
350
|
},
|
224
351
|
|
225
352
|
/**
|
226
353
|
Clears the search box and reset the collection to its original.
|
354
|
+
|
355
|
+
If the collection is a PageableCollection, clearing will go back to the
|
356
|
+
first page.
|
227
357
|
*/
|
228
358
|
clear: function () {
|
229
|
-
this
|
230
|
-
this.collection
|
359
|
+
this.clearSearchBox();
|
360
|
+
var col = this.collection;
|
361
|
+
if (col.pageableCollection) col.pageableCollection.getFirstPage({silent: true});
|
362
|
+
col.reset(this.shadowCollection.models, {reindex: false});
|
231
363
|
}
|
232
364
|
|
233
365
|
});
|
@@ -240,7 +372,7 @@
|
|
240
372
|
@class Backgrid.Extension.LunrFilter
|
241
373
|
@extends Backgrid.Extension.ClientSideFilter
|
242
374
|
*/
|
243
|
-
Backgrid.Extension.LunrFilter = ClientSideFilter.extend({
|
375
|
+
var LunrFilter = Backgrid.Extension.LunrFilter = ClientSideFilter.extend({
|
244
376
|
|
245
377
|
/**
|
246
378
|
@property {string} [ref="id"]`lunrjs` document reference attribute name.
|
@@ -262,18 +394,18 @@
|
|
262
394
|
|
263
395
|
@param {Object} options
|
264
396
|
@param {Backbone.Collection} options.collection
|
265
|
-
@param {
|
397
|
+
@param {string} [options.placeholder]
|
266
398
|
@param {string} [options.ref] `lunrjs` document reference attribute name.
|
267
399
|
@param {Object} [options.fields] A hash of `lunrjs` index field names and
|
268
400
|
boost value.
|
269
401
|
@param {number} [options.wait]
|
270
402
|
*/
|
271
403
|
initialize: function (options) {
|
272
|
-
|
404
|
+
LunrFilter.__super__.initialize.apply(this, arguments);
|
273
405
|
|
274
406
|
this.ref = options.ref || this.ref;
|
275
407
|
|
276
|
-
var collection = this.collection;
|
408
|
+
var collection = this.collection = this.collection.fullCollection || this.collection;
|
277
409
|
this.listenTo(collection, "add", this.addToIndex);
|
278
410
|
this.listenTo(collection, "remove", this.removeFromIndex);
|
279
411
|
this.listenTo(collection, "reset", this.resetIndex);
|
@@ -349,17 +481,28 @@
|
|
349
481
|
the client-side. The search result is returned by resetting the
|
350
482
|
underlying collection to the models after interrogating the index for the
|
351
483
|
query answer.
|
484
|
+
|
485
|
+
If the collection is a PageableCollection, searching will go back to the
|
486
|
+
first page.
|
352
487
|
*/
|
353
488
|
search: function () {
|
354
|
-
var
|
489
|
+
var col = this.collection;
|
490
|
+
if (!this.query()) {
|
491
|
+
col.reset(this.shadowCollection.models, {reindex: false});
|
492
|
+
return;
|
493
|
+
}
|
494
|
+
|
495
|
+
var searchResults = this.index.search(this.query());
|
355
496
|
var models = [];
|
356
497
|
for (var i = 0; i < searchResults.length; i++) {
|
357
498
|
var result = searchResults[i];
|
358
499
|
models.push(this.shadowCollection.get(result.ref));
|
359
500
|
}
|
360
|
-
|
501
|
+
|
502
|
+
if (col.pageableCollection) col.pageableCollection.getFirstPage({silent: true});
|
503
|
+
col.reset(models, {reindex: false});
|
361
504
|
}
|
362
505
|
|
363
506
|
});
|
364
507
|
|
365
|
-
}
|
508
|
+
}));
|
@@ -5,7 +5,17 @@
|
|
5
5
|
Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors
|
6
6
|
Licensed under the MIT @license.
|
7
7
|
*/
|
8
|
-
(function (
|
8
|
+
(function (root, factory) {
|
9
|
+
|
10
|
+
// CommonJS
|
11
|
+
if (typeof exports == "object") {
|
12
|
+
module.exports = factory(require("underscore"), require("backgrid"),
|
13
|
+
require("moment"));
|
14
|
+
}
|
15
|
+
// Browser
|
16
|
+
else factory(root._, root.Backgrid, root.moment);
|
17
|
+
|
18
|
+
}(this, function (_, Backgrid, moment) {
|
9
19
|
|
10
20
|
/**
|
11
21
|
MomentFormatter converts bi-directionally any datetime values in any format
|
@@ -152,14 +162,14 @@
|
|
152
162
|
*/
|
153
163
|
initialize: function (options) {
|
154
164
|
|
155
|
-
|
165
|
+
MomentCell.__super__.initialize.apply(this, arguments);
|
156
166
|
|
157
167
|
var formatterDefaults = MomentFormatter.prototype.defaults;
|
158
168
|
var formatterDefaultKeys = _.keys(formatterDefaults);
|
159
|
-
var
|
169
|
+
var instanceAttrs = _.pick(this, formatterDefaultKeys);
|
160
170
|
var formatterOptions = _.pick(options, formatterDefaultKeys);
|
161
171
|
|
162
|
-
|
172
|
+
_.extend(this.formatter, formatterDefaults, instanceAttrs, formatterOptions);
|
163
173
|
|
164
174
|
this.editor = this.editor.extend({
|
165
175
|
attributes: _.extend({}, this.editor.prototype.attributes || this.editor.attributes || {}, {
|
@@ -172,4 +182,4 @@
|
|
172
182
|
|
173
183
|
_.extend(MomentCell.prototype, MomentFormatter.prototype.defaults);
|
174
184
|
|
175
|
-
}
|
185
|
+
}));
|