js_stack 0.5.7 → 0.6.0

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.
Files changed (23) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/README.md +7 -7
  4. data/lib/js_stack/version.rb +1 -1
  5. data/vendor/assets/javascripts/js_stack/base/marionette/{1.8.0.js → 1.8.3.js} +173 -8
  6. data/vendor/assets/javascripts/js_stack/base/marionette.js +1 -1
  7. data/vendor/assets/javascripts/js_stack/plugins/backbone/stickit/0.8.0.js +595 -0
  8. data/vendor/assets/javascripts/js_stack/plugins/backbone.stickit.js +1 -1
  9. metadata +4 -17
  10. data/vendor/assets/javascripts/js_stack/base/backbone/1.1.0.js +0 -1581
  11. data/vendor/assets/javascripts/js_stack/base/backbone/1.1.1.js +0 -1609
  12. data/vendor/assets/javascripts/js_stack/base/marionette/1.6.2.js +0 -2555
  13. data/vendor/assets/javascripts/js_stack/base/marionette/1.7.0.js +0 -2746
  14. data/vendor/assets/javascripts/js_stack/base/marionette/1.7.3.js +0 -2765
  15. data/vendor/assets/javascripts/js_stack/plugins/backbone/associations/0.5.1.js +0 -533
  16. data/vendor/assets/javascripts/js_stack/plugins/backbone/associations/0.5.4.js +0 -574
  17. data/vendor/assets/javascripts/js_stack/plugins/backbone/mutators/0.4.1.js +0 -207
  18. data/vendor/assets/javascripts/js_stack/plugins/backbone/pageable/1.4.5.js +0 -1318
  19. data/vendor/assets/javascripts/js_stack/plugins/backbone/virtualcollection/0.4.11.js +0 -345
  20. data/vendor/assets/javascripts/js_stack/plugins/backbone/virtualcollection/0.4.12.js +0 -351
  21. data/vendor/assets/javascripts/js_stack/plugins/backbone/virtualcollection/0.4.14.js +0 -398
  22. data/vendor/assets/javascripts/js_stack/plugins/backbone/virtualcollection/0.4.5.js +0 -293
  23. data/vendor/assets/javascripts/js_stack/plugins/backbone/virtualcollection/0.4.8.js +0 -340
@@ -0,0 +1,595 @@
1
+ // Backbone.Stickit v0.8.0, MIT Licensed
2
+ // Copyright (c) 2012 The New York Times, CMS Group, Matthew DeLambo <delambo@gmail.com>
3
+
4
+ (function (factory) {
5
+
6
+ // Set up Stickit appropriately for the environment. Start with AMD.
7
+ if (typeof define === 'function' && define.amd) {
8
+ define(['underscore', 'backbone', 'exports'], factory);
9
+ }
10
+
11
+ // Next for Node.js or CommonJS.
12
+ else if (typeof exports === 'object') {
13
+ factory(require('underscore'), require('backbone'), exports);
14
+ }
15
+
16
+ // Finally, as a browser global.
17
+ else {
18
+ factory(_, Backbone, {});
19
+ }
20
+
21
+ }(function (_, Backbone, Stickit) {
22
+
23
+ // Stickit Namespace
24
+ // --------------------------
25
+
26
+ Stickit._handlers = [];
27
+
28
+ Stickit.addHandler = function(handlers) {
29
+ // Fill-in default values.
30
+ handlers = _.map(_.flatten([handlers]), function(handler) {
31
+ return _.extend({
32
+ updateModel: true,
33
+ updateView: true,
34
+ updateMethod: 'text'
35
+ }, handler);
36
+ });
37
+ this._handlers = this._handlers.concat(handlers);
38
+ };
39
+
40
+ // Backbone.View Mixins
41
+ // --------------------
42
+
43
+ Stickit.ViewMixin = {
44
+
45
+ // Collection of model event bindings.
46
+ // [{model,event,fn,config}, ...]
47
+ _modelBindings: null,
48
+
49
+ // Unbind the model and event bindings from `this._modelBindings` and
50
+ // `this.$el`. If the optional `model` parameter is defined, then only
51
+ // delete bindings for the given `model` and its corresponding view events.
52
+ unstickit: function(model, bindingSelector) {
53
+ // Support bindings hash in place of selector.
54
+ if (_.isObject(bindingSelector)) {
55
+ _.each(_.keys(bindingSelector), function(selector) {
56
+ this.unstickit(model, selector);
57
+ }, this);
58
+ return;
59
+ }
60
+
61
+ var models = [], destroyFns = [];
62
+ _.each(this._modelBindings, function(binding, i) {
63
+ if (model && binding.model !== model) { return; }
64
+ if (bindingSelector && binding.config.selector != bindingSelector) return;
65
+ destroyFns.push(binding.config._destroy);
66
+ binding.model.off(binding.event, binding.fn);
67
+ models.push(binding.model);
68
+ delete this._modelBindings[i];
69
+ }, this);
70
+
71
+ // Trigger an event for each model that was unbound.
72
+ _.invoke(_.uniq(models), 'trigger', 'stickit:unstuck', this.cid);
73
+ // Call `_destroy` on a unique list of the binding callbacks.
74
+ _.each(_.uniq(destroyFns), function(fn) { fn.call(this); }, this);
75
+ // Cleanup the null values.
76
+ this._modelBindings = _.compact(this._modelBindings);
77
+
78
+ this.$el.off('.stickit' + (model ? '.' + model.cid : ''), bindingSelector);
79
+ },
80
+
81
+ // Using `this.bindings` configuration or the `optionalBindingsConfig`, binds `this.model`
82
+ // or the `optionalModel` to elements in the view.
83
+ stickit: function(optionalModel, optionalBindingsConfig) {
84
+ var model = optionalModel || this.model,
85
+ bindings = optionalBindingsConfig || _.result(this, "bindings") || {};
86
+
87
+ this._modelBindings || (this._modelBindings = []);
88
+
89
+ // Iterate through the selectors in the bindings configuration and configure
90
+ // the various options for each field.
91
+ this.addBinding(model, bindings);
92
+
93
+ // Wrap `view.remove` to unbind stickit model and dom events.
94
+ var remove = this.remove;
95
+ if (!remove.stickitWrapped) {
96
+ this.remove = function() {
97
+ var ret = this;
98
+ this.unstickit();
99
+ if (remove) ret = remove.apply(this, arguments);
100
+ return ret;
101
+ };
102
+ }
103
+ this.remove.stickitWrapped = true;
104
+ return this;
105
+ },
106
+
107
+ // Add a single model binding to the view
108
+ addBinding: function(optionalModel, second, _binding) {
109
+ var $el, options, modelAttr, config, selector,
110
+ model = optionalModel || this.model,
111
+ namespace = '.stickit.' + model.cid,
112
+ binding = _binding || {},
113
+ bindId = _.uniqueId();
114
+
115
+ // Allow jQuery-style {key: val} event maps
116
+ if (_.isString(second)) {
117
+ selector = second;
118
+ } else {
119
+ var bindings = second;
120
+ _.each(bindings, function(v, selector) {
121
+ this.addBinding(model, selector, bindings[selector]);
122
+ }, this);
123
+ return;
124
+ }
125
+
126
+ // Support ':el' selector - special case selector for the view managed delegate.
127
+ $el = selector === ':el' ? this.$el : this.$(selector);
128
+
129
+ this.unstickit(model, selector);
130
+
131
+ // Fail fast if the selector didn't match an element.
132
+ if (!$el.length) return;
133
+
134
+ // Allow shorthand setting of model attributes - `'selector':'observe'`.
135
+ if (_.isString(binding)) binding = {observe:binding};
136
+
137
+ // Handle case where `observe` is in the form of a function.
138
+ if (_.isFunction(binding.observe)) binding.observe = binding.observe.call(this);
139
+
140
+ config = getConfiguration($el, binding);
141
+ config.selector = selector;
142
+ modelAttr = config.observe;
143
+
144
+ // Create the model set options with a unique `bindId` so that we
145
+ // can avoid double-binding in the `change:attribute` event handler.
146
+ config.bindId = bindId;
147
+
148
+ // Add a reference to the view for handlers of stickitChange events
149
+ config.view = this;
150
+ options = _.extend({stickitChange:config}, config.setOptions);
151
+
152
+ // Add a `_destroy` callback to the configuration, in case `destroy`
153
+ // is a named function and we need a unique function when unsticking.
154
+ config._destroy = function() {
155
+ applyViewFn(this, config.destroy, $el, model, config);
156
+ };
157
+
158
+ initializeAttributes(this, $el, config, model, modelAttr);
159
+
160
+ initializeClasses(this, $el, config, model, modelAttr);
161
+
162
+ initializeVisible(this, $el, config, model, modelAttr);
163
+
164
+ if (modelAttr) {
165
+ // Setup one-way, form element to model, bindings.
166
+ _.each(config.events, function(type) {
167
+ var event = type + namespace;
168
+ var method = function(event) {
169
+ var val = config.getVal.call(this, $el, event, config, _.rest(arguments));
170
+ // Don't update the model if false is returned from the `updateModel` configuration.
171
+ if (evaluateBoolean(this, config.updateModel, val, event, config))
172
+ setAttr(model, modelAttr, val, options, this, config);
173
+ };
174
+ method = _.bind(method, this);
175
+ if (selector === ':el') this.$el.on(event, method);
176
+ else this.$el.on(event, selector, method);
177
+ }, this);
178
+
179
+ // Setup a `change:modelAttr` observer to keep the view element in sync.
180
+ // `modelAttr` may be an array of attributes or a single string value.
181
+ _.each(_.flatten([modelAttr]), function(attr) {
182
+ observeModelEvent(model, this, 'change:'+attr, config, function(model, val, options) {
183
+ var changeId = options && options.stickitChange && options.stickitChange.bindId || null;
184
+ if (changeId !== bindId)
185
+ updateViewBindEl(this, $el, config, getAttr(model, modelAttr, config, this), model);
186
+ });
187
+ }, this);
188
+
189
+ updateViewBindEl(this, $el, config, getAttr(model, modelAttr, config, this), model, true);
190
+ }
191
+
192
+ // After each binding is setup, call the `initialize` callback.
193
+ applyViewFn(this, config.initialize, $el, model, config);
194
+ }
195
+ };
196
+
197
+ _.extend(Backbone.View.prototype, Stickit.ViewMixin);
198
+
199
+ // Helpers
200
+ // -------
201
+
202
+ // Evaluates the given `path` (in object/dot-notation) relative to the given
203
+ // `obj`. If the path is null/undefined, then the given `obj` is returned.
204
+ var evaluatePath = function(obj, path) {
205
+ var parts = (path || '').split('.');
206
+ var result = _.reduce(parts, function(memo, i) { return memo[i]; }, obj);
207
+ return result == null ? obj : result;
208
+ };
209
+
210
+ // If the given `fn` is a string, then view[fn] is called, otherwise it is
211
+ // a function that should be executed.
212
+ var applyViewFn = function(view, fn) {
213
+ if (fn) return (_.isString(fn) ? evaluatePath(view,fn) : fn).apply(view, _.rest(arguments, 2));
214
+ };
215
+
216
+ var getSelectedOption = function($select) { return $select.find('option').not(function(){ return !this.selected; }); };
217
+
218
+ // Given a function, string (view function reference), or a boolean
219
+ // value, returns the truthy result. Any other types evaluate as false.
220
+ var evaluateBoolean = function(view, reference) {
221
+ if (_.isBoolean(reference)) return reference;
222
+ else if (_.isFunction(reference) || _.isString(reference))
223
+ return applyViewFn.apply(this, arguments);
224
+ return false;
225
+ };
226
+
227
+ // Setup a model event binding with the given function, and track the event
228
+ // in the view's _modelBindings.
229
+ var observeModelEvent = function(model, view, event, config, fn) {
230
+ model.on(event, fn, view);
231
+ view._modelBindings.push({model:model, event:event, fn:fn, config:config});
232
+ };
233
+
234
+ // Prepares the given `val`ue and sets it into the `model`.
235
+ var setAttr = function(model, attr, val, options, context, config) {
236
+ var value = {};
237
+ if (config.onSet)
238
+ val = applyViewFn(context, config.onSet, val, config);
239
+
240
+ if (config.set)
241
+ applyViewFn(context, config.set, attr, val, options, config);
242
+ else {
243
+ value[attr] = val;
244
+ // If `observe` is defined as an array and `onSet` returned
245
+ // an array, then map attributes to their values.
246
+ if (_.isArray(attr) && _.isArray(val)) {
247
+ value = _.reduce(attr, function(memo, attribute, index) {
248
+ memo[attribute] = _.has(val, index) ? val[index] : null;
249
+ return memo;
250
+ }, {});
251
+ }
252
+ model.set(value, options);
253
+ }
254
+ };
255
+
256
+ // Returns the given `attr`'s value from the `model`, escaping and
257
+ // formatting if necessary. If `attr` is an array, then an array of
258
+ // respective values will be returned.
259
+ var getAttr = function(model, attr, config, context) {
260
+ var val,
261
+ retrieveVal = function(field) {
262
+ return model[config.escape ? 'escape' : 'get'](field);
263
+ },
264
+ sanitizeVal = function(val) {
265
+ return val == null ? '' : val;
266
+ };
267
+ val = _.isArray(attr) ? _.map(attr, retrieveVal) : retrieveVal(attr);
268
+ if (config.onGet) val = applyViewFn(context, config.onGet, val, config);
269
+ return _.isArray(val) ? _.map(val, sanitizeVal) : sanitizeVal(val);
270
+ };
271
+
272
+ // Find handlers in `Backbone.Stickit._handlers` with selectors that match
273
+ // `$el` and generate a configuration by mixing them in the order that they
274
+ // were found with the given `binding`.
275
+ var getConfiguration = Stickit.getConfiguration = function($el, binding) {
276
+ var handlers = [{
277
+ updateModel: false,
278
+ updateMethod: 'text',
279
+ update: function($el, val, m, opts) { if ($el[opts.updateMethod]) $el[opts.updateMethod](val); },
280
+ getVal: function($el, e, opts) { return $el[opts.updateMethod](); }
281
+ }];
282
+ handlers = handlers.concat(_.filter(Stickit._handlers, function(handler) {
283
+ return $el.is(handler.selector);
284
+ }));
285
+ handlers.push(binding);
286
+ var config = _.extend.apply(_, handlers);
287
+ // `updateView` is defaulted to false for configutrations with
288
+ // `visible`; otherwise, `updateView` is defaulted to true.
289
+ if (config.visible && !_.has(config, 'updateView')) config.updateView = false;
290
+ else if (!_.has(config, 'updateView')) config.updateView = true;
291
+ return config;
292
+ };
293
+
294
+ // Setup the attributes configuration - a list that maps an attribute or
295
+ // property `name`, to an `observe`d model attribute, using an optional
296
+ // `onGet` formatter.
297
+ //
298
+ // attributes: [{
299
+ // name: 'attributeOrPropertyName',
300
+ // observe: 'modelAttrName'
301
+ // onGet: function(modelAttrVal, modelAttrName) { ... }
302
+ // }, ...]
303
+ //
304
+ var initializeAttributes = function(view, $el, config, model, modelAttr) {
305
+ var props = ['autofocus', 'autoplay', 'async', 'checked', 'controls', 'defer', 'disabled', 'hidden', 'indeterminate', 'loop', 'multiple', 'open', 'readonly', 'required', 'scoped', 'selected'];
306
+
307
+ _.each(config.attributes || [], function(attrConfig) {
308
+ var lastClass = '', observed, updateAttr;
309
+ attrConfig = _.clone(attrConfig);
310
+ observed = attrConfig.observe || (attrConfig.observe = modelAttr),
311
+ updateAttr = function() {
312
+ var updateType = _.indexOf(props, attrConfig.name, true) > -1 ? 'prop' : 'attr',
313
+ val = getAttr(model, observed, attrConfig, view);
314
+ // If it is a class then we need to remove the last value and add the new.
315
+ if (attrConfig.name === 'class') {
316
+ $el.removeClass(lastClass).addClass(val);
317
+ lastClass = val;
318
+ }
319
+ else $el[updateType](attrConfig.name, val);
320
+ };
321
+ _.each(_.flatten([observed]), function(attr) {
322
+ observeModelEvent(model, view, 'change:' + attr, config, updateAttr);
323
+ });
324
+ updateAttr();
325
+ });
326
+ };
327
+
328
+ var initializeClasses = function(view, $el, config, model, modelAttr) {
329
+ _.each(config.classes || [], function(classConfig, name) {
330
+ var observed, updateClass;
331
+ observed = classConfig.observe || classConfig;
332
+ updateClass = function() {
333
+ var val = getAttr(model, observed, classConfig, view);
334
+ $el.toggleClass(name, !!val);
335
+ };
336
+
337
+ _.each(_.flatten([observed]), function(attr) {
338
+ observeModelEvent(model, view, 'change:' + attr, config, updateClass);
339
+ });
340
+ updateClass();
341
+ });
342
+ };
343
+
344
+ // If `visible` is configured, then the view element will be shown/hidden
345
+ // based on the truthiness of the modelattr's value or the result of the
346
+ // given callback. If a `visibleFn` is also supplied, then that callback
347
+ // will be executed to manually handle showing/hiding the view element.
348
+ //
349
+ // observe: 'isRight',
350
+ // visible: true, // or function(val, options) {}
351
+ // visibleFn: function($el, isVisible, options) {} // optional handler
352
+ //
353
+ var initializeVisible = function(view, $el, config, model, modelAttr) {
354
+ if (config.visible == null) return;
355
+ var visibleCb = function() {
356
+ var visible = config.visible,
357
+ visibleFn = config.visibleFn,
358
+ val = getAttr(model, modelAttr, config, view),
359
+ isVisible = !!val;
360
+ // If `visible` is a function then it should return a boolean result to show/hide.
361
+ if (_.isFunction(visible) || _.isString(visible)) isVisible = !!applyViewFn(view, visible, val, config);
362
+ // Either use the custom `visibleFn`, if provided, or execute the standard show/hide.
363
+ if (visibleFn) applyViewFn(view, visibleFn, $el, isVisible, config);
364
+ else {
365
+ $el.toggle(isVisible);
366
+ }
367
+ };
368
+ _.each(_.flatten([modelAttr]), function(attr) {
369
+ observeModelEvent(model, view, 'change:' + attr, config, visibleCb);
370
+ });
371
+ visibleCb();
372
+ };
373
+
374
+ // Update the value of `$el` using the given configuration and trigger the
375
+ // `afterUpdate` callback. This action may be blocked by `config.updateView`.
376
+ //
377
+ // update: function($el, val, model, options) {}, // handler for updating
378
+ // updateView: true, // defaults to true
379
+ // afterUpdate: function($el, val, options) {} // optional callback
380
+ //
381
+ var updateViewBindEl = function(view, $el, config, val, model, isInitializing) {
382
+ if (!evaluateBoolean(view, config.updateView, val, config)) return;
383
+ applyViewFn(view, config.update, $el, val, model, config);
384
+ if (!isInitializing) applyViewFn(view, config.afterUpdate, $el, val, config);
385
+ };
386
+
387
+ // Default Handlers
388
+ // ----------------
389
+
390
+ Stickit.addHandler([{
391
+ selector: '[contenteditable="true"]',
392
+ updateMethod: 'html',
393
+ events: ['input', 'change']
394
+ }, {
395
+ selector: 'input',
396
+ events: ['propertychange', 'input', 'change'],
397
+ update: function($el, val) { $el.val(val); },
398
+ getVal: function($el) {
399
+ return $el.val();
400
+ }
401
+ }, {
402
+ selector: 'textarea',
403
+ events: ['propertychange', 'input', 'change'],
404
+ update: function($el, val) { $el.val(val); },
405
+ getVal: function($el) { return $el.val(); }
406
+ }, {
407
+ selector: 'input[type="radio"]',
408
+ events: ['change'],
409
+ update: function($el, val) {
410
+ $el.filter('[value="'+val+'"]').prop('checked', true);
411
+ },
412
+ getVal: function($el) {
413
+ return $el.filter(':checked').val();
414
+ }
415
+ }, {
416
+ selector: 'input[type="checkbox"]',
417
+ events: ['change'],
418
+ update: function($el, val, model, options) {
419
+ if ($el.length > 1) {
420
+ // There are multiple checkboxes so we need to go through them and check
421
+ // any that have value attributes that match what's in the array of `val`s.
422
+ val || (val = []);
423
+ $el.each(function(i, el) {
424
+ var checkbox = Backbone.$(el);
425
+ var checked = _.contains(val, checkbox.val());
426
+ checkbox.prop('checked', checked);
427
+ });
428
+ } else {
429
+ var checked = _.isBoolean(val) ? val : val === $el.val();
430
+ $el.prop('checked', checked);
431
+ }
432
+ },
433
+ getVal: function($el) {
434
+ var val;
435
+ if ($el.length > 1) {
436
+ val = _.reduce($el, function(memo, el) {
437
+ var checkbox = Backbone.$(el);
438
+ if (checkbox.prop('checked')) memo.push(checkbox.val());
439
+ return memo;
440
+ }, []);
441
+ } else {
442
+ val = $el.prop('checked');
443
+ // If the checkbox has a value attribute defined, then
444
+ // use that value. Most browsers use "on" as a default.
445
+ var boxval = $el.val();
446
+ if (boxval !== 'on' && boxval != null) {
447
+ val = val ? $el.val() : null;
448
+ }
449
+ }
450
+ return val;
451
+ }
452
+ }, {
453
+ selector: 'select',
454
+ events: ['change'],
455
+ update: function($el, val, model, options) {
456
+ var optList,
457
+ selectConfig = options.selectOptions,
458
+ list = selectConfig && selectConfig.collection || undefined,
459
+ isMultiple = $el.prop('multiple');
460
+
461
+ // If there are no `selectOptions` then we assume that the `<select>`
462
+ // is pre-rendered and that we need to generate the collection.
463
+ if (!selectConfig) {
464
+ selectConfig = {};
465
+ var getList = function($el) {
466
+ return $el.map(function() {
467
+ return {value:this.value, label:this.text};
468
+ }).get();
469
+ };
470
+ if ($el.find('optgroup').length) {
471
+ list = {opt_labels:[]};
472
+ // Search for options without optgroup
473
+ if ($el.find('> option').length) {
474
+ list.opt_labels.push(undefined);
475
+ _.each($el.find('> option'), function(el) {
476
+ list[undefined] = getList(Backbone.$(el));
477
+ });
478
+ }
479
+ _.each($el.find('optgroup'), function(el) {
480
+ var label = Backbone.$(el).attr('label');
481
+ list.opt_labels.push(label);
482
+ list[label] = getList(Backbone.$(el).find('option'));
483
+ });
484
+ } else {
485
+ list = getList($el.find('option'));
486
+ }
487
+ }
488
+
489
+ // Fill in default label and path values.
490
+ selectConfig.valuePath = selectConfig.valuePath || 'value';
491
+ selectConfig.labelPath = selectConfig.labelPath || 'label';
492
+
493
+ var addSelectOptions = function(optList, $el, fieldVal) {
494
+ _.each(optList, function(obj) {
495
+ var option = Backbone.$('<option/>'), optionVal = obj;
496
+
497
+ var fillOption = function(text, val) {
498
+ option.text(text);
499
+ optionVal = val;
500
+ // Save the option value as data so that we can reference it later.
501
+ option.data('stickit_bind_val', optionVal);
502
+ if (!_.isArray(optionVal) && !_.isObject(optionVal)) option.val(optionVal);
503
+ };
504
+
505
+ if (obj === '__default__')
506
+ fillOption(selectConfig.defaultOption.label, selectConfig.defaultOption.value);
507
+ else
508
+ fillOption(evaluatePath(obj, selectConfig.labelPath), evaluatePath(obj, selectConfig.valuePath));
509
+
510
+ // Determine if this option is selected.
511
+ if (!isMultiple && optionVal != null && fieldVal != null && optionVal === fieldVal || (_.isObject(fieldVal) && _.isEqual(optionVal, fieldVal)))
512
+ option.prop('selected', true);
513
+ else if (isMultiple && _.isArray(fieldVal)) {
514
+ _.each(fieldVal, function(val) {
515
+ if (_.isObject(val)) val = evaluatePath(val, selectConfig.valuePath);
516
+ if (val === optionVal || (_.isObject(val) && _.isEqual(optionVal, val)))
517
+ option.prop('selected', true);
518
+ });
519
+ }
520
+
521
+ $el.append(option);
522
+ });
523
+ };
524
+
525
+ $el.find('*').remove();
526
+
527
+ // The `list` configuration is a function that returns the options list or a string
528
+ // which represents the path to the list relative to `window` or the view/`this`.
529
+ var evaluate = function(view, list) {
530
+ var context = window;
531
+ if (list.indexOf('this.') === 0) context = view;
532
+ list = list.replace(/^[a-z]*\.(.+)$/, '$1');
533
+ return evaluatePath(context, list);
534
+ };
535
+ if (_.isString(list)) optList = evaluate(this, list);
536
+ else if (_.isFunction(list)) optList = applyViewFn(this, list, $el, options);
537
+ else optList = list;
538
+
539
+ // Support Backbone.Collection and deserialize.
540
+ if (optList instanceof Backbone.Collection) optList = optList.toJSON();
541
+
542
+ if (selectConfig.defaultOption) {
543
+ addSelectOptions(["__default__"], $el);
544
+ }
545
+
546
+ if (_.isArray(optList)) {
547
+ addSelectOptions(optList, $el, val);
548
+ } else if (optList.opt_labels) {
549
+ // To define a select with optgroups, format selectOptions.collection as an object
550
+ // with an 'opt_labels' property, as in the following:
551
+ //
552
+ // {
553
+ // 'opt_labels': ['Looney Tunes', 'Three Stooges'],
554
+ // 'Looney Tunes': [{id: 1, name: 'Bugs Bunny'}, {id: 2, name: 'Donald Duck'}],
555
+ // 'Three Stooges': [{id: 3, name : 'moe'}, {id: 4, name : 'larry'}, {id: 5, name : 'curly'}]
556
+ // }
557
+ //
558
+ _.each(optList.opt_labels, function(label) {
559
+ var $group = Backbone.$('<optgroup/>').attr('label', label);
560
+ addSelectOptions(optList[label], $group, val);
561
+ $el.append($group);
562
+ });
563
+ // With no 'opt_labels' parameter, the object is assumed to be a simple value-label map.
564
+ // Pass a selectOptions.comparator to override the default order of alphabetical by label.
565
+ } else {
566
+ var opts = [], opt;
567
+ for (var i in optList) {
568
+ opt = {};
569
+ opt[selectConfig.valuePath] = i;
570
+ opt[selectConfig.labelPath] = optList[i];
571
+ opts.push(opt);
572
+ }
573
+ addSelectOptions(_.sortBy(opts, selectConfig.comparator || selectConfig.labelPath), $el, val);
574
+ }
575
+ },
576
+ getVal: function($el) {
577
+ var val;
578
+ if ($el.prop('multiple')) {
579
+ val = Backbone.$(getSelectedOption($el).map(function() {
580
+ return Backbone.$(this).data('stickit_bind_val');
581
+ })).get();
582
+ } else {
583
+ val = getSelectedOption($el).data('stickit_bind_val');
584
+ }
585
+ return val;
586
+ }
587
+ }]);
588
+
589
+
590
+ // Export onto Backbone object
591
+ Backbone.Stickit = Stickit;
592
+
593
+ return Backbone.Stickit;
594
+
595
+ }));
@@ -1 +1 @@
1
- //= require js_stack/plugins/backbone/stickit/0.7.0
1
+ //= require js_stack/plugins/backbone/stickit/0.8.0
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.7
4
+ version: 0.6.0
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-15 00:00:00.000000000 Z
12
+ date: 2014-04-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: haml_coffee_assets
@@ -103,8 +103,6 @@ files:
103
103
  - vendor/assets/javascripts/js_stack/base.js
104
104
  - vendor/assets/javascripts/js_stack/base/backbone.js
105
105
  - vendor/assets/javascripts/js_stack/base/backbone/1.0.0.js
106
- - vendor/assets/javascripts/js_stack/base/backbone/1.1.0.js
107
- - vendor/assets/javascripts/js_stack/base/backbone/1.1.1.js
108
106
  - vendor/assets/javascripts/js_stack/base/backbone/1.1.2.js
109
107
  - vendor/assets/javascripts/js_stack/base/hamlcoffee.js
110
108
  - vendor/assets/javascripts/js_stack/base/jsroutes.js
@@ -112,12 +110,9 @@ files:
112
110
  - vendor/assets/javascripts/js_stack/base/marionette/1.1.0.js
113
111
  - vendor/assets/javascripts/js_stack/base/marionette/1.4.1.js
114
112
  - vendor/assets/javascripts/js_stack/base/marionette/1.5.1.js
115
- - vendor/assets/javascripts/js_stack/base/marionette/1.6.2.js
116
113
  - vendor/assets/javascripts/js_stack/base/marionette/1.6.4.js
117
- - vendor/assets/javascripts/js_stack/base/marionette/1.7.0.js
118
- - vendor/assets/javascripts/js_stack/base/marionette/1.7.3.js
119
114
  - vendor/assets/javascripts/js_stack/base/marionette/1.7.4.js
120
- - vendor/assets/javascripts/js_stack/base/marionette/1.8.0.js
115
+ - vendor/assets/javascripts/js_stack/base/marionette/1.8.3.js
121
116
  - vendor/assets/javascripts/js_stack/base/underscore.js
122
117
  - vendor/assets/javascripts/js_stack/base/underscore/1.5.2.js
123
118
  - vendor/assets/javascripts/js_stack/base/underscore/1.6.0.js
@@ -130,27 +125,19 @@ files:
130
125
  - vendor/assets/javascripts/js_stack/plugins/backbone.stickit.js
131
126
  - vendor/assets/javascripts/js_stack/plugins/backbone.validation.js
132
127
  - vendor/assets/javascripts/js_stack/plugins/backbone.virtualcollection.js
133
- - vendor/assets/javascripts/js_stack/plugins/backbone/associations/0.5.1.js
134
- - vendor/assets/javascripts/js_stack/plugins/backbone/associations/0.5.4.js
135
128
  - vendor/assets/javascripts/js_stack/plugins/backbone/associations/0.5.5.js
136
129
  - vendor/assets/javascripts/js_stack/plugins/backbone/associations/0.6.1.js
137
130
  - vendor/assets/javascripts/js_stack/plugins/backbone/deepmodel/0.10.4.js
138
- - vendor/assets/javascripts/js_stack/plugins/backbone/mutators/0.4.1.js
139
131
  - vendor/assets/javascripts/js_stack/plugins/backbone/mutators/0.4.2.js
140
132
  - vendor/assets/javascripts/js_stack/plugins/backbone/pageable/1.3.2.js
141
- - vendor/assets/javascripts/js_stack/plugins/backbone/pageable/1.4.5.js
142
133
  - vendor/assets/javascripts/js_stack/plugins/backbone/pageable/1.4.8.js
143
134
  - vendor/assets/javascripts/js_stack/plugins/backbone/routefilter/0.2.0.js
144
135
  - vendor/assets/javascripts/js_stack/plugins/backbone/stickit/0.6.3.js
145
136
  - vendor/assets/javascripts/js_stack/plugins/backbone/stickit/0.7.0.js
137
+ - vendor/assets/javascripts/js_stack/plugins/backbone/stickit/0.8.0.js
146
138
  - vendor/assets/javascripts/js_stack/plugins/backbone/validation/0.8.1.js
147
139
  - vendor/assets/javascripts/js_stack/plugins/backbone/validation/0.9.1.js
148
- - vendor/assets/javascripts/js_stack/plugins/backbone/virtualcollection/0.4.11.js
149
- - vendor/assets/javascripts/js_stack/plugins/backbone/virtualcollection/0.4.12.js
150
- - vendor/assets/javascripts/js_stack/plugins/backbone/virtualcollection/0.4.14.js
151
140
  - vendor/assets/javascripts/js_stack/plugins/backbone/virtualcollection/0.4.15.js
152
- - vendor/assets/javascripts/js_stack/plugins/backbone/virtualcollection/0.4.5.js
153
- - vendor/assets/javascripts/js_stack/plugins/backbone/virtualcollection/0.4.8.js
154
141
  - vendor/assets/javascripts/js_stack/plugins/cocktail.js
155
142
  - vendor/assets/javascripts/js_stack/plugins/cocktail/0.5.3.js
156
143
  - vendor/assets/javascripts/js_stack/plugins/moment.js