js_stack 0.5.6 → 0.5.7

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.
@@ -0,0 +1,399 @@
1
+ (function (global, factory) {
2
+
3
+ // Set up lib appropriately for the environment. Start with AMD.
4
+ if (typeof define === 'function' && define.amd) {
5
+ define(['underscore', 'backbone'], factory);
6
+
7
+ // Next for Node.js or CommonJS.
8
+ } else if (typeof module !== 'undefined' && module.exports) {
9
+ module.exports = factory(require('underscore'), require('backbone'));
10
+
11
+ // Finally, use browser globals.
12
+ } else {
13
+ factory(global._, global.Backbone);
14
+ }
15
+
16
+ }(this, function (_, Backbone) {
17
+ 'use strict';
18
+
19
+ var vc, iterators, proxy;
20
+
21
+ iterators = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
22
+ 'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
23
+ 'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
24
+ 'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
25
+ 'tail', 'drop', 'last', 'without', 'indexOf', 'shuffle', 'lastIndexOf',
26
+ 'isEmpty', 'chain', 'pluck'];
27
+
28
+ proxy = ['add', 'remove'];
29
+
30
+ /**
31
+ * Constructor for the virtual collection
32
+ * @param {Collection} collection
33
+ * @param {Function|Object} filter function, or hash of properties to match
34
+ * @param {Object} options
35
+ * @param {[Function|Object]} filter function, or hash of properties to match
36
+ * @param {[Function|String]} comparator
37
+ */
38
+ function VirtualCollection(collection, options) {
39
+ this.collection = collection;
40
+ options = options || {};
41
+ this.comparator = options.comparator;
42
+ this.model = collection.model;
43
+
44
+ _.bindAll(this, 'each', 'map', 'get', 'at', 'indexOf', 'sort', 'closeWith',
45
+ '_rebuildIndex', '_models', '_onAdd', '_onRemove', '_onChange', '_onReset',
46
+ '_indexAdd', '_indexRemove');
47
+
48
+ // set filter
49
+ this.filterFunction = VirtualCollection.buildFilter(options.filter);
50
+
51
+ // build index
52
+ this._rebuildIndex();
53
+
54
+ this.listenTo(this.collection, 'add', this._onAdd, this);
55
+ this.listenTo(this.collection, 'remove', this._onRemove, this);
56
+ this.listenTo(this.collection, 'change', this._onChange, this);
57
+ this.listenTo(this.collection, 'reset', this._onReset, this);
58
+
59
+ if (options.close_with) {
60
+ this.closeWith(options.close_with);
61
+ }
62
+ }
63
+
64
+ /**
65
+ * [static] Returns a function that returns true for models that meet the specified conditions
66
+ *
67
+ * @param {Object} hash of model attributes or {Function} filter
68
+ * @return {Function} filtering function
69
+ */
70
+ VirtualCollection.buildFilter = function (filter) {
71
+ if (!filter) {
72
+ // If no filter is passed, all models should be added
73
+ return function () {
74
+ return true;
75
+ };
76
+ } else if (_.isFunction(filter)) {
77
+ // If filter is passed a function, just return it
78
+ return filter;
79
+ } else if (filter.constructor === Object) {
80
+ // If filter is a hash of attributes, return a function that checks each of them
81
+ return function (model) {
82
+ return !Boolean(_(Object.keys(filter)).detect(function (key) {
83
+ return model.get(key) !== filter[key];
84
+ }));
85
+ };
86
+ }
87
+ };
88
+
89
+ vc = VirtualCollection.prototype;
90
+
91
+ // mix in Underscore method as proxies
92
+ _.each(iterators, function (method) {
93
+ vc[method] = function () {
94
+ var args = Array.prototype.slice.call(arguments)
95
+ , proxyCollection = { models: this._models() };
96
+ return Backbone.Collection.prototype[method].apply(proxyCollection, args);
97
+ };
98
+ });
99
+
100
+ // proxy functions to parent
101
+ _.each(proxy, function (method) {
102
+ vc[method] = function () {
103
+ var args = Array.prototype.slice.call(arguments);
104
+ return this.collection[method].apply(this.collection, args);
105
+ };
106
+ });
107
+
108
+ /**
109
+ * Returns a model if it belongs to the virtual collection
110
+ *
111
+ * @param {String} id or cid
112
+ * @return {Model}
113
+ */
114
+ vc.get = function (id) {
115
+ var model = this._getParentCollection().get(id);
116
+ if (model && _.contains(this.index, model.cid)) {
117
+ return model;
118
+ }
119
+ };
120
+
121
+ /**
122
+ * Returns the parent non-virtual collection.
123
+ *
124
+ * @return {Collection}
125
+ */
126
+ vc._getParentCollection = function () {
127
+ if (this.collection instanceof VirtualCollection) {
128
+ return this.collection._getParentCollection();
129
+ } else {
130
+ return this.collection;
131
+ }
132
+ };
133
+
134
+ /**
135
+ * Returns the model at the position in the index
136
+ *
137
+ * @param {Number} index
138
+ * @return {Model}
139
+ */
140
+ vc.at = function (index) {
141
+ return this.collection.get(this.index[index]);
142
+ };
143
+
144
+ vc.where = Backbone.Collection.prototype.where;
145
+ vc.findWhere = Backbone.Collection.prototype.findWhere;
146
+
147
+ /**
148
+ * Returns the index of the model in the virtual collection
149
+ *
150
+ * @param {Model} model
151
+ * @return {Number} index
152
+ */
153
+ vc.indexOf = function (model) {
154
+ return this.index.indexOf(model.cid);
155
+ };
156
+
157
+ /**
158
+ * Returns a JSON representation of all the models in the index
159
+ *
160
+ * @return {Array} JSON models
161
+ */
162
+ vc.toJSON = function () {
163
+ return _.map(this._models(), function (model) {
164
+ return model.toJSON();
165
+ });
166
+ };
167
+
168
+ /**
169
+ * Sorts the models in the virtual collection
170
+ *
171
+ * You only need to trigger this manually if you change the comparator
172
+ *
173
+ * @param {Object} options
174
+ * @return {VirtualCollection}
175
+ */
176
+ vc.sort = function (options) {
177
+ var self = this;
178
+
179
+ if (!this.comparator) {
180
+ throw new Error('Cannot sort a set without a comparator');
181
+ }
182
+
183
+ options = options || {};
184
+
185
+ // Run sort based on type of `comparator`.
186
+ if (_.isString(this.comparator)) {
187
+ this.index = _.sortBy(this.index, function (cid) {
188
+ var model = this.collection.get(cid);
189
+ return model.get(this.comparator);
190
+ }, this);
191
+ } else if (this.comparator.length === 1) {
192
+ this.index = _.sortBy(this.index, function (cid) {
193
+ var model = this.collection.get(cid);
194
+ return this.comparator.call(self, model);
195
+ }, this);
196
+ } else {
197
+ this.index.sort(function (cid1, cid2) {
198
+ var model1 = self.collection.get(cid1),
199
+ model2 = self.collection.get(cid2);
200
+
201
+ return self.comparator.call(self, model1, model2);
202
+ });
203
+ }
204
+
205
+ if (!options.silent) {
206
+ this.trigger('sort', this, options);
207
+ }
208
+
209
+ return this;
210
+ };
211
+
212
+ /**
213
+ * Change the filter and update collection
214
+ *
215
+ * @param {Object} hash of model attributes or {Function} filter
216
+ * @return {VirtualCollection}
217
+ */
218
+
219
+ vc.updateFilter = function (filter) {
220
+ // Reset the filter
221
+ this.filterFunction = VirtualCollection.buildFilter(filter);
222
+
223
+ // Update the models
224
+ this._rebuildIndex();
225
+
226
+ // Trigger filter event
227
+ this.trigger('filter', this, filter);
228
+
229
+ // Trigger reset event
230
+ this.trigger('reset', this, filter);
231
+
232
+ return this;
233
+ };
234
+
235
+ /**
236
+ * A utility function for unbiding listeners
237
+ *
238
+ * @param {View} view (marionette view)
239
+ */
240
+ vc.closeWith = function (view) {
241
+ view.on('close', function () {
242
+ this.stopListening();
243
+ }, this);
244
+ };
245
+
246
+ // private
247
+
248
+ vc._rebuildIndex = function () {
249
+ this.index = [];
250
+
251
+ this.collection.each(function (model, index) {
252
+ if (this.filterFunction(model, index)) {
253
+ this.index.push(model.cid);
254
+ }
255
+ }, this);
256
+
257
+ if (this.comparator) {
258
+ this.sort({silent: true});
259
+ }
260
+
261
+ this.length = this.index.length;
262
+ };
263
+
264
+ /**
265
+ * Returns an array of models in the virtual collection
266
+ *
267
+ * @return {Array}
268
+ */
269
+ vc._models = function () {
270
+ var parentCollection = this._getParentCollection();
271
+
272
+ return _.map(this.index, function (cid) {
273
+ return parentCollection.get(cid);
274
+ }, this);
275
+ };
276
+
277
+ /**
278
+ * Handles the collection:add event
279
+ * May update the virtual collection's index
280
+ *
281
+ * @param {Model} model
282
+ * @return {undefined}
283
+ */
284
+ vc._onAdd = function (model, collection, options) {
285
+ if (this.filterFunction(model)) {
286
+ this._indexAdd(model);
287
+ this.trigger('add', model, this, options);
288
+ }
289
+ };
290
+
291
+ /**
292
+ * Handles the collection:remove event
293
+ * May update the virtual collection's index
294
+ *
295
+ * @param {Model} model
296
+ * @return {undefined}
297
+ */
298
+ vc._onRemove = function (model, collection, options) {
299
+ if (_(this.index).contains(model.cid)) {
300
+ var i = this._indexRemove(model)
301
+ , options_clone;
302
+
303
+ if (options) {
304
+ options_clone = _.clone(options);
305
+ options_clone.index = i;
306
+ }
307
+
308
+ this.trigger('remove', model, this, options_clone);
309
+ }
310
+ };
311
+
312
+ /**
313
+ * Handles the collection:change event
314
+ * May update the virtual collection's index
315
+ *
316
+ * @param {Model} model
317
+ * @param {Object} object
318
+ */
319
+ vc._onChange = function (model, options) {
320
+ var already_here = _.contains(this.index, model.cid);
321
+
322
+ if (this.filterFunction(model)) {
323
+ if (already_here) {
324
+ this.trigger('change', model, this, options);
325
+ } else {
326
+ this._indexAdd(model);
327
+ this.trigger('add', model, this, options);
328
+ }
329
+ } else {
330
+ if (already_here) {
331
+ this._indexRemove(model);
332
+ this.trigger('remove', model, this, options);
333
+ }
334
+ }
335
+ };
336
+
337
+ /**
338
+ * Handles the collection:reset event
339
+ *
340
+ * @param {Collection} collection
341
+ * @param {Object} object
342
+ */
343
+ vc._onReset = function (collection, options) {
344
+ this._rebuildIndex();
345
+ this.trigger('reset', this, options);
346
+ };
347
+
348
+ /**
349
+ * Adds a model to the virtual collection index
350
+ * Inserting it in the correct order
351
+ *
352
+ * @param {Model} model
353
+ * @return {undefined}
354
+ */
355
+ vc._indexAdd = function (model) {
356
+ if (this.index.indexOf(model.cid) === -1) {
357
+
358
+ if (!this.comparator) { // order inherit's from parent collection
359
+ var i, orig_index = this.collection.indexOf(model);
360
+ for (i = 0; i < this.length; i++) {
361
+ if (this.collection.indexOf(this.collection.get(this.index[i])) > orig_index) {
362
+ break;
363
+ }
364
+ }
365
+ this.index.splice(i, 0, model.cid);
366
+
367
+ } else { // the virtual collection has a custom order
368
+ this.index.push(model.cid);
369
+ this.sort({silent: true});
370
+ }
371
+ this.length = this.index.length;
372
+ }
373
+ };
374
+
375
+ /**
376
+ * Removes a model from the virtual collection index
377
+ *
378
+ * @param {Model} model
379
+ * @return {int} the index for the removed model or -1 if not found
380
+ */
381
+ vc._indexRemove = function (model) {
382
+ var i = this.index.indexOf(model.cid);
383
+
384
+ if (i !== -1) {
385
+ this.index.splice(i, 1);
386
+ this.length = this.index.length;
387
+ }
388
+
389
+ return i;
390
+ };
391
+
392
+ _.extend(vc, Backbone.Events);
393
+
394
+ VirtualCollection.extend = Backbone.Collection.extend;
395
+
396
+ Backbone.VirtualCollection = VirtualCollection;
397
+
398
+ return VirtualCollection;
399
+ }));
@@ -1 +1 @@
1
- //= require js_stack/plugins/backbone/pageable/1.4.5
1
+ //= require js_stack/plugins/backbone/pageable/1.4.8
@@ -1 +1 @@
1
- //= require js_stack/plugins/backbone/virtualcollection/0.4.14
1
+ //= require js_stack/plugins/backbone/virtualcollection/0.4.15
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: js_stack
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.6
4
+ version: 0.5.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tomasz Pewiński
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-04-03 00:00:00.000000000 Z
12
+ date: 2014-04-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: haml_coffee_assets
@@ -117,6 +117,7 @@ files:
117
117
  - vendor/assets/javascripts/js_stack/base/marionette/1.7.0.js
118
118
  - vendor/assets/javascripts/js_stack/base/marionette/1.7.3.js
119
119
  - vendor/assets/javascripts/js_stack/base/marionette/1.7.4.js
120
+ - vendor/assets/javascripts/js_stack/base/marionette/1.8.0.js
120
121
  - vendor/assets/javascripts/js_stack/base/underscore.js
121
122
  - vendor/assets/javascripts/js_stack/base/underscore/1.5.2.js
122
123
  - vendor/assets/javascripts/js_stack/base/underscore/1.6.0.js
@@ -138,6 +139,7 @@ files:
138
139
  - vendor/assets/javascripts/js_stack/plugins/backbone/mutators/0.4.2.js
139
140
  - vendor/assets/javascripts/js_stack/plugins/backbone/pageable/1.3.2.js
140
141
  - vendor/assets/javascripts/js_stack/plugins/backbone/pageable/1.4.5.js
142
+ - vendor/assets/javascripts/js_stack/plugins/backbone/pageable/1.4.8.js
141
143
  - vendor/assets/javascripts/js_stack/plugins/backbone/routefilter/0.2.0.js
142
144
  - vendor/assets/javascripts/js_stack/plugins/backbone/stickit/0.6.3.js
143
145
  - vendor/assets/javascripts/js_stack/plugins/backbone/stickit/0.7.0.js
@@ -146,6 +148,7 @@ files:
146
148
  - vendor/assets/javascripts/js_stack/plugins/backbone/virtualcollection/0.4.11.js
147
149
  - vendor/assets/javascripts/js_stack/plugins/backbone/virtualcollection/0.4.12.js
148
150
  - vendor/assets/javascripts/js_stack/plugins/backbone/virtualcollection/0.4.14.js
151
+ - vendor/assets/javascripts/js_stack/plugins/backbone/virtualcollection/0.4.15.js
149
152
  - vendor/assets/javascripts/js_stack/plugins/backbone/virtualcollection/0.4.5.js
150
153
  - vendor/assets/javascripts/js_stack/plugins/backbone/virtualcollection/0.4.8.js
151
154
  - vendor/assets/javascripts/js_stack/plugins/cocktail.js