define(["backbone", "underscore"], function(Backbone, _) { var LicenseModel = Backbone.Model.extend({ defaults: { "type": null, "options": {}, "custom": false // either `false`, or a string }, initialize: function(attributes) { if(attributes && attributes.asString) { this.setFromString(attributes.asString); this.unset("asString"); } }, toString: function() { var custom = this.get("custom"); if (custom) { return custom; } var type = this.get("type"), options = this.get("options"); if (_.isEmpty(options)) { return type || ""; } // options are where it gets tricky var optionStrings = _.map(options, function (value, key) { if(_.isBoolean(value)) { return value ? key : null } else { return key + "=" + value } }); // filter out nulls optionStrings = _.filter(optionStrings, _.identity); // build license string and return return type + ": " + optionStrings.join(" "); }, setFromString: function(string, options) { if (!string) { // reset to defaults return this.set(this.defaults, options); } var colonIndex = string.indexOf(":"), spaceIndex = string.indexOf(" "); // a string without a colon could be a custom license, or a license // type without options if (colonIndex == -1) { if (spaceIndex == -1) { // if there's no space, it's a license type without options return this.set({ "type": string, "options": {}, "custom": false }, options); } else { // if there is a space, it's a custom license return this.set({ "type": null, "options": {}, "custom": string }, options); } } // there is a colon, which indicates a license type with options. var type = string.substring(0, colonIndex), optionsObj = {}, optionsString = string.substring(colonIndex + 1); _.each(optionsString.split(" "), function(optionString) { if (_.isEmpty(optionString)) { return; } var eqIndex = optionString.indexOf("="); if(eqIndex == -1) { // this is a boolean flag optionsObj[optionString] = true; } else { // this is a key-value pair var optionKey = optionString.substring(0, eqIndex); var optionVal = optionString.substring(eqIndex + 1); optionsObj[optionKey] = optionVal; } }); return this.set({ "type": type, "options": optionsObj, "custom": false, }, options); } }); return LicenseModel; });