backgridjs-rails 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (26) hide show
  1. checksums.yaml +15 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +25 -0
  4. data/Rakefile +27 -0
  5. data/lib/backgridjs-rails.rb +5 -0
  6. data/lib/backgridjs-rails.rb~ +2 -0
  7. data/lib/backgridjs-rails/engine.rb +8 -0
  8. data/lib/backgridjs-rails/engine.rb~ +8 -0
  9. data/lib/backgridjs-rails/version.rb +3 -0
  10. data/lib/backgridjs-rails/version.rb~ +3 -0
  11. data/lib/tasks/backgridjs-rails_tasks.rake +4 -0
  12. data/vendor/assets/javascripts/backgrid-extensions/backgrid-filter.js +365 -0
  13. data/vendor/assets/javascripts/backgrid-extensions/backgrid-moment-cell.js +175 -0
  14. data/vendor/assets/javascripts/backgrid-extensions/backgrid-paginator.js +198 -0
  15. data/vendor/assets/javascripts/backgrid-extensions/backgrid-select-all.js +215 -0
  16. data/vendor/assets/javascripts/backgrid-extensions/backgrid-select2-cell.js +121 -0
  17. data/vendor/assets/javascripts/backgrid-extensions/backgrid-text-cell.js +159 -0
  18. data/vendor/assets/javascripts/backgrid.js +2531 -0
  19. data/vendor/assets/stylesheets/backgrid-extensions/backgrid-filter.css +19 -0
  20. data/vendor/assets/stylesheets/backgrid-extensions/backgrid-moment-cell.css +14 -0
  21. data/vendor/assets/stylesheets/backgrid-extensions/backgrid-paginator.css +58 -0
  22. data/vendor/assets/stylesheets/backgrid-extensions/backgrid-select-all.css +11 -0
  23. data/vendor/assets/stylesheets/backgrid-extensions/backgrid-select2-cell.css +19 -0
  24. data/vendor/assets/stylesheets/backgrid-extensions/backgrid-text-cell.css +31 -0
  25. data/vendor/assets/stylesheets/backgrid.css +215 -0
  26. metadata +82 -0
@@ -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=
@@ -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.
@@ -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.
@@ -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,5 @@
1
+ module BackgridjsRails
2
+ module Rails
3
+ require 'backgridjs-rails/engine'
4
+ end
5
+ end
@@ -0,0 +1,2 @@
1
+ module BackgridjsRails
2
+ end
@@ -0,0 +1,8 @@
1
+ require 'rails'
2
+
3
+ module BackgridjsRails
4
+ module Rails
5
+ class Engine < ::Rails::Engine
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require 'rails'
2
+
3
+ module Backgridjs
4
+ module Rails
5
+ class Engine < ::Rails::Engine
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ module BackgridjsRails
2
+ VERSION = "0.2.6"
3
+ end
@@ -0,0 +1,3 @@
1
+ module BackgridjsRails
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :backgridjs-rails do
3
+ # # Task goes here
4
+ # end
@@ -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="#">&times;</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));