js_stack 0.0.1

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,293 @@
1
+ (function (global) {
2
+ 'use strict';
3
+
4
+ var _ = global._, Backbone = global.Backbone, vc, iterators;
5
+
6
+ if ((!_ || !Backbone) && (typeof require !== 'undefined')) {
7
+ _ = require('underscore');
8
+ Backbone = require('backbone');
9
+ }
10
+
11
+ iterators = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
12
+ 'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
13
+ 'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
14
+ 'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
15
+ 'tail', 'drop', 'last', 'without', 'indexOf', 'shuffle', 'lastIndexOf',
16
+ 'isEmpty', 'chain'];
17
+
18
+ /**
19
+ * Constructor for the virtual collection
20
+ * @param {Collection} collection
21
+ * @param {Function|Object} filter function, or hash of properties to match
22
+ * @param {Object} options
23
+ * @param {[Function|Object]} filter function, or hash of properties to match
24
+ * @param {[Function|String]} comparator
25
+ */
26
+ function VirtualCollection(collection, options) {
27
+ this.collection = collection;
28
+ options = options || {};
29
+ this.comparator = options.comparator;
30
+
31
+ _.bindAll(this, 'each', 'map', 'get', 'at', 'indexOf', 'sort', 'closeWith',
32
+ '_rebuildIndex', '_models', '_onAdd', '_onRemove', '_onChange', '_onReset',
33
+ '_indexAdd', '_indexRemove');
34
+
35
+ if (!options.filter) {
36
+ this.filter = function () { return true; };
37
+ } else if (_.isFunction(options.filter)) {
38
+ this.filter = options.filter;
39
+ } else if (options.filter.constructor === Object) {
40
+ this.filter = VirtualCollection.buildFilterFromHash(options.filter);
41
+ }
42
+
43
+ // build index
44
+ this._rebuildIndex();
45
+
46
+ this.listenTo(this.collection, 'add', this._onAdd, this);
47
+ this.listenTo(this.collection, 'remove', this._onRemove, this);
48
+ this.listenTo(this.collection, 'change', this._onChange, this);
49
+ this.listenTo(this.collection, 'reset', this._onReset, this);
50
+
51
+ if (options.close_with) {
52
+ this.closeWith(options.close_with);
53
+ }
54
+ }
55
+
56
+ /**
57
+ * [static] Returns a function that returns true for models that meet the specified conditions
58
+ * @param {Object} hash of model attributes
59
+ * @return {Function} filtering function
60
+ */
61
+ VirtualCollection.buildFilterFromHash = function (hash) {
62
+ return function (model) {
63
+ return !Boolean(_(Object.keys(hash)).detect(function (key) {
64
+ return model.get(key) !== hash[key];
65
+ }));
66
+ };
67
+ };
68
+
69
+ vc = VirtualCollection.prototype;
70
+
71
+
72
+ // mix in Underscore method as proxies
73
+ _.each(iterators, function (method) {
74
+ vc[method] = function () {
75
+ var args = Array.prototype.slice.call(arguments);
76
+ args.unshift(this._models());
77
+ return _[method].apply(_, args);
78
+ };
79
+ });
80
+
81
+ /**
82
+ * Returns a model if it belongs to the virtual collection
83
+ * @param {String} id
84
+ * @return {Model}
85
+ */
86
+ vc.get = function (id) {
87
+ var model = this.collection.get(id);
88
+ if (model && this.filter(model)) {
89
+ return model;
90
+ }
91
+ };
92
+
93
+ /**
94
+ * Returns the model at the position in the index
95
+ * @param {Number} index
96
+ * @return {Model}
97
+ */
98
+ vc.at = function (index) {
99
+ return this.collection.get(this.index[index]);
100
+ };
101
+
102
+ /**
103
+ * Returns the index of the model in the virtual collection
104
+ * @param {Model} model
105
+ * @return {Number} index
106
+ */
107
+ vc.indexOf = function (model) {
108
+ return this.index.indexOf(model.cid);
109
+ };
110
+
111
+ /**
112
+ * Sorts the models in the virtual collection
113
+ *
114
+ * You only need to trigger this manually if you change the comparator
115
+ * @param {Object} options
116
+ * @return {VirtualCollection}
117
+ */
118
+ vc.sort = function (options) {
119
+ var self = this;
120
+ if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
121
+ options = options || {};
122
+
123
+ // Run sort based on type of `comparator`.
124
+ if (_.isString(this.comparator)) {
125
+ this.index = _.sortBy(this.index, function (cid) {
126
+ var model = this.collection.get(cid);
127
+ return model.get(this.comparator);
128
+ }, this);
129
+ } else if (this.comparator.length === 1) {
130
+ this.index = _.sortBy(this.index, function (cid) {
131
+ var model = this.collection.get(cid);
132
+ return this.comparator.call(self, model);
133
+ }, this);
134
+ } else {
135
+ this.index.sort(function (cid1, cid2) {
136
+ var model1 = self.collection.get(cid1),
137
+ model2 = self.collection.get(cid2);
138
+
139
+ return self.comparator.call(self, model1, model2);
140
+ });
141
+ }
142
+
143
+ if (!options.silent) this.trigger('sort', this, options);
144
+ return this;
145
+ };
146
+
147
+ /**
148
+ * A utility function for unbiding listeners
149
+ * @param {View} view (marionette view)
150
+ */
151
+ vc.closeWith = function (view) {
152
+ view.on('close', function () {
153
+ this.stopListening();
154
+ }, this);
155
+ };
156
+
157
+ // private
158
+
159
+ vc._rebuildIndex = function () {
160
+ this.index = [];
161
+ this.collection.each(function (model) {
162
+ if (this.filter(model)) {
163
+ this.index.push(model.cid);
164
+ }
165
+ }, this);
166
+ if (this.comparator) {
167
+ this.sort({silent: true});
168
+ }
169
+ this.length = this.index.length;
170
+ };
171
+
172
+ /**
173
+ * Returns an array of models in the virtual collection
174
+ * @return {Array}
175
+ */
176
+ vc._models = function () {
177
+ return _.map(this.index, function (cid) {
178
+ return this.collection.get(cid);
179
+ }, this);
180
+ };
181
+
182
+ /**
183
+ * Handles the collection:add event
184
+ * May update the virtual collection's index
185
+ * @param {Model} model
186
+ * @return {undefined}
187
+ */
188
+ vc._onAdd = function (model, collection, options) {
189
+ if (this.filter(model)) {
190
+ this._indexAdd(model);
191
+ this.trigger('add', model, this, options);
192
+ }
193
+ };
194
+
195
+ /**
196
+ * Handles the collection:remove event
197
+ * May update the virtual collection's index
198
+ * @param {Model} model
199
+ * @return {undefined}
200
+ */
201
+ vc._onRemove = function (model, collection, options) {
202
+ if (_(this.index).contains(model.cid)) {
203
+ this._indexRemove(model);
204
+ this.trigger('remove', model, this, options);
205
+ }
206
+ };
207
+
208
+ /**
209
+ * Handles the collection:change event
210
+ * May update the virtual collection's index
211
+ * @param {Model} model
212
+ * @param {Object} object
213
+ */
214
+ vc._onChange = function (model, options) {
215
+ var already_here = _.contains(this.index, model.cid);
216
+ if (this.filter(model)) {
217
+ if (already_here) {
218
+ this.trigger('change', model, this, options);
219
+ } else {
220
+ this._indexAdd(model);
221
+ this.trigger('add', model, this, options);
222
+ }
223
+ } else {
224
+ if (already_here) {
225
+ this._indexRemove(model);
226
+ this.trigger('remove', model, this, options);
227
+ }
228
+ }
229
+ };
230
+
231
+ /**
232
+ * Handles the collection:reset event
233
+ * @param {Collection} collection
234
+ * @param {Object} object
235
+ */
236
+ vc._onReset = function (collection, options) {
237
+ this._rebuildIndex();
238
+ this.trigger('reset', this, options);
239
+ };
240
+
241
+ /**
242
+ * Adds a model to the virtual collection index
243
+ * Inserting it in the correct order
244
+ * @param {Model} model
245
+ * @return {undefined}
246
+ */
247
+ vc._indexAdd = function (model) {
248
+ if (this.index.indexOf(model.cid) === -1) {
249
+
250
+ if (!this.comparator) { // order inherit's from parent collection
251
+ var i, orig_index = this.collection.indexOf(model);
252
+ for (i = 0; i < this.length; i++) {
253
+ if (this.collection.indexOf(this.collection.get(this.index[i])) > orig_index) {
254
+ break;
255
+ }
256
+ }
257
+ this.index.splice(i, 0, model.cid);
258
+
259
+ } else { // the virtual collection has a custom order
260
+ this.index.push(model.cid);
261
+ this.sort({silent: true});
262
+ }
263
+ this.length = this.index.length;
264
+ }
265
+ };
266
+
267
+ /**
268
+ * Removes a model from the virtual collection index
269
+ * @param {Model} model
270
+ * @return {undefined}
271
+ */
272
+ vc._indexRemove = function (model) {
273
+ var i = this.index.indexOf(model.cid);
274
+ if (i !== -1) {
275
+ this.index.splice(i, 1);
276
+ this.length = this.index.length;
277
+ }
278
+ };
279
+
280
+ if (!_ && (typeof require !== 'undefined')) {
281
+ _ = require('underscore');
282
+ }
283
+ if (!Backbone && (typeof require !== 'undefined')) {
284
+ Backbone = require('backbone');
285
+ }
286
+ if (typeof module !== 'undefined' && module.exports) {
287
+ module.exports = VirtualCollection;
288
+ }
289
+ _.extend(vc, Backbone.Events);
290
+
291
+ Backbone.VirtualCollection = VirtualCollection;
292
+
293
+ }(this));
@@ -0,0 +1 @@
1
+ //= require js_stack/backbone.virtualcollection/backbone.virtualcollection-0.4.5
@@ -0,0 +1 @@
1
+ //= require backbone.marionette
@@ -0,0 +1,8 @@
1
+ //= require js_stack/backbone
2
+ //= require js_stack/backbone.stickit
3
+ //= require js_stack/marionette
4
+ //= require js_stack/backbone.validation
5
+ //= require js_stack/backbone.pageable
6
+ //= require js_stack/backbone.deepmodel
7
+ //= require js_stack/backbone.associations
8
+ //= require js_stack/backbone.virtualcollection
metadata ADDED
@@ -0,0 +1,124 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: js_stack
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Tomasz Pewiński
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-08-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: backbone-rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.0.0.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.0.0.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: marionette-rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 1.1.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 1.1.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: standard SPA stack used at netguru.co
70
+ email:
71
+ - pewniak747@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - Gemfile
77
+ - Gemfile.lock
78
+ - LICENSE.txt
79
+ - README.md
80
+ - Rakefile
81
+ - js_stack.gemspec
82
+ - js_stack/.gitignore
83
+ - lib/js_stack.rb
84
+ - lib/js_stack/version.rb
85
+ - vendor/assets/javascripts/js_stack.js
86
+ - vendor/assets/javascripts/js_stack/backbone.associations.js
87
+ - vendor/assets/javascripts/js_stack/backbone.associations/backbone.associations-0.5.1.js
88
+ - vendor/assets/javascripts/js_stack/backbone.deepmodel.js
89
+ - vendor/assets/javascripts/js_stack/backbone.deepmodel/backbone.deepmodel-0.10.4.js
90
+ - vendor/assets/javascripts/js_stack/backbone.js
91
+ - vendor/assets/javascripts/js_stack/backbone.pageable.js
92
+ - vendor/assets/javascripts/js_stack/backbone.pageable/backbone.pageable-1.3.2.js
93
+ - vendor/assets/javascripts/js_stack/backbone.stickit.js
94
+ - vendor/assets/javascripts/js_stack/backbone.stickit/backbone.stickit-0.6.3.js
95
+ - vendor/assets/javascripts/js_stack/backbone.validation.js
96
+ - vendor/assets/javascripts/js_stack/backbone.validation/backbone.validation-0.8.1.js
97
+ - vendor/assets/javascripts/js_stack/backbone.virtualcollection.js
98
+ - vendor/assets/javascripts/js_stack/backbone.virtualcollection/backbone.virtualcollection-0.4.5.js
99
+ - vendor/assets/javascripts/js_stack/marionette.js
100
+ homepage: https://github.com/netguru/js_stack
101
+ licenses:
102
+ - MIT
103
+ metadata: {}
104
+ post_install_message:
105
+ rdoc_options: []
106
+ require_paths:
107
+ - lib
108
+ required_ruby_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - '>='
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ requirements: []
119
+ rubyforge_project:
120
+ rubygems_version: 2.0.3
121
+ signing_key:
122
+ specification_version: 4
123
+ summary: standard SPA stack used at netguru.co
124
+ test_files: []