backbone-syphon-rails 0.4.1.1

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