backbone-syphon-rails 0.4.1.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.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in backbone-syphon-rails.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Kirillov Alexander
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,34 @@
1
+ # Backbone::Syphon::Rails for Rails
2
+
3
+ It is a wrapper for [Backbone.Syphon](https://github.com/derickbailey/backbone.syphon) plugin for [Backbone](https://github.com/documentcloud/backbone/)
4
+ ## Verstion
5
+ The version of this gem follows that of the associated Backbone.Syphon version
6
+
7
+ Current version is **0.4.1**
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ gem 'backbone-syphon-rails'
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install backbone-syphon-rails
21
+
22
+ ## Usage
23
+
24
+ Add this line to your application.js file:
25
+
26
+ //= require backbone-syphone
27
+
28
+ ## Contributing
29
+
30
+ 1. Fork it
31
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
32
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
33
+ 4. Push to the branch (`git push origin my-new-feature`)
34
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'backbone-syphon-rails/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "backbone-syphon-rails"
8
+ gem.version = Backbone::Syphon::Rails::VERSION
9
+ gem.authors = ["Kirillov Alexander"]
10
+ gem.email = ["saratovsource@gmail.com"]
11
+ gem.description = %q{A wrapper for Backbone.Syphon in the Rails asset pipeline}
12
+ gem.summary = %q{Backbone.Syphon for Rails >= 3.1}
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+ end
@@ -0,0 +1,9 @@
1
+ require "backbone-syphon-rails/version"
2
+
3
+ module Backbone
4
+ module Syphon
5
+ module Rails
6
+ # Your code goes here...
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ module Backbone
2
+ module Syphon
3
+ module Rails
4
+ VERSION = "0.4.1.1"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,469 @@
1
+ // Backbone.Syphon, v0.4.1
2
+ // Copyright (c)2012 Derick Bailey, Muted Solutions, LLC.
3
+ // Distributed under MIT license
4
+ // http://github.com/derickbailey/backbone.syphon
5
+ Backbone.Syphon = (function(Backbone, $, _){
6
+ var Syphon = {};
7
+
8
+ // Ignore Element Types
9
+ // --------------------
10
+
11
+ // Tell Syphon to ignore all elements of these types. You can
12
+ // push new types to ignore directly in to this array.
13
+ Syphon.ignoredTypes = ["button", "submit", "reset", "fieldset"];
14
+
15
+ // Syphon
16
+ // ------
17
+
18
+ // Get a JSON object that represents
19
+ // all of the form inputs, in this view.
20
+ // Alternately, pass a form element directly
21
+ // in place of the view.
22
+ Syphon.serialize = function(view, options){
23
+ var data = {};
24
+
25
+ // Build the configuration
26
+ var config = buildConfig(options);
27
+
28
+ // Get all of the elements to process
29
+ var elements = getInputElements(view, config);
30
+
31
+ // Process all of the elements
32
+ _.each(elements, function(el){
33
+ var $el = $(el);
34
+ var type = getElementType($el);
35
+
36
+ // Get the key for the input
37
+ var keyExtractor = config.keyExtractors.get(type);
38
+ var key = keyExtractor($el);
39
+
40
+ // Get the value for the input
41
+ var inputReader = config.inputReaders.get(type);
42
+ var value = inputReader($el);
43
+
44
+ // Get the key assignment validator and make sure
45
+ // it's valid before assigning the value to the key
46
+ var validKeyAssignment = config.keyAssignmentValidators.get(type);
47
+ if (validKeyAssignment($el, key, value)){
48
+ var keychain = config.keySplitter(key);
49
+ data = assignKeyValue(data, keychain, value);
50
+ }
51
+ });
52
+
53
+ // Done; send back the results.
54
+ return data;
55
+ };
56
+
57
+ // Use the given JSON object to populate
58
+ // all of the form inputs, in this view.
59
+ // Alternately, pass a form element directly
60
+ // in place of the view.
61
+ Syphon.deserialize = function(view, data, options){
62
+ // Build the configuration
63
+ var config = buildConfig(options);
64
+
65
+ // Get all of the elements to process
66
+ var elements = getInputElements(view, config);
67
+
68
+ // Flatten the data structure that we are deserializing
69
+ var flattenedData = flattenData(config, data);
70
+
71
+ // Process all of the elements
72
+ _.each(elements, function(el){
73
+ var $el = $(el);
74
+ var type = getElementType($el);
75
+
76
+ // Get the key for the input
77
+ var keyExtractor = config.keyExtractors.get(type);
78
+ var key = keyExtractor($el);
79
+
80
+ // Get the input writer and the value to write
81
+ var inputWriter = config.inputWriters.get(type);
82
+ var value = flattenedData[key];
83
+
84
+ // Write the value to the input
85
+ inputWriter($el, value);
86
+ });
87
+ };
88
+
89
+ // Helpers
90
+ // -------
91
+
92
+ // Retrieve all of the form inputs
93
+ // from the form
94
+ var getInputElements = function(view, config){
95
+ var form = getForm(view);
96
+ var elements = form.elements;
97
+
98
+ elements = _.reject(elements, function(el){
99
+ var reject;
100
+ var type = getElementType(el);
101
+ var extractor = config.keyExtractors.get(type);
102
+ var identifier = extractor($(el));
103
+
104
+ var foundInIgnored = _.include(config.ignoredTypes, type);
105
+ var foundInInclude = _.include(config.include, identifier);
106
+ var foundInExclude = _.include(config.exclude, identifier);
107
+
108
+ if (foundInInclude){
109
+ reject = false;
110
+ } else {
111
+ if (config.include){
112
+ reject = true;
113
+ } else {
114
+ reject = (foundInExclude || foundInIgnored);
115
+ }
116
+ }
117
+
118
+ return reject;
119
+ });
120
+
121
+ return elements;
122
+ };
123
+
124
+ // Determine what type of element this is. It
125
+ // will either return the `type` attribute of
126
+ // an `<input>` element, or the `tagName` of
127
+ // the element when the element is not an `<input>`.
128
+ var getElementType = function(el){
129
+ var typeAttr;
130
+ var $el = $(el);
131
+ var tagName = $el[0].tagName;
132
+ var type = tagName;
133
+
134
+ if (tagName.toLowerCase() === "input"){
135
+ typeAttr = $el.attr("type");
136
+ if (typeAttr){
137
+ type = typeAttr;
138
+ } else {
139
+ type = "text";
140
+ }
141
+ }
142
+
143
+ // Always return the type as lowercase
144
+ // so it can be matched to lowercase
145
+ // type registrations.
146
+ return type.toLowerCase();
147
+ };
148
+
149
+ // If a form element is given, just return it.
150
+ // Otherwise, get the form element from the view.
151
+ var getForm = function(viewOrForm){
152
+ if (_.isUndefined(viewOrForm.$el) && viewOrForm.tagName.toLowerCase() === 'form'){
153
+ return viewOrForm;
154
+ } else {
155
+ return viewOrForm.$el.is("form") ? viewOrForm.el : viewOrForm.$("form")[0];
156
+ }
157
+ };
158
+
159
+ // Build a configuration object and initialize
160
+ // default values.
161
+ var buildConfig = function(options){
162
+ var config = _.clone(options) || {};
163
+
164
+ config.ignoredTypes = _.clone(Syphon.ignoredTypes);
165
+ config.inputReaders = config.inputReaders || Syphon.InputReaders;
166
+ config.inputWriters = config.inputWriters || Syphon.InputWriters;
167
+ config.keyExtractors = config.keyExtractors || Syphon.KeyExtractors;
168
+ config.keySplitter = config.keySplitter || Syphon.KeySplitter;
169
+ config.keyJoiner = config.keyJoiner || Syphon.KeyJoiner;
170
+ config.keyAssignmentValidators = config.keyAssignmentValidators || Syphon.KeyAssignmentValidators;
171
+
172
+ return config;
173
+ };
174
+
175
+ // Assigns `value` to a parsed JSON key.
176
+ //
177
+ // The first parameter is the object which will be
178
+ // modified to store the key/value pair.
179
+ //
180
+ // The second parameter accepts an array of keys as a
181
+ // string with an option array containing a
182
+ // single string as the last option.
183
+ //
184
+ // The third parameter is the value to be assigned.
185
+ //
186
+ // Examples:
187
+ //
188
+ // `["foo", "bar", "baz"] => {foo: {bar: {baz: "value"}}}`
189
+ //
190
+ // `["foo", "bar", ["baz"]] => {foo: {bar: {baz: ["value"]}}}`
191
+ //
192
+ // When the final value is an array with a string, the key
193
+ // becomes an array, and values are pushed in to the array,
194
+ // allowing multiple fields with the same name to be
195
+ // assigned to the array.
196
+ var assignKeyValue = function(obj, keychain, value) {
197
+ if (!keychain){ return obj; }
198
+
199
+ var key = keychain.shift();
200
+
201
+ // build the current object we need to store data
202
+ if (!obj[key]){
203
+ obj[key] = _.isArray(key) ? [] : {};
204
+ }
205
+
206
+ // if it's the last key in the chain, assign the value directly
207
+ if (keychain.length === 0){
208
+ if (_.isArray(obj[key])){
209
+ obj[key].push(value);
210
+ } else {
211
+ obj[key] = value;
212
+ }
213
+ }
214
+
215
+ // recursive parsing of the array, depth-first
216
+ if (keychain.length > 0){
217
+ assignKeyValue(obj[key], keychain, value);
218
+ }
219
+
220
+ return obj;
221
+ };
222
+
223
+ // Flatten the data structure in to nested strings, using the
224
+ // provided `KeyJoiner` function.
225
+ //
226
+ // Example:
227
+ //
228
+ // This input:
229
+ //
230
+ // ```js
231
+ // {
232
+ // widget: "wombat",
233
+ // foo: {
234
+ // bar: "baz",
235
+ // baz: {
236
+ // quux: "qux"
237
+ // },
238
+ // quux: ["foo", "bar"]
239
+ // }
240
+ // }
241
+ // ```
242
+ //
243
+ // With a KeyJoiner that uses [ ] square brackets,
244
+ // should produce this output:
245
+ //
246
+ // ```js
247
+ // {
248
+ // "widget": "wombat",
249
+ // "foo[bar]": "baz",
250
+ // "foo[baz][quux]": "qux",
251
+ // "foo[quux]": ["foo", "bar"]
252
+ // }
253
+ // ```
254
+ var flattenData = function(config, data, parentKey){
255
+ var flatData = {};
256
+
257
+ _.each(data, function(value, keyName){
258
+ var hash = {};
259
+
260
+ // If there is a parent key, join it with
261
+ // the current, child key.
262
+ if (parentKey){
263
+ keyName = config.keyJoiner(parentKey, keyName);
264
+ }
265
+
266
+ if (_.isArray(value)){
267
+ keyName += "[]";
268
+ hash[keyName] = value;
269
+ } else if (_.isObject(value)){
270
+ hash = flattenData(config, value, keyName);
271
+ } else {
272
+ hash[keyName] = value;
273
+ }
274
+
275
+ // Store the resulting key/value pairs in the
276
+ // final flattened data object
277
+ _.extend(flatData, hash);
278
+ });
279
+
280
+ return flatData;
281
+ };
282
+
283
+ return Syphon;
284
+ })(Backbone, jQuery, _);
285
+
286
+ // Type Registry
287
+ // -------------
288
+
289
+ // Type Registries allow you to register something to
290
+ // an input type, and retrieve either the item registered
291
+ // for a specific type or the default registration
292
+ Backbone.Syphon.TypeRegistry = function(){
293
+ this.registeredTypes = {};
294
+ };
295
+
296
+ // Borrow Backbone's `extend` keyword for our TypeRegistry
297
+ Backbone.Syphon.TypeRegistry.extend = Backbone.Model.extend;
298
+
299
+ _.extend(Backbone.Syphon.TypeRegistry.prototype, {
300
+
301
+ // Get the registered item by type. If nothing is
302
+ // found for the specified type, the default is
303
+ // returned.
304
+ get: function(type){
305
+ var item = this.registeredTypes[type];
306
+
307
+ if (!item){
308
+ item = this.registeredTypes["default"];
309
+ }
310
+
311
+ return item;
312
+ },
313
+
314
+ // Register a new item for a specified type
315
+ register: function(type, item){
316
+ this.registeredTypes[type] = item;
317
+ },
318
+
319
+ // Register a default item to be used when no
320
+ // item for a specified type is found
321
+ registerDefault: function(item){
322
+ this.registeredTypes["default"] = item;
323
+ },
324
+
325
+ // Remove an item from a given type registration
326
+ unregister: function(type){
327
+ if (this.registeredTypes[type]){
328
+ delete this.registeredTypes[type];
329
+ }
330
+ }
331
+ });
332
+
333
+
334
+
335
+
336
+ // Key Extractors
337
+ // --------------
338
+
339
+ // Key extractors produce the "key" in `{key: "value"}`
340
+ // pairs, when serializing.
341
+ Backbone.Syphon.KeyExtractorSet = Backbone.Syphon.TypeRegistry.extend();
342
+
343
+ // Built-in Key Extractors
344
+ Backbone.Syphon.KeyExtractors = new Backbone.Syphon.KeyExtractorSet();
345
+
346
+ // The default key extractor, which uses the
347
+ // input element's "id" attribute
348
+ Backbone.Syphon.KeyExtractors.registerDefault(function($el){
349
+ return $el.prop("name");
350
+ });
351
+
352
+
353
+ // Input Readers
354
+ // -------------
355
+
356
+ // Input Readers are used to extract the value from
357
+ // an input element, for the serialized object result
358
+ Backbone.Syphon.InputReaderSet = Backbone.Syphon.TypeRegistry.extend();
359
+
360
+ // Built-in Input Readers
361
+ Backbone.Syphon.InputReaders = new Backbone.Syphon.InputReaderSet();
362
+
363
+ // The default input reader, which uses an input
364
+ // element's "value"
365
+ Backbone.Syphon.InputReaders.registerDefault(function($el){
366
+ return $el.val();
367
+ });
368
+
369
+ // Checkbox reader, returning a boolean value for
370
+ // whether or not the checkbox is checked.
371
+ Backbone.Syphon.InputReaders.register("checkbox", function($el){
372
+ var checked = $el.prop("checked");
373
+ return checked;
374
+ });
375
+
376
+
377
+ // Input Writers
378
+ // -------------
379
+
380
+ // Input Writers are used to insert a value from an
381
+ // object into an input element.
382
+ Backbone.Syphon.InputWriterSet = Backbone.Syphon.TypeRegistry.extend();
383
+
384
+ // Built-in Input Writers
385
+ Backbone.Syphon.InputWriters = new Backbone.Syphon.InputWriterSet();
386
+
387
+ // The default input writer, which sets an input
388
+ // element's "value"
389
+ Backbone.Syphon.InputWriters.registerDefault(function($el, value){
390
+ $el.val(value);
391
+ });
392
+
393
+ // Checkbox writer, set whether or not the checkbox is checked
394
+ // depending on the boolean value.
395
+ Backbone.Syphon.InputWriters.register("checkbox", function($el, value){
396
+ $el.prop("checked", value);
397
+ });
398
+
399
+ // Radio button writer, set whether or not the radio button is
400
+ // checked. The button should only be checked if it's value
401
+ // equals the given value.
402
+ Backbone.Syphon.InputWriters.register("radio", function($el, value){
403
+ $el.prop("checked", $el.val() === value);
404
+ });
405
+
406
+ // Key Assignment Validators
407
+ // -------------------------
408
+
409
+ // Key Assignment Validators are used to determine whether or not a
410
+ // key should be assigned to a value, after the key and value have been
411
+ // extracted from the element. This is the last opportunity to prevent
412
+ // bad data from getting serialized to your object.
413
+
414
+ Backbone.Syphon.KeyAssignmentValidatorSet = Backbone.Syphon.TypeRegistry.extend();
415
+
416
+ // Build-in Key Assignment Validators
417
+ Backbone.Syphon.KeyAssignmentValidators = new Backbone.Syphon.KeyAssignmentValidatorSet();
418
+
419
+ // Everything is valid by default
420
+ Backbone.Syphon.KeyAssignmentValidators.registerDefault(function(){ return true; });
421
+
422
+ // But only the "checked" radio button for a given
423
+ // radio button group is valid
424
+ Backbone.Syphon.KeyAssignmentValidators.register("radio", function($el, key, value){
425
+ return $el.prop("checked");
426
+ });
427
+
428
+
429
+ // Backbone.Syphon.KeySplitter
430
+ // ---------------------------
431
+
432
+ // This function is used to split DOM element keys in to an array
433
+ // of parts, which are then used to create a nested result structure.
434
+ // returning `["foo", "bar"]` results in `{foo: { bar: "value" }}`.
435
+ //
436
+ // Override this method to use a custom key splitter, such as:
437
+ // `<input name="foo.bar.baz">`, `return key.split(".")`
438
+ Backbone.Syphon.KeySplitter = function(key){
439
+ var matches = key.match(/[^\[\]]+/g);
440
+
441
+ if (key.indexOf("[]") === key.length - 2){
442
+ lastKey = matches.pop();
443
+ matches.push([lastKey]);
444
+ }
445
+
446
+ return matches;
447
+ }
448
+
449
+
450
+ // Backbone.Syphon.KeyJoiner
451
+ // -------------------------
452
+
453
+ // Take two segments of a key and join them together, to create the
454
+ // de-normalized key name, when deserializing a data structure back
455
+ // in to a form.
456
+ //
457
+ // Example:
458
+ //
459
+ // With this data strucutre `{foo: { bar: {baz: "value", quux: "another"} } }`,
460
+ // the key joiner will be called with these parameters, and assuming the
461
+ // join happens with "[ ]" square brackets, the specified output:
462
+ //
463
+ // `KeyJoiner("foo", "bar")` //=> "foo[bar]"
464
+ // `KeyJoiner("foo[bar]", "baz")` //=> "foo[bar][baz]"
465
+ // `KeyJoiner("foo[bar]", "quux")` //=> "foo[bar][quux]"
466
+
467
+ Backbone.Syphon.KeyJoiner = function(parentKey, childKey){
468
+ return parentKey + "[" + childKey + "]";
469
+ }
metadata ADDED
@@ -0,0 +1,54 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: backbone-syphon-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.1.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Kirillov Alexander
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-30 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: A wrapper for Backbone.Syphon in the Rails asset pipeline
15
+ email:
16
+ - saratovsource@gmail.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - .gitignore
22
+ - Gemfile
23
+ - LICENSE.txt
24
+ - README.md
25
+ - Rakefile
26
+ - backbone-syphon-rails.gemspec
27
+ - lib/backbone-syphon-rails.rb
28
+ - lib/backbone-syphon-rails/version.rb
29
+ - vendor/assets/javascripts/backbone-syphon.js
30
+ homepage: ''
31
+ licenses: []
32
+ post_install_message:
33
+ rdoc_options: []
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ! '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ requirements: []
49
+ rubyforge_project:
50
+ rubygems_version: 1.8.24
51
+ signing_key:
52
+ specification_version: 3
53
+ summary: Backbone.Syphon for Rails >= 3.1
54
+ test_files: []