From: Scott Baker Date: Tue, 28 Oct 2014 19:03:28 +0000 (-0700) Subject: check in missing js file X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=69ccb0024e0bb0d6f26d493d1cbc22c605bab508;p=plstackapi.git check in missing js file --- diff --git a/planetstack/core/xoslib/static/js/vendor/backbone.syphon.js b/planetstack/core/xoslib/static/js/vendor/backbone.syphon.js new file mode 100644 index 0000000..3cd1537 --- /dev/null +++ b/planetstack/core/xoslib/static/js/vendor/backbone.syphon.js @@ -0,0 +1,469 @@ +// Backbone.Syphon, v0.4.1 +// Copyright (c)2012 Derick Bailey, Muted Solutions, LLC. +// Distributed under MIT license +// http://github.com/derickbailey/backbone.syphon +Backbone.Syphon = (function(Backbone, $, _){ + var Syphon = {}; + + // Ignore Element Types + // -------------------- + + // Tell Syphon to ignore all elements of these types. You can + // push new types to ignore directly in to this array. + Syphon.ignoredTypes = ["button", "submit", "reset", "fieldset"]; + + // Syphon + // ------ + + // Get a JSON object that represents + // all of the form inputs, in this view. + // Alternately, pass a form element directly + // in place of the view. + Syphon.serialize = function(view, options){ + var data = {}; + + // Build the configuration + var config = buildConfig(options); + + // Get all of the elements to process + var elements = getInputElements(view, config); + + // Process all of the elements + _.each(elements, function(el){ + var $el = $(el); + var type = getElementType($el); + + // Get the key for the input + var keyExtractor = config.keyExtractors.get(type); + var key = keyExtractor($el); + + // Get the value for the input + var inputReader = config.inputReaders.get(type); + var value = inputReader($el); + + // Get the key assignment validator and make sure + // it's valid before assigning the value to the key + var validKeyAssignment = config.keyAssignmentValidators.get(type); + if (validKeyAssignment($el, key, value)){ + var keychain = config.keySplitter(key); + data = assignKeyValue(data, keychain, value); + } + }); + + // Done; send back the results. + return data; + }; + + // Use the given JSON object to populate + // all of the form inputs, in this view. + // Alternately, pass a form element directly + // in place of the view. + Syphon.deserialize = function(view, data, options){ + // Build the configuration + var config = buildConfig(options); + + // Get all of the elements to process + var elements = getInputElements(view, config); + + // Flatten the data structure that we are deserializing + var flattenedData = flattenData(config, data); + + // Process all of the elements + _.each(elements, function(el){ + var $el = $(el); + var type = getElementType($el); + + // Get the key for the input + var keyExtractor = config.keyExtractors.get(type); + var key = keyExtractor($el); + + // Get the input writer and the value to write + var inputWriter = config.inputWriters.get(type); + var value = flattenedData[key]; + + // Write the value to the input + inputWriter($el, value); + }); + }; + + // Helpers + // ------- + + // Retrieve all of the form inputs + // from the form + var getInputElements = function(view, config){ + var form = getForm(view); + var elements = form.elements; + + elements = _.reject(elements, function(el){ + var reject; + var type = getElementType(el); + var extractor = config.keyExtractors.get(type); + var identifier = extractor($(el)); + + var foundInIgnored = _.include(config.ignoredTypes, type); + var foundInInclude = _.include(config.include, identifier); + var foundInExclude = _.include(config.exclude, identifier); + + if (foundInInclude){ + reject = false; + } else { + if (config.include){ + reject = true; + } else { + reject = (foundInExclude || foundInIgnored); + } + } + + return reject; + }); + + return elements; + }; + + // Determine what type of element this is. It + // will either return the `type` attribute of + // an `` element, or the `tagName` of + // the element when the element is not an ``. + var getElementType = function(el){ + var typeAttr; + var $el = $(el); + var tagName = $el[0].tagName; + var type = tagName; + + if (tagName.toLowerCase() === "input"){ + typeAttr = $el.attr("type"); + if (typeAttr){ + type = typeAttr; + } else { + type = "text"; + } + } + + // Always return the type as lowercase + // so it can be matched to lowercase + // type registrations. + return type.toLowerCase(); + }; + + // If a form element is given, just return it. + // Otherwise, get the form element from the view. + var getForm = function(viewOrForm){ + if (_.isUndefined(viewOrForm.$el) && viewOrForm.tagName.toLowerCase() === 'form'){ + return viewOrForm; + } else { + return viewOrForm.$el.is("form") ? viewOrForm.el : viewOrForm.$("form")[0]; + } + }; + + // Build a configuration object and initialize + // default values. + var buildConfig = function(options){ + var config = _.clone(options) || {}; + + config.ignoredTypes = _.clone(Syphon.ignoredTypes); + config.inputReaders = config.inputReaders || Syphon.InputReaders; + config.inputWriters = config.inputWriters || Syphon.InputWriters; + config.keyExtractors = config.keyExtractors || Syphon.KeyExtractors; + config.keySplitter = config.keySplitter || Syphon.KeySplitter; + config.keyJoiner = config.keyJoiner || Syphon.KeyJoiner; + config.keyAssignmentValidators = config.keyAssignmentValidators || Syphon.KeyAssignmentValidators; + + return config; + }; + + // Assigns `value` to a parsed JSON key. + // + // The first parameter is the object which will be + // modified to store the key/value pair. + // + // The second parameter accepts an array of keys as a + // string with an option array containing a + // single string as the last option. + // + // The third parameter is the value to be assigned. + // + // Examples: + // + // `["foo", "bar", "baz"] => {foo: {bar: {baz: "value"}}}` + // + // `["foo", "bar", ["baz"]] => {foo: {bar: {baz: ["value"]}}}` + // + // When the final value is an array with a string, the key + // becomes an array, and values are pushed in to the array, + // allowing multiple fields with the same name to be + // assigned to the array. + var assignKeyValue = function(obj, keychain, value) { + if (!keychain){ return obj; } + + var key = keychain.shift(); + + // build the current object we need to store data + if (!obj[key]){ + obj[key] = _.isArray(key) ? [] : {}; + } + + // if it's the last key in the chain, assign the value directly + if (keychain.length === 0){ + if (_.isArray(obj[key])){ + obj[key].push(value); + } else { + obj[key] = value; + } + } + + // recursive parsing of the array, depth-first + if (keychain.length > 0){ + assignKeyValue(obj[key], keychain, value); + } + + return obj; + }; + + // Flatten the data structure in to nested strings, using the + // provided `KeyJoiner` function. + // + // Example: + // + // This input: + // + // ```js + // { + // widget: "wombat", + // foo: { + // bar: "baz", + // baz: { + // quux: "qux" + // }, + // quux: ["foo", "bar"] + // } + // } + // ``` + // + // With a KeyJoiner that uses [ ] square brackets, + // should produce this output: + // + // ```js + // { + // "widget": "wombat", + // "foo[bar]": "baz", + // "foo[baz][quux]": "qux", + // "foo[quux]": ["foo", "bar"] + // } + // ``` + var flattenData = function(config, data, parentKey){ + var flatData = {}; + + _.each(data, function(value, keyName){ + var hash = {}; + + // If there is a parent key, join it with + // the current, child key. + if (parentKey){ + keyName = config.keyJoiner(parentKey, keyName); + } + + if (_.isArray(value)){ + keyName += "[]"; + hash[keyName] = value; + } else if (_.isObject(value)){ + hash = flattenData(config, value, keyName); + } else { + hash[keyName] = value; + } + + // Store the resulting key/value pairs in the + // final flattened data object + _.extend(flatData, hash); + }); + + return flatData; + }; + + return Syphon; +})(Backbone, jQuery, _); + +// Type Registry +// ------------- + +// Type Registries allow you to register something to +// an input type, and retrieve either the item registered +// for a specific type or the default registration +Backbone.Syphon.TypeRegistry = function(){ + this.registeredTypes = {}; +}; + +// Borrow Backbone's `extend` keyword for our TypeRegistry +Backbone.Syphon.TypeRegistry.extend = Backbone.Model.extend; + +_.extend(Backbone.Syphon.TypeRegistry.prototype, { + + // Get the registered item by type. If nothing is + // found for the specified type, the default is + // returned. + get: function(type){ + var item = this.registeredTypes[type]; + + if (!item){ + item = this.registeredTypes["default"]; + } + + return item; + }, + + // Register a new item for a specified type + register: function(type, item){ + this.registeredTypes[type] = item; + }, + + // Register a default item to be used when no + // item for a specified type is found + registerDefault: function(item){ + this.registeredTypes["default"] = item; + }, + + // Remove an item from a given type registration + unregister: function(type){ + if (this.registeredTypes[type]){ + delete this.registeredTypes[type]; + } + } +}); + + + + +// Key Extractors +// -------------- + +// Key extractors produce the "key" in `{key: "value"}` +// pairs, when serializing. +Backbone.Syphon.KeyExtractorSet = Backbone.Syphon.TypeRegistry.extend(); + +// Built-in Key Extractors +Backbone.Syphon.KeyExtractors = new Backbone.Syphon.KeyExtractorSet(); + +// The default key extractor, which uses the +// input element's "id" attribute +Backbone.Syphon.KeyExtractors.registerDefault(function($el){ + return $el.prop("name"); +}); + + +// Input Readers +// ------------- + +// Input Readers are used to extract the value from +// an input element, for the serialized object result +Backbone.Syphon.InputReaderSet = Backbone.Syphon.TypeRegistry.extend(); + +// Built-in Input Readers +Backbone.Syphon.InputReaders = new Backbone.Syphon.InputReaderSet(); + +// The default input reader, which uses an input +// element's "value" +Backbone.Syphon.InputReaders.registerDefault(function($el){ + return $el.val(); +}); + +// Checkbox reader, returning a boolean value for +// whether or not the checkbox is checked. +Backbone.Syphon.InputReaders.register("checkbox", function($el){ + var checked = $el.prop("checked"); + return checked; +}); + + +// Input Writers +// ------------- + +// Input Writers are used to insert a value from an +// object into an input element. +Backbone.Syphon.InputWriterSet = Backbone.Syphon.TypeRegistry.extend(); + +// Built-in Input Writers +Backbone.Syphon.InputWriters = new Backbone.Syphon.InputWriterSet(); + +// The default input writer, which sets an input +// element's "value" +Backbone.Syphon.InputWriters.registerDefault(function($el, value){ + $el.val(value); +}); + +// Checkbox writer, set whether or not the checkbox is checked +// depending on the boolean value. +Backbone.Syphon.InputWriters.register("checkbox", function($el, value){ + $el.prop("checked", value); +}); + +// Radio button writer, set whether or not the radio button is +// checked. The button should only be checked if it's value +// equals the given value. +Backbone.Syphon.InputWriters.register("radio", function($el, value){ + $el.prop("checked", $el.val() === value); +}); + +// Key Assignment Validators +// ------------------------- + +// Key Assignment Validators are used to determine whether or not a +// key should be assigned to a value, after the key and value have been +// extracted from the element. This is the last opportunity to prevent +// bad data from getting serialized to your object. + +Backbone.Syphon.KeyAssignmentValidatorSet = Backbone.Syphon.TypeRegistry.extend(); + +// Build-in Key Assignment Validators +Backbone.Syphon.KeyAssignmentValidators = new Backbone.Syphon.KeyAssignmentValidatorSet(); + +// Everything is valid by default +Backbone.Syphon.KeyAssignmentValidators.registerDefault(function(){ return true; }); + +// But only the "checked" radio button for a given +// radio button group is valid +Backbone.Syphon.KeyAssignmentValidators.register("radio", function($el, key, value){ + return $el.prop("checked"); +}); + + +// Backbone.Syphon.KeySplitter +// --------------------------- + +// This function is used to split DOM element keys in to an array +// of parts, which are then used to create a nested result structure. +// returning `["foo", "bar"]` results in `{foo: { bar: "value" }}`. +// +// Override this method to use a custom key splitter, such as: +// ``, `return key.split(".")` +Backbone.Syphon.KeySplitter = function(key){ + var matches = key.match(/[^\[\]]+/g); + + if (key.indexOf("[]") === key.length - 2){ + lastKey = matches.pop(); + matches.push([lastKey]); + } + + return matches; +} + + +// Backbone.Syphon.KeyJoiner +// ------------------------- + +// Take two segments of a key and join them together, to create the +// de-normalized key name, when deserializing a data structure back +// in to a form. +// +// Example: +// +// With this data strucutre `{foo: { bar: {baz: "value", quux: "another"} } }`, +// the key joiner will be called with these parameters, and assuming the +// join happens with "[ ]" square brackets, the specified output: +// +// `KeyJoiner("foo", "bar")` //=> "foo[bar]" +// `KeyJoiner("foo[bar]", "baz")` //=> "foo[bar][baz]" +// `KeyJoiner("foo[bar]", "quux")` //=> "foo[bar][quux]" + +Backbone.Syphon.KeyJoiner = function(parentKey, childKey){ + return parentKey + "[" + childKey + "]"; +}