backgridjs-rails 0.2.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +25 -0
- data/Rakefile +27 -0
- data/lib/backgridjs-rails.rb +5 -0
- data/lib/backgridjs-rails.rb~ +2 -0
- data/lib/backgridjs-rails/engine.rb +8 -0
- data/lib/backgridjs-rails/engine.rb~ +8 -0
- data/lib/backgridjs-rails/version.rb +3 -0
- data/lib/backgridjs-rails/version.rb~ +3 -0
- data/lib/tasks/backgridjs-rails_tasks.rake +4 -0
- data/vendor/assets/javascripts/backgrid-extensions/backgrid-filter.js +365 -0
- data/vendor/assets/javascripts/backgrid-extensions/backgrid-moment-cell.js +175 -0
- data/vendor/assets/javascripts/backgrid-extensions/backgrid-paginator.js +198 -0
- data/vendor/assets/javascripts/backgrid-extensions/backgrid-select-all.js +215 -0
- data/vendor/assets/javascripts/backgrid-extensions/backgrid-select2-cell.js +121 -0
- data/vendor/assets/javascripts/backgrid-extensions/backgrid-text-cell.js +159 -0
- data/vendor/assets/javascripts/backgrid.js +2531 -0
- data/vendor/assets/stylesheets/backgrid-extensions/backgrid-filter.css +19 -0
- data/vendor/assets/stylesheets/backgrid-extensions/backgrid-moment-cell.css +14 -0
- data/vendor/assets/stylesheets/backgrid-extensions/backgrid-paginator.css +58 -0
- data/vendor/assets/stylesheets/backgrid-extensions/backgrid-select-all.css +11 -0
- data/vendor/assets/stylesheets/backgrid-extensions/backgrid-select2-cell.css +19 -0
- data/vendor/assets/stylesheets/backgrid-extensions/backgrid-text-cell.css +31 -0
- data/vendor/assets/stylesheets/backgrid.css +215 -0
- metadata +82 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZjE2OTQ4Y2JjNTM2YzM2MWFkYmEzM2U0MjBhNGViMTQxN2JkZjBiZA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZTNiOGU0MGViYmI1ZTUzMTExNmUzMWYyYjNiNzVmNzU4ZWQ1OTliZA==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MWY3MDhiNDhjNDkyOTQ1ZTBiNDM5MTQ0YWUwYWUwMDhmOWNkNjQ4YmFhNTdm
|
10
|
+
NTljZGUyYzMxNzM4NDg0MGIyNDJjY2RkZmM4OGEzOThjNjc2OTcwYThlNTNj
|
11
|
+
Y2FlYjc5ZDRhYzM2MDg3ODQ3ODg1MDc0ODA4ODFiYjAzMzMzMTU=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YzNlNjQ4MTg5YTg1N2Q5ZDE4YTkyYmJkOGE1N2ZmODEwMjg1NDJjMDc2MDc2
|
14
|
+
MDk5MzY3ZTRjYTU1OWU0M2FhYzc2YjZiMmJhMmEzMWE5NWY5MGIxODQ2NzQy
|
15
|
+
N2Y4ZDIwY2E3YWY1YWQ0Y2MyNTMxMjMzOWQ4MWQ0NTg2YjkwMDk=
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2013 YOURNAME
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
= BackgridjsRails
|
2
|
+
|
3
|
+
Vendors backgrid js and extensions into rails asset pipeline
|
4
|
+
|
5
|
+
== Installation
|
6
|
+
|
7
|
+
Add the gem to your Gemfile
|
8
|
+
|
9
|
+
gem 'backgridjs-rails'
|
10
|
+
|
11
|
+
Then add backgrid to the app/assets/javascripts/application.js
|
12
|
+
|
13
|
+
//= require backgrid
|
14
|
+
|
15
|
+
And to app/assets/stylesheets/application.css.scss
|
16
|
+
|
17
|
+
*= require backgrid
|
18
|
+
|
19
|
+
== Extensions
|
20
|
+
|
21
|
+
The backgrid extensions are included too, to use them add the revelant one to application.js and application.css.scss
|
22
|
+
|
23
|
+
//= require backgrid-extensions/backgrid-filter
|
24
|
+
|
25
|
+
This project rocks and uses MIT-LICENSE.
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'BackgridjsRails'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
Bundler::GemHelper.install_tasks
|
27
|
+
|
@@ -0,0 +1,365 @@
|
|
1
|
+
/*
|
2
|
+
backgrid-filter
|
3
|
+
http://github.com/wyuenho/backgrid
|
4
|
+
|
5
|
+
Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors
|
6
|
+
Licensed under the MIT @license.
|
7
|
+
*/
|
8
|
+
|
9
|
+
(function ($, _, Backbone, Backgrid, lunr) {
|
10
|
+
|
11
|
+
"use strict";
|
12
|
+
|
13
|
+
/**
|
14
|
+
ServerSideFilter is a search form widget that submits a query to the server
|
15
|
+
for filtering the current collection.
|
16
|
+
|
17
|
+
@class Backgrid.Extension.ServerSideFilter
|
18
|
+
*/
|
19
|
+
var ServerSideFilter = Backgrid.Extension.ServerSideFilter = Backbone.View.extend({
|
20
|
+
|
21
|
+
/** @property */
|
22
|
+
tagName: "form",
|
23
|
+
|
24
|
+
/** @property */
|
25
|
+
className: "backgrid-filter form-search",
|
26
|
+
|
27
|
+
/** @property {function(Object, ?Object=): string} template */
|
28
|
+
template: _.template('<div class="input-prepend input-append"><span class="add-on"><i class="icon-search"></i></span><input type="text" <% if (placeholder) { %> placeholder="<%- placeholder %>" <% } %> name="<%- name %>" /><span class="add-on"><a class="close" href="#">×</a></span></div>'),
|
29
|
+
|
30
|
+
/** @property */
|
31
|
+
events: {
|
32
|
+
"click .close": "clear",
|
33
|
+
"submit": "search"
|
34
|
+
},
|
35
|
+
|
36
|
+
/** @property {string} [name='q'] Query key */
|
37
|
+
name: "q",
|
38
|
+
|
39
|
+
/** @property The HTML5 placeholder to appear beneath the search box. */
|
40
|
+
placeholder: null,
|
41
|
+
|
42
|
+
/**
|
43
|
+
@param {Object} options
|
44
|
+
@param {Backbone.Collection} options.collection
|
45
|
+
@param {String} [options.name]
|
46
|
+
@param {String} [options.placeholder]
|
47
|
+
*/
|
48
|
+
initialize: function (options) {
|
49
|
+
Backgrid.requireOptions(options, ["collection"]);
|
50
|
+
Backbone.View.prototype.initialize.apply(this, arguments);
|
51
|
+
this.name = options.name || this.name;
|
52
|
+
this.placeholder = options.placeholder || this.placeholder;
|
53
|
+
|
54
|
+
var collection = this.collection, self = this;
|
55
|
+
if (Backbone.PageableCollection &&
|
56
|
+
collection instanceof Backbone.PageableCollection &&
|
57
|
+
collection.mode == "server") {
|
58
|
+
collection.queryParams[this.name] = function () {
|
59
|
+
return self.$el.find("input[type=text]").val();
|
60
|
+
};
|
61
|
+
}
|
62
|
+
},
|
63
|
+
|
64
|
+
/**
|
65
|
+
Upon search form submission, this event handler constructs a query
|
66
|
+
parameter object and pass it to Collection#fetch for server-side
|
67
|
+
filtering.
|
68
|
+
*/
|
69
|
+
search: function (e) {
|
70
|
+
if (e) e.preventDefault();
|
71
|
+
var data = {};
|
72
|
+
data[this.name] = this.$el.find("input[type=text]").val();
|
73
|
+
this.collection.fetch({data: data});
|
74
|
+
},
|
75
|
+
|
76
|
+
/**
|
77
|
+
Event handler for the close button. Clears the search box and refetch the
|
78
|
+
collection.
|
79
|
+
*/
|
80
|
+
clear: function (e) {
|
81
|
+
if (e) e.preventDefault();
|
82
|
+
this.$("input[type=text]").val(null);
|
83
|
+
this.collection.fetch();
|
84
|
+
},
|
85
|
+
|
86
|
+
/**
|
87
|
+
Renders a search form with a text box, optionally with a placeholder and
|
88
|
+
a preset value if supplied during initialization.
|
89
|
+
*/
|
90
|
+
render: function () {
|
91
|
+
this.$el.empty().append(this.template({
|
92
|
+
name: this.name,
|
93
|
+
placeholder: this.placeholder,
|
94
|
+
value: this.value
|
95
|
+
}));
|
96
|
+
this.delegateEvents();
|
97
|
+
return this;
|
98
|
+
}
|
99
|
+
|
100
|
+
});
|
101
|
+
|
102
|
+
/**
|
103
|
+
ClientSideFilter is a search form widget that searches a collection for
|
104
|
+
model matches against a query on the client side. The exact matching
|
105
|
+
algorithm can be overriden by subclasses.
|
106
|
+
|
107
|
+
@class Backgrid.Extension.ClientSideFilter
|
108
|
+
@extends Backgrid.Extension.ServerSideFilter
|
109
|
+
*/
|
110
|
+
var ClientSideFilter = Backgrid.Extension.ClientSideFilter = ServerSideFilter.extend({
|
111
|
+
|
112
|
+
/** @property */
|
113
|
+
events: {
|
114
|
+
"click .close": function (e) {
|
115
|
+
e.preventDefault();
|
116
|
+
this.clear();
|
117
|
+
},
|
118
|
+
"change input[type=text]": "search",
|
119
|
+
"keyup input[type=text]": "search",
|
120
|
+
"submit": function (e) {
|
121
|
+
e.preventDefault();
|
122
|
+
this.search();
|
123
|
+
}
|
124
|
+
},
|
125
|
+
|
126
|
+
/**
|
127
|
+
@property {?Array.<string>} A list of model field names to search
|
128
|
+
for matches. If null, all of the fields will be searched.
|
129
|
+
*/
|
130
|
+
fields: null,
|
131
|
+
|
132
|
+
/**
|
133
|
+
@property wait The time in milliseconds to wait since for since the last
|
134
|
+
change to the search box's value before searching. This value can be
|
135
|
+
adjusted depending on how often the search box is used and how large the
|
136
|
+
search index is.
|
137
|
+
*/
|
138
|
+
wait: 149,
|
139
|
+
|
140
|
+
/**
|
141
|
+
Debounces the #search and #clear methods and makes a copy of the given
|
142
|
+
collection for searching.
|
143
|
+
|
144
|
+
@param {Object} options
|
145
|
+
@param {Backbone.Collection} options.collection
|
146
|
+
@param {String} [options.placeholder]
|
147
|
+
@param {String} [options.fields]
|
148
|
+
@param {String} [options.wait=149]
|
149
|
+
*/
|
150
|
+
initialize: function (options) {
|
151
|
+
ServerSideFilter.prototype.initialize.apply(this, arguments);
|
152
|
+
|
153
|
+
this.fields = options.fields || this.fields;
|
154
|
+
this.wait = options.wait || this.wait;
|
155
|
+
|
156
|
+
this._debounceMethods(["search", "clear"]);
|
157
|
+
|
158
|
+
var collection = this.collection;
|
159
|
+
var shadowCollection = this.shadowCollection = collection.clone();
|
160
|
+
shadowCollection.url = collection.url;
|
161
|
+
shadowCollection.sync = collection.sync;
|
162
|
+
shadowCollection.parse = collection.parse;
|
163
|
+
|
164
|
+
this.listenTo(collection, "add", function (model, collection, options) {
|
165
|
+
shadowCollection.add(model, options);
|
166
|
+
});
|
167
|
+
this.listenTo(collection, "remove", function (model, collection, options) {
|
168
|
+
shadowCollection.remove(model, options);
|
169
|
+
});
|
170
|
+
this.listenTo(collection, "sort reset", function (collection, options) {
|
171
|
+
options = _.extend({reindex: true}, options || {});
|
172
|
+
if (options.reindex) shadowCollection.reset(collection.models);
|
173
|
+
});
|
174
|
+
},
|
175
|
+
|
176
|
+
_debounceMethods: function (methodNames) {
|
177
|
+
if (_.isString(methodNames)) methodNames = [methodNames];
|
178
|
+
|
179
|
+
this.undelegateEvents();
|
180
|
+
|
181
|
+
for (var i = 0, l = methodNames.length; i < l; i++) {
|
182
|
+
var methodName = methodNames[i];
|
183
|
+
var method = this[methodName];
|
184
|
+
this[methodName] = _.debounce(method, this.wait);
|
185
|
+
}
|
186
|
+
|
187
|
+
this.delegateEvents();
|
188
|
+
},
|
189
|
+
|
190
|
+
/**
|
191
|
+
This default implementation takes a query string and returns a matcher
|
192
|
+
function that looks for matches in the model's #fields or all of its
|
193
|
+
fields if #fields is null, for any of the words in the query
|
194
|
+
case-insensitively.
|
195
|
+
|
196
|
+
Subclasses overriding this method must take care to conform to the
|
197
|
+
signature of the matcher function. In addition, when the matcher function
|
198
|
+
is called, its context will be bound to this ClientSideFilter object so
|
199
|
+
it has access to the filter's attributes and methods.
|
200
|
+
|
201
|
+
@param {string} query The search query in the search box.
|
202
|
+
@return {function(Backbone.Model):boolean} A matching function.
|
203
|
+
*/
|
204
|
+
makeMatcher: function (query) {
|
205
|
+
var regexp = new RegExp(query.trim().split(/\W/).join("|"), "i");
|
206
|
+
return function (model) {
|
207
|
+
var keys = this.fields || model.keys();
|
208
|
+
for (var i = 0, l = keys.length; i < l; i++) {
|
209
|
+
if (regexp.test(model.get(keys[i]) + "")) return true;
|
210
|
+
}
|
211
|
+
return false;
|
212
|
+
};
|
213
|
+
},
|
214
|
+
|
215
|
+
/**
|
216
|
+
Takes the query from the search box, constructs a matcher with it and
|
217
|
+
loops through collection looking for matches. Reset the given collection
|
218
|
+
when all the matches have been found.
|
219
|
+
*/
|
220
|
+
search: function () {
|
221
|
+
var matcher = _.bind(this.makeMatcher(this.$("input[type=text]").val()), this);
|
222
|
+
this.collection.reset(this.shadowCollection.filter(matcher), {reindex: false});
|
223
|
+
},
|
224
|
+
|
225
|
+
/**
|
226
|
+
Clears the search box and reset the collection to its original.
|
227
|
+
*/
|
228
|
+
clear: function () {
|
229
|
+
this.$("input[type=text]").val(null);
|
230
|
+
this.collection.reset(this.shadowCollection.models, {reindex: false});
|
231
|
+
}
|
232
|
+
|
233
|
+
});
|
234
|
+
|
235
|
+
/**
|
236
|
+
LunrFilter is a ClientSideFilter that uses [lunrjs](http://lunrjs.com/) to
|
237
|
+
index the text fields of each model for a collection, and performs
|
238
|
+
full-text searching.
|
239
|
+
|
240
|
+
@class Backgrid.Extension.LunrFilter
|
241
|
+
@extends Backgrid.Extension.ClientSideFilter
|
242
|
+
*/
|
243
|
+
Backgrid.Extension.LunrFilter = ClientSideFilter.extend({
|
244
|
+
|
245
|
+
/**
|
246
|
+
@property {string} [ref="id"]`lunrjs` document reference attribute name.
|
247
|
+
*/
|
248
|
+
ref: "id",
|
249
|
+
|
250
|
+
/**
|
251
|
+
@property {Object} fields A hash of `lunrjs` index field names and boost
|
252
|
+
value. Unlike ClientSideFilter#fields, LunrFilter#fields is _required_ to
|
253
|
+
initialize the index.
|
254
|
+
*/
|
255
|
+
fields: null,
|
256
|
+
|
257
|
+
/**
|
258
|
+
Indexes the underlying collection on construction. The index will refresh
|
259
|
+
when the underlying collection is reset. If any model is added, removed
|
260
|
+
or if any indexed fields of any models has changed, the index will be
|
261
|
+
updated.
|
262
|
+
|
263
|
+
@param {Object} options
|
264
|
+
@param {Backbone.Collection} options.collection
|
265
|
+
@param {String} [options.placeholder]
|
266
|
+
@param {string} [options.ref] `lunrjs` document reference attribute name.
|
267
|
+
@param {Object} [options.fields] A hash of `lunrjs` index field names and
|
268
|
+
boost value.
|
269
|
+
@param {number} [options.wait]
|
270
|
+
*/
|
271
|
+
initialize: function (options) {
|
272
|
+
ClientSideFilter.prototype.initialize.apply(this, arguments);
|
273
|
+
|
274
|
+
this.ref = options.ref || this.ref;
|
275
|
+
|
276
|
+
var collection = this.collection;
|
277
|
+
this.listenTo(collection, "add", this.addToIndex);
|
278
|
+
this.listenTo(collection, "remove", this.removeFromIndex);
|
279
|
+
this.listenTo(collection, "reset", this.resetIndex);
|
280
|
+
this.listenTo(collection, "change", this.updateIndex);
|
281
|
+
|
282
|
+
this.resetIndex(collection);
|
283
|
+
},
|
284
|
+
|
285
|
+
/**
|
286
|
+
Reindex the collection. If `options.reindex` is `false`, this method is a
|
287
|
+
no-op.
|
288
|
+
|
289
|
+
@param {Backbone.Collection} collection
|
290
|
+
@param {Object} [options]
|
291
|
+
@param {boolean} [options.reindex=true]
|
292
|
+
*/
|
293
|
+
resetIndex: function (collection, options) {
|
294
|
+
options = _.extend({reindex: true}, options || {});
|
295
|
+
|
296
|
+
if (options.reindex) {
|
297
|
+
var self = this;
|
298
|
+
this.index = lunr(function () {
|
299
|
+
_.each(self.fields, function (boost, fieldName) {
|
300
|
+
this.field(fieldName, boost);
|
301
|
+
this.ref(self.ref);
|
302
|
+
}, this);
|
303
|
+
});
|
304
|
+
|
305
|
+
collection.each(function (model) {
|
306
|
+
this.addToIndex(model);
|
307
|
+
}, this);
|
308
|
+
}
|
309
|
+
},
|
310
|
+
|
311
|
+
/**
|
312
|
+
Adds the given model to the index.
|
313
|
+
|
314
|
+
@param {Backbone.Model} model
|
315
|
+
*/
|
316
|
+
addToIndex: function (model) {
|
317
|
+
var index = this.index;
|
318
|
+
var doc = model.toJSON();
|
319
|
+
if (index.documentStore.has(doc[this.ref])) index.update(doc);
|
320
|
+
else index.add(doc);
|
321
|
+
},
|
322
|
+
|
323
|
+
/**
|
324
|
+
Removes the given model from the index.
|
325
|
+
|
326
|
+
@param {Backbone.Model} model
|
327
|
+
*/
|
328
|
+
removeFromIndex: function (model) {
|
329
|
+
var index = this.index;
|
330
|
+
var doc = model.toJSON();
|
331
|
+
if (index.documentStore.has(doc[this.ref])) index.remove(doc);
|
332
|
+
},
|
333
|
+
|
334
|
+
/**
|
335
|
+
Updates the index for the given model.
|
336
|
+
|
337
|
+
@param {Backbone.Model} model
|
338
|
+
*/
|
339
|
+
updateIndex: function (model) {
|
340
|
+
var changed = model.changedAttributes();
|
341
|
+
if (changed && !_.isEmpty(_.intersection(_.keys(this.fields),
|
342
|
+
_.keys(changed)))) {
|
343
|
+
this.index.update(model.toJSON());
|
344
|
+
}
|
345
|
+
},
|
346
|
+
|
347
|
+
/**
|
348
|
+
Takes the query from the search box and performs a full-text search on
|
349
|
+
the client-side. The search result is returned by resetting the
|
350
|
+
underlying collection to the models after interrogating the index for the
|
351
|
+
query answer.
|
352
|
+
*/
|
353
|
+
search: function () {
|
354
|
+
var searchResults = this.index.search(this.$("input[type=text]").val());
|
355
|
+
var models = [];
|
356
|
+
for (var i = 0; i < searchResults.length; i++) {
|
357
|
+
var result = searchResults[i];
|
358
|
+
models.push(this.shadowCollection.get(result.ref));
|
359
|
+
}
|
360
|
+
this.collection.reset(models, {reindex: false});
|
361
|
+
}
|
362
|
+
|
363
|
+
});
|
364
|
+
|
365
|
+
}(jQuery, _, Backbone, Backgrid, lunr));
|