js_stack 0.5.6 → 0.5.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -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