backbone-stickit-rails 0.6.3
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.
- checksums.yaml +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +33 -0
- data/lib/backbone/stickit/rails.rb +10 -0
- data/lib/backbone/stickit/rails/version.rb +7 -0
- data/vendor/assets/javascripts/backbone.stickit.js +468 -0
- metadata +97 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ce28e2d9b7f84a8ab32ac88627c31c81b4ca3c6a
|
4
|
+
data.tar.gz: 33fcc80f659cedff12c6838e7221b5383cba7c7a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 27acf5e40c9a5474f4b07056954259898a85b295b686463301adf126f4cac0c0a1c8a61b07feabdacf50866bd318984a2351b6407d2dbf07b781c813b7f44789
|
7
|
+
data.tar.gz: 36f1502fdc633b8ba3f9f8653f88de01708aa2bb450a28ebdb4682a07c797a9b5206a12e89a701163846822546624644c03ef21823bc6b4765aec5cbfa3908c8
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Sean Griffin
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# Backbone.Stickit Rails
|
2
|
+
|
3
|
+
A simple wrapper for backbone.stickit for use with the Rails asset pipeline
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'backbone-stickit-rails'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install backbone-stickit-rails
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
Add the following line to application.js
|
22
|
+
|
23
|
+
```javascript
|
24
|
+
//= require backbone.stickit
|
25
|
+
```
|
26
|
+
|
27
|
+
## Contributing
|
28
|
+
|
29
|
+
1. Fork it
|
30
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
31
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
32
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
33
|
+
5. Create new Pull Request
|
@@ -0,0 +1,468 @@
|
|
1
|
+
//
|
2
|
+
// backbone.stickit - v0.6.3
|
3
|
+
// The MIT License
|
4
|
+
// Copyright (c) 2012 The New York Times, CMS Group, Matthew DeLambo <delambo@gmail.com>
|
5
|
+
//
|
6
|
+
(function($) {
|
7
|
+
|
8
|
+
// Backbone.Stickit Namespace
|
9
|
+
// --------------------------
|
10
|
+
|
11
|
+
Backbone.Stickit = {
|
12
|
+
|
13
|
+
_handlers: [],
|
14
|
+
|
15
|
+
addHandler: function(handlers) {
|
16
|
+
// Fill-in default values.
|
17
|
+
handlers = _.map(_.flatten([handlers]), function(handler) {
|
18
|
+
return _.extend({
|
19
|
+
updateModel: true,
|
20
|
+
updateView: true,
|
21
|
+
updateMethod: 'text'
|
22
|
+
}, handler);
|
23
|
+
});
|
24
|
+
this._handlers = this._handlers.concat(handlers);
|
25
|
+
}
|
26
|
+
};
|
27
|
+
|
28
|
+
// Backbone.View Mixins
|
29
|
+
// --------------------
|
30
|
+
|
31
|
+
_.extend(Backbone.View.prototype, {
|
32
|
+
|
33
|
+
// Collection of model event bindings.
|
34
|
+
// [{model,event,fn}, ...]
|
35
|
+
_modelBindings: null,
|
36
|
+
|
37
|
+
// Unbind the model and event bindings from `this._modelBindings` and
|
38
|
+
// `this.$el`. If the optional `model` parameter is defined, then only
|
39
|
+
// delete bindings for the given `model` and its corresponding view events.
|
40
|
+
unstickit: function(model) {
|
41
|
+
_.each(this._modelBindings, _.bind(function(binding, i) {
|
42
|
+
if (model && binding.model !== model) return false;
|
43
|
+
binding.model.off(binding.event, binding.fn);
|
44
|
+
delete this._modelBindings[i];
|
45
|
+
}, this));
|
46
|
+
this._modelBindings = _.compact(this._modelBindings);
|
47
|
+
|
48
|
+
this.$el.off('.stickit' + (model ? '.' + model.cid : ''));
|
49
|
+
},
|
50
|
+
|
51
|
+
// Using `this.bindings` configuration or the `optionalBindingsConfig`, binds `this.model`
|
52
|
+
// or the `optionalModel` to elements in the view.
|
53
|
+
stickit: function(optionalModel, optionalBindingsConfig) {
|
54
|
+
var self = this,
|
55
|
+
model = optionalModel || this.model,
|
56
|
+
namespace = '.stickit.' + model.cid,
|
57
|
+
bindings = optionalBindingsConfig || this.bindings || {};
|
58
|
+
|
59
|
+
this._modelBindings || (this._modelBindings = []);
|
60
|
+
this.unstickit(model);
|
61
|
+
|
62
|
+
// Iterate through the selectors in the bindings configuration and configure
|
63
|
+
// the various options for each field.
|
64
|
+
_.each(_.keys(bindings), function(selector) {
|
65
|
+
var $el, options, modelAttr, config,
|
66
|
+
binding = bindings[selector] || {},
|
67
|
+
bindKey = _.uniqueId();
|
68
|
+
|
69
|
+
// Support ':el' selector - special case selector for the view managed delegate.
|
70
|
+
if (selector != ':el') $el = self.$(selector);
|
71
|
+
else {
|
72
|
+
$el = self.$el;
|
73
|
+
selector = '';
|
74
|
+
}
|
75
|
+
|
76
|
+
// Fail fast if the selector didn't match an element.
|
77
|
+
if (!$el.length) return;
|
78
|
+
|
79
|
+
// Allow shorthand setting of model attributes - `'selector':'observe'`.
|
80
|
+
if (_.isString(binding)) binding = {observe:binding};
|
81
|
+
|
82
|
+
config = getConfiguration($el, binding);
|
83
|
+
|
84
|
+
modelAttr = config.observe;
|
85
|
+
|
86
|
+
// Create the model set options with a unique `bindKey` so that we
|
87
|
+
// can avoid double-binding in the `change:attribute` event handler.
|
88
|
+
options = _.extend({bindKey:bindKey}, config.setOptions || {});
|
89
|
+
|
90
|
+
initializeAttributes(self, $el, config, model, modelAttr);
|
91
|
+
|
92
|
+
initializeVisible(self, $el, config, model, modelAttr);
|
93
|
+
|
94
|
+
if (modelAttr) {
|
95
|
+
// Setup one-way, form element to model, bindings.
|
96
|
+
_.each(config.events || [], function(type) {
|
97
|
+
var event = type + namespace;
|
98
|
+
var method = function(event) {
|
99
|
+
var val = config.getVal.call(self, $el, event, config);
|
100
|
+
// Don't update the model if false is returned from the `updateModel` configuration.
|
101
|
+
if (evaluateBoolean(self, config.updateModel, val, config))
|
102
|
+
setAttr(model, modelAttr, val, options, self, config);
|
103
|
+
};
|
104
|
+
if (selector === '') self.$el.on(event, method);
|
105
|
+
else self.$el.on(event, selector, method);
|
106
|
+
});
|
107
|
+
|
108
|
+
// Setup a `change:modelAttr` observer to keep the view element in sync.
|
109
|
+
// `modelAttr` may be an array of attributes or a single string value.
|
110
|
+
_.each(_.flatten([modelAttr]), function(attr) {
|
111
|
+
observeModelEvent(model, self, 'change:'+attr, function(model, val, options) {
|
112
|
+
if (options == null || options.bindKey != bindKey)
|
113
|
+
updateViewBindEl(self, $el, config, getAttr(model, modelAttr, config, self), model);
|
114
|
+
});
|
115
|
+
});
|
116
|
+
|
117
|
+
updateViewBindEl(self, $el, config, getAttr(model, modelAttr, config, self), model, true);
|
118
|
+
}
|
119
|
+
|
120
|
+
// After each binding is setup, call the `initialize` callback.
|
121
|
+
applyViewFn(self, config.initialize, $el, model, config);
|
122
|
+
});
|
123
|
+
|
124
|
+
// Wrap `view.remove` to unbind stickit model and dom events.
|
125
|
+
this.remove = _.wrap(this.remove, function(oldRemove) {
|
126
|
+
self.unstickit();
|
127
|
+
if (oldRemove) oldRemove.call(self);
|
128
|
+
});
|
129
|
+
}
|
130
|
+
});
|
131
|
+
|
132
|
+
// Helpers
|
133
|
+
// -------
|
134
|
+
|
135
|
+
// Evaluates the given `path` (in object/dot-notation) relative to the given
|
136
|
+
// `obj`. If the path is null/undefined, then the given `obj` is returned.
|
137
|
+
var evaluatePath = function(obj, path) {
|
138
|
+
var parts = (path || '').split('.');
|
139
|
+
var result = _.reduce(parts, function(memo, i) { return memo[i]; }, obj);
|
140
|
+
return result == null ? obj : result;
|
141
|
+
};
|
142
|
+
|
143
|
+
// If the given `fn` is a string, then view[fn] is called, otherwise it is
|
144
|
+
// a function that should be executed.
|
145
|
+
var applyViewFn = function(view, fn) {
|
146
|
+
if (fn) return (_.isString(fn) ? view[fn] : fn).apply(view, _.toArray(arguments).slice(2));
|
147
|
+
};
|
148
|
+
|
149
|
+
var getSelectedOption = function($select) { return $select.find('option').not(function(){ return !this.selected; }); };
|
150
|
+
|
151
|
+
// Given a function, string (view function reference), or a boolean
|
152
|
+
// value, returns the truthy result. Any other types evaluate as false.
|
153
|
+
var evaluateBoolean = function(view, reference) {
|
154
|
+
if (_.isBoolean(reference)) return reference;
|
155
|
+
else if (_.isFunction(reference) || _.isString(reference))
|
156
|
+
return applyViewFn.apply(this, _.toArray(arguments));
|
157
|
+
return false;
|
158
|
+
};
|
159
|
+
|
160
|
+
// Setup a model event binding with the given function, and track the event
|
161
|
+
// in the view's _modelBindings.
|
162
|
+
var observeModelEvent = function(model, view, event, fn) {
|
163
|
+
model.on(event, fn, view);
|
164
|
+
view._modelBindings.push({model:model, event:event, fn:fn});
|
165
|
+
};
|
166
|
+
|
167
|
+
// Prepares the given `val`ue and sets it into the `model`.
|
168
|
+
var setAttr = function(model, attr, val, options, context, config) {
|
169
|
+
if (config.onSet) val = applyViewFn(context, config.onSet, val, config);
|
170
|
+
model.set(attr, val, options);
|
171
|
+
};
|
172
|
+
|
173
|
+
// Returns the given `attr`'s value from the `model`, escaping and
|
174
|
+
// formatting if necessary. If `attr` is an array, then an array of
|
175
|
+
// respective values will be returned.
|
176
|
+
var getAttr = function(model, attr, config, context) {
|
177
|
+
var val, retrieveVal = function(field) {
|
178
|
+
var retrieved = config.escape ? model.escape(field) : model.get(field);
|
179
|
+
return _.isUndefined(retrieved) ? '' : retrieved;
|
180
|
+
};
|
181
|
+
val = _.isArray(attr) ? _.map(attr, retrieveVal) : retrieveVal(attr);
|
182
|
+
return config.onGet ? applyViewFn(context, config.onGet, val, config) : val;
|
183
|
+
};
|
184
|
+
|
185
|
+
// Find handlers in `Backbone.Stickit._handlers` with selectors that match
|
186
|
+
// `$el` and generate a configuration by mixing them in the order that they
|
187
|
+
// were found with the with the givne `binding`.
|
188
|
+
var getConfiguration = function($el, binding) {
|
189
|
+
var handlers = [{
|
190
|
+
updateModel: false,
|
191
|
+
updateView: true,
|
192
|
+
updateMethod: 'text',
|
193
|
+
update: function($el, val, m, opts) { $el[opts.updateMethod](val); },
|
194
|
+
getVal: function($el, e, opts) { return $el[opts.updateMethod](); }
|
195
|
+
}];
|
196
|
+
_.each(Backbone.Stickit._handlers, function(handler) {
|
197
|
+
if ($el.is(handler.selector)) handlers.push(handler);
|
198
|
+
});
|
199
|
+
handlers.push(binding);
|
200
|
+
var config = _.extend.apply(_, handlers);
|
201
|
+
delete config.selector;
|
202
|
+
return config;
|
203
|
+
};
|
204
|
+
|
205
|
+
// Setup the attributes configuration - a list that maps an attribute or
|
206
|
+
// property `name`, to an `observe`d model attribute, using an optional
|
207
|
+
// `onGet` formatter.
|
208
|
+
//
|
209
|
+
// attributes: [{
|
210
|
+
// name: 'attributeOrPropertyName',
|
211
|
+
// observe: 'modelAttrName'
|
212
|
+
// onGet: function(modelAttrVal, modelAttrName) { ... }
|
213
|
+
// }, ...]
|
214
|
+
//
|
215
|
+
var initializeAttributes = function(view, $el, config, model, modelAttr) {
|
216
|
+
var props = ['autofocus', 'autoplay', 'async', 'checked', 'controls', 'defer', 'disabled', 'hidden', 'loop', 'multiple', 'open', 'readonly', 'required', 'scoped', 'selected'];
|
217
|
+
|
218
|
+
_.each(config.attributes || [], function(attrConfig) {
|
219
|
+
var lastClass = '',
|
220
|
+
observed = attrConfig.observe || (attrConfig.observe = modelAttr),
|
221
|
+
updateAttr = function() {
|
222
|
+
var updateType = _.indexOf(props, attrConfig.name, true) > -1 ? 'prop' : 'attr',
|
223
|
+
val = getAttr(model, observed, attrConfig, view);
|
224
|
+
// If it is a class then we need to remove the last value and add the new.
|
225
|
+
if (attrConfig.name == 'class') {
|
226
|
+
$el.removeClass(lastClass).addClass(val);
|
227
|
+
lastClass = val;
|
228
|
+
}
|
229
|
+
else $el[updateType](attrConfig.name, val);
|
230
|
+
};
|
231
|
+
_.each(_.flatten([observed]), function(attr) {
|
232
|
+
observeModelEvent(model, view, 'change:' + attr, updateAttr);
|
233
|
+
});
|
234
|
+
updateAttr();
|
235
|
+
});
|
236
|
+
};
|
237
|
+
|
238
|
+
// If `visible` is configured, then the view element will be shown/hidden
|
239
|
+
// based on the truthiness of the modelattr's value or the result of the
|
240
|
+
// given callback. If a `visibleFn` is also supplied, then that callback
|
241
|
+
// will be executed to manually handle showing/hiding the view element.
|
242
|
+
//
|
243
|
+
// observe: 'isRight',
|
244
|
+
// visible: true, // or function(val, options) {}
|
245
|
+
// visibleFn: function($el, isVisible, options) {} // optional handler
|
246
|
+
//
|
247
|
+
var initializeVisible = function(view, $el, config, model, modelAttr) {
|
248
|
+
if (config.visible == null) return;
|
249
|
+
var visibleCb = function() {
|
250
|
+
var visible = config.visible,
|
251
|
+
visibleFn = config.visibleFn,
|
252
|
+
val = getAttr(model, modelAttr, config, view),
|
253
|
+
isVisible = !!val;
|
254
|
+
// If `visible` is a function then it should return a boolean result to show/hide.
|
255
|
+
if (_.isFunction(visible) || _.isString(visible)) isVisible = applyViewFn(view, visible, val, config);
|
256
|
+
// Either use the custom `visibleFn`, if provided, or execute the standard show/hide.
|
257
|
+
if (visibleFn) applyViewFn(view, visibleFn, $el, isVisible, config);
|
258
|
+
else {
|
259
|
+
if (isVisible) $el.show();
|
260
|
+
else $el.hide();
|
261
|
+
}
|
262
|
+
};
|
263
|
+
_.each(_.flatten([modelAttr]), function(attr) {
|
264
|
+
observeModelEvent(model, view, 'change:' + attr, visibleCb);
|
265
|
+
});
|
266
|
+
visibleCb();
|
267
|
+
};
|
268
|
+
|
269
|
+
// Update the value of `$el` using the given configuration and trigger the
|
270
|
+
// `afterUpdate` callback. This action may be blocked by `config.updateView`.
|
271
|
+
//
|
272
|
+
// update: function($el, val, model, options) {}, // handler for updating
|
273
|
+
// updateView: true, // defaults to true
|
274
|
+
// afterUpdate: function($el, val, options) {} // optional callback
|
275
|
+
//
|
276
|
+
var updateViewBindEl = function(view, $el, config, val, model, isInitializing) {
|
277
|
+
if (!evaluateBoolean(view, config.updateView, val, config)) return;
|
278
|
+
config.update.call(view, $el, val, model, config);
|
279
|
+
if (!isInitializing) applyViewFn(view, config.afterUpdate, $el, val, config);
|
280
|
+
};
|
281
|
+
|
282
|
+
// Default Handlers
|
283
|
+
// ----------------
|
284
|
+
|
285
|
+
Backbone.Stickit.addHandler([{
|
286
|
+
selector: '[contenteditable="true"]',
|
287
|
+
updateMethod: 'html',
|
288
|
+
events: ['keyup', 'change', 'paste', 'cut']
|
289
|
+
}, {
|
290
|
+
selector: 'input',
|
291
|
+
events: ['keyup', 'change', 'paste', 'cut'],
|
292
|
+
update: function($el, val) { $el.val(val); },
|
293
|
+
getVal: function($el) {
|
294
|
+
var val = $el.val();
|
295
|
+
if ($el.is('[type="number"]')) return val == null ? val : Number(val);
|
296
|
+
else return val;
|
297
|
+
}
|
298
|
+
}, {
|
299
|
+
selector: 'textarea',
|
300
|
+
events: ['keyup', 'change', 'paste', 'cut'],
|
301
|
+
update: function($el, val) { $el.val(val); },
|
302
|
+
getVal: function($el) { return $el.val(); }
|
303
|
+
}, {
|
304
|
+
selector: 'input[type="radio"]',
|
305
|
+
events: ['change'],
|
306
|
+
update: function($el, val) {
|
307
|
+
$el.filter('[value="'+val+'"]').prop('checked', true);
|
308
|
+
},
|
309
|
+
getVal: function($el) {
|
310
|
+
return $el.filter(':checked').val();
|
311
|
+
}
|
312
|
+
}, {
|
313
|
+
selector: 'input[type="checkbox"]',
|
314
|
+
events: ['change'],
|
315
|
+
update: function($el, val, model, options) {
|
316
|
+
if ($el.length > 1) {
|
317
|
+
// There are multiple checkboxes so we need to go through them and check
|
318
|
+
// any that have value attributes that match what's in the array of `val`s.
|
319
|
+
val || (val = []);
|
320
|
+
_.each($el, function(el) {
|
321
|
+
if (_.indexOf(val, $(el).val()) > -1) $(el).prop('checked', true);
|
322
|
+
else $(el).prop('checked', false);
|
323
|
+
});
|
324
|
+
} else {
|
325
|
+
if (_.isBoolean(val)) $el.prop('checked', val);
|
326
|
+
else $el.prop('checked', val == $el.val());
|
327
|
+
}
|
328
|
+
},
|
329
|
+
getVal: function($el) {
|
330
|
+
var val;
|
331
|
+
if ($el.length > 1) {
|
332
|
+
val = _.reduce($el, function(memo, el) {
|
333
|
+
if ($(el).prop('checked')) memo.push($(el).val());
|
334
|
+
return memo;
|
335
|
+
}, []);
|
336
|
+
} else {
|
337
|
+
val = $el.prop('checked');
|
338
|
+
// If the checkbox has a value attribute defined, then
|
339
|
+
// use that value. Most browsers use "on" as a default.
|
340
|
+
var boxval = $el.val();
|
341
|
+
if (boxval != 'on' && boxval != null) {
|
342
|
+
if (val) val = $el.val();
|
343
|
+
else val = null;
|
344
|
+
}
|
345
|
+
}
|
346
|
+
return val;
|
347
|
+
}
|
348
|
+
}, {
|
349
|
+
selector: 'select',
|
350
|
+
events: ['change'],
|
351
|
+
update: function($el, val, model, options) {
|
352
|
+
var optList,
|
353
|
+
selectConfig = options.selectOptions,
|
354
|
+
list = selectConfig && selectConfig.collection || undefined,
|
355
|
+
isMultiple = $el.prop('multiple');
|
356
|
+
|
357
|
+
// If there are no `selectOptions` then we assume that the `<select>`
|
358
|
+
// is pre-rendered and that we need to generate the collection.
|
359
|
+
if (!selectConfig) {
|
360
|
+
selectConfig = {};
|
361
|
+
var getList = function($el) {
|
362
|
+
return $el.find('option').map(function() {
|
363
|
+
return {value:this.value, label:this.text};
|
364
|
+
}).get();
|
365
|
+
};
|
366
|
+
if ($el.find('optgroup').length) {
|
367
|
+
list = {opt_labels:[]};
|
368
|
+
_.each($el.find('optgroup'), function(el) {
|
369
|
+
var label = $(el).attr('label');
|
370
|
+
list.opt_labels.push(label);
|
371
|
+
list[label] = getList($(el));
|
372
|
+
});
|
373
|
+
} else {
|
374
|
+
list = getList($el);
|
375
|
+
}
|
376
|
+
}
|
377
|
+
|
378
|
+
// Fill in default label and path values.
|
379
|
+
selectConfig.valuePath = selectConfig.valuePath || 'value';
|
380
|
+
selectConfig.labelPath = selectConfig.labelPath || 'label';
|
381
|
+
|
382
|
+
var addSelectOptions = function(optList, $el, fieldVal) {
|
383
|
+
// Add a flag for default option at the beginning of the list.
|
384
|
+
if (selectConfig.defaultOption) {
|
385
|
+
optList = _.clone(optList);
|
386
|
+
optList.unshift('__default__');
|
387
|
+
}
|
388
|
+
_.each(optList, function(obj) {
|
389
|
+
var option = $('<option/>'), optionVal = obj;
|
390
|
+
|
391
|
+
var fillOption = function(text, val) {
|
392
|
+
option.text(text);
|
393
|
+
optionVal = val;
|
394
|
+
// Save the option value as data so that we can reference it later.
|
395
|
+
option.data('stickit_bind_val', optionVal);
|
396
|
+
if (!_.isArray(optionVal) && !_.isObject(optionVal)) option.val(optionVal);
|
397
|
+
};
|
398
|
+
|
399
|
+
if (obj === '__default__')
|
400
|
+
fillOption(selectConfig.defaultOption.label, selectConfig.defaultOption.value);
|
401
|
+
else
|
402
|
+
fillOption(evaluatePath(obj, selectConfig.labelPath), evaluatePath(obj, selectConfig.valuePath));
|
403
|
+
|
404
|
+
// Determine if this option is selected.
|
405
|
+
if (!isMultiple && optionVal != null && fieldVal != null && optionVal == fieldVal || (_.isObject(fieldVal) && _.isEqual(optionVal, fieldVal)))
|
406
|
+
option.prop('selected', true);
|
407
|
+
else if (isMultiple && _.isArray(fieldVal)) {
|
408
|
+
_.each(fieldVal, function(val) {
|
409
|
+
if (_.isObject(val)) val = evaluatePath(val, selectConfig.valuePath);
|
410
|
+
if (val == optionVal || (_.isObject(val) && _.isEqual(optionVal, val)))
|
411
|
+
option.prop('selected', true);
|
412
|
+
});
|
413
|
+
}
|
414
|
+
|
415
|
+
$el.append(option);
|
416
|
+
});
|
417
|
+
};
|
418
|
+
|
419
|
+
$el.html('');
|
420
|
+
|
421
|
+
// The `list` configuration is a function that returns the options list or a string
|
422
|
+
// which represents the path to the list relative to `window` or the view/`this`.
|
423
|
+
var evaluate = function(view, list) {
|
424
|
+
var context = window;
|
425
|
+
if (list.indexOf('this.') === 0) context = view;
|
426
|
+
list = list.replace(/^[a-z]*\.(.+)$/, '$1');
|
427
|
+
return evaluatePath(context, list);
|
428
|
+
};
|
429
|
+
if (_.isString(list)) optList = evaluate(this, list);
|
430
|
+
else if (_.isFunction(list)) optList = applyViewFn(this, list, $el, options);
|
431
|
+
else optList = list;
|
432
|
+
|
433
|
+
// Support Backbone.Collection and deserialize.
|
434
|
+
if (optList instanceof Backbone.Collection) optList = optList.toJSON();
|
435
|
+
|
436
|
+
if (_.isArray(optList)) {
|
437
|
+
addSelectOptions(optList, $el, val);
|
438
|
+
} else {
|
439
|
+
// If the optList is an object, then it should be used to define an optgroup. An
|
440
|
+
// optgroup object configuration looks like the following:
|
441
|
+
//
|
442
|
+
// {
|
443
|
+
// 'opt_labels': ['Looney Tunes', 'Three Stooges'],
|
444
|
+
// 'Looney Tunes': [{id: 1, name: 'Bugs Bunny'}, {id: 2, name: 'Donald Duck'}],
|
445
|
+
// 'Three Stooges': [{id: 3, name : 'moe'}, {id: 4, name : 'larry'}, {id: 5, name : 'curly'}]
|
446
|
+
// }
|
447
|
+
//
|
448
|
+
_.each(optList.opt_labels, function(label) {
|
449
|
+
var $group = $('<optgroup/>').attr('label', label);
|
450
|
+
addSelectOptions(optList[label], $group, val);
|
451
|
+
$el.append($group);
|
452
|
+
});
|
453
|
+
}
|
454
|
+
},
|
455
|
+
getVal: function($el) {
|
456
|
+
var val;
|
457
|
+
if ($el.prop('multiple')) {
|
458
|
+
val = $(getSelectedOption($el).map(function() {
|
459
|
+
return $(this).data('stickit_bind_val');
|
460
|
+
})).get();
|
461
|
+
} else {
|
462
|
+
val = getSelectedOption($el).data('stickit_bind_val');
|
463
|
+
}
|
464
|
+
return val;
|
465
|
+
}
|
466
|
+
}]);
|
467
|
+
|
468
|
+
})(window.jQuery || window.Zepto);
|
metadata
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: backbone-stickit-rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.6.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sean Griffin
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-10-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: railties
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.1'
|
48
|
+
- - <=
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '4.0'
|
51
|
+
type: :runtime
|
52
|
+
prerelease: false
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - '>='
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '3.1'
|
58
|
+
- - <=
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '4.0'
|
61
|
+
description: A wrapper around backbone.stickit for use with the rails asset pipeline
|
62
|
+
email:
|
63
|
+
- sean@thoughtbot.com
|
64
|
+
executables: []
|
65
|
+
extensions: []
|
66
|
+
extra_rdoc_files: []
|
67
|
+
files:
|
68
|
+
- lib/backbone/stickit/rails/version.rb
|
69
|
+
- lib/backbone/stickit/rails.rb
|
70
|
+
- vendor/assets/javascripts/backbone.stickit.js
|
71
|
+
- LICENSE.txt
|
72
|
+
- README.md
|
73
|
+
homepage: ''
|
74
|
+
licenses:
|
75
|
+
- MIT
|
76
|
+
metadata: {}
|
77
|
+
post_install_message:
|
78
|
+
rdoc_options: []
|
79
|
+
require_paths:
|
80
|
+
- lib
|
81
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
requirements: []
|
92
|
+
rubyforge_project:
|
93
|
+
rubygems_version: 2.0.2
|
94
|
+
signing_key:
|
95
|
+
specification_version: 4
|
96
|
+
summary: A wrapper around backbone.stickit for use with the rails asset pipeline
|
97
|
+
test_files: []
|