(function (root, define, require, exports, module, factory, undef) { 'use strict'; if (typeof exports === 'object') { // Node. Does not work with strict CommonJS, but // only CommonJS-like enviroments that support module.exports, // like Node. module.exports = factory(require('underscore'), require('backbone')); } else if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define(['underscore', 'backbone'], function (_, Backbone) { // Check if we use the AMD branch of Back _ = _ === undef ? root._ : _; Backbone = Backbone === undef ? root.Backbone : Backbone; return (root.returnExportsGlobal = factory(_, Backbone, root)); }); } else { // Browser globals root.returnExportsGlobal = factory(root._, root.Backbone); } // Usage: // // Note: This plugin is UMD compatible, you can use it in node, amd and vanilla js envs // // Vanilla JS: // // // // // Node: // var _ = require('underscore'); // var Backbone = require('backbone'); // var Mutators = require('backbone.mutators'); // // // AMD: // define(['underscore', 'backbone', 'backbone.mutators'], function (_, Backbone, Mutators) { // // insert sample from below // return User; // }); // // var User = Backbone.Model.extend({ // mutators: { // fullname: function () { // return this.firstname + ' ' + this.lastname; // } // }, // // defaults: { // firstname: 'Sebastian', // lastname: 'Golasch' // } // }); // // var user = new User(); // user.get('fullname') // returns 'Sebastian Golasch' // user.toJSON() // return '{firstname: 'Sebastian', lastname: 'Golasch', fullname: 'Sebastian Golasch'}' }(this, this.define, this.require, this.exports, this.module, function (_, Backbone, root, undef) { 'use strict'; // check if we use the amd branch of backbone and underscore Backbone = Backbone === undef ? root.Backbone : Backbone; _ = _ === undef ? root._ : _; // extend backbones model prototype with the mutator functionality var Mutator = function () { }, oldGet = Backbone.Model.prototype.get, oldSet = Backbone.Model.prototype.set, oldToJson = Backbone.Model.prototype.toJSON; // This is necessary to ensure that Models declared without the mutators object do not throw and error Mutator.prototype.mutators = {}; // override get functionality to fetch the mutator props Mutator.prototype.get = function (attr) { var isMutator = this.mutators !== undef; // check if we have a getter mutation if (isMutator === true && _.isFunction(this.mutators[attr]) === true) { return this.mutators[attr].call(this); } // check if we have a deeper nested getter mutation if (isMutator === true && _.isObject(this.mutators[attr]) === true && _.isFunction(this.mutators[attr].get) === true) { return this.mutators[attr].get.call(this); } return oldGet.call(this, attr); }; // override set functionality to set the mutator props Mutator.prototype.set = function (key, value, options) { var isMutator = this.mutators !== undef, ret = null, attrs = null, attr = null; // seamleassly stolen from backbone core // check if the setter action is triggered // using key <-> value or object if (_.isObject(key) || key === null) { attrs = key; options = value; } else { attrs = {}; attrs[key] = value; } // check if we have a deeper nested setter mutation if (isMutator === true && _.isObject(this.mutators[key]) === true) { // check if we need to set a single value if (_.isFunction(this.mutators[key].set) === true) { ret = this.mutators[key].set.call(this, key, attrs[key], options, _.bind(oldSet, this)); } else if (_.isFunction(this.mutators[key])) { ret = this.mutators[key].call(this, key, attrs[key], options, _.bind(oldSet, this)); } } if (_.isObject(attrs)) { _.each(attrs, _.bind(function (attr, attrKey) { if (isMutator === true && _.isObject(this.mutators[attrKey]) === true) { // check if we need to set a single value var meth = this.mutators[attrKey]; if (_.isFunction(meth.set)) { meth = meth.set; } if (_.isFunction(meth)) { if (options === undef || (_.isObject(options) === true && options.silent !== true && (options.mutators !== undef && options.mutators.silent !== true))) { this.trigger('mutators:set:' + attrKey); } ret = meth.call(this, attrKey, attr, options, _.bind(oldSet, this)); } } }, this)); } //validation purposes if (ret !== null) { return ret; } return oldSet.call(this, key, value, options); }; // override toJSON functionality to serialize mutator properties Mutator.prototype.toJSON = function () { // fetch ye olde values var attr = oldToJson.call(this); // iterate over all mutators (if there are some) _.each(this.mutators, _.bind(function (mutator, name) { // check if we have some getter mutations (nested or ) if (_.isObject(this.mutators[name]) === true && _.isFunction(this.mutators[name].get)) { attr[name] = _.bind(this.mutators[name].get, this)(); } else { attr[name] = _.bind(this.mutators[name], this)(); } }, this)); return attr; }; // extend the models prototype _.extend(Backbone.Model.prototype, Mutator.prototype); // make mutators globally available under the Backbone namespace Backbone.Mutators = Mutator; return Mutator; }));