UNPKG

6.35 kBJavaScriptView Raw
1(function (root, factory, undef) {
2 'use strict';
3
4 if (typeof exports === 'object') {
5 // Node. Does not work with strict CommonJS, but
6 // only CommonJS-like enviroments that support module.exports,
7 // like Node.
8 module.exports = factory(require('underscore'), require('Backbone'));
9 } else if (typeof define === 'function' && define.amd) {
10 // AMD. Register as an anonymous module.
11 define(['underscore', 'backbone'], function (_, Backbone) {
12 // Check if we use the AMD branch of Back
13 _ = _ === undef ? root._ : _;
14 Backbone = Backbone === undef ? root.Backbone : Backbone;
15 return (root.returnExportsGlobal = factory(_, Backbone, root));
16 });
17 } else {
18 // Browser globals
19 root.returnExportsGlobal = factory(root._, root.Backbone);
20 }
21
22// Usage:
23//
24// Note: This plugin is UMD compatible, you can use it in node, amd and vanilla js envs
25//
26// Vanilla JS:
27// <script src="underscore.js"></script>
28// <script src="backbone.js"></script>
29// <script src="backbone.mutators.js"></script>
30//
31// Node:
32// var _ = require('underscore');
33// var Backbone = require('backbone');
34// var Mutators = require('backbone.mutators');
35//
36//
37// AMD:
38// define(['underscore', 'backbone', 'backbone.mutators'], function (_, Backbone, Mutators) {
39// // insert sample from below
40// return User;
41// });
42//
43// var User = Backbone.Model.extend({
44// mutators: {
45// fullname: function () {
46// return this.firstname + ' ' + this.lastname;
47// }
48// },
49//
50// defaults: {
51// firstname: 'Sebastian',
52// lastname: 'Golasch'
53// }
54// });
55//
56// var user = new User();
57// user.get('fullname') // returns 'Sebastian Golasch'
58// user.toJSON() // return '{firstname: 'Sebastian', lastname: 'Golasch', fullname: 'Sebastian Golasch'}'
59
60}(this, function (_, Backbone, root, undef) {
61 'use strict';
62
63 // check if we use the amd branch of backbone and underscore
64 Backbone = Backbone === undef ? root.Backbone : Backbone;
65 _ = _ === undef ? root._ : _;
66
67 // extend backbones model prototype with the mutator functionality
68 var Mutator = function () {},
69 oldGet = Backbone.Model.prototype.get,
70 oldSet = Backbone.Model.prototype.set,
71 oldToJson = Backbone.Model.prototype.toJSON;
72
73 // This is necessary to ensure that Models declared without the mutators object do not throw and error
74 Mutator.prototype.mutators = {};
75
76 // override get functionality to fetch the mutator props
77 Mutator.prototype.get = function (attr) {
78 var isMutator = this.mutators !== undef;
79
80 // check if we have a getter mutation
81 if (isMutator === true && _.isFunction(this.mutators[attr]) === true) {
82 return this.mutators[attr].call(this);
83 }
84
85 // check if we have a deeper nested getter mutation
86 if (isMutator === true && _.isObject(this.mutators[attr]) === true && _.isFunction(this.mutators[attr].get) === true) {
87 return this.mutators[attr].get.call(this);
88 }
89
90 return oldGet.call(this, attr);
91 };
92
93 // override set functionality to set the mutator props
94 Mutator.prototype.set = function (key, value, options) {
95 var isMutator = this.mutators !== undef,
96 ret = null,
97 attrs = null;
98
99 ret = oldSet.call(this, key, value, options);
100
101 // seamleassly stolen from backbone core
102 // check if the setter action is triggered
103 // using key <-> value or object
104 if (_.isObject(key) || key === null) {
105 attrs = key;
106 options = value;
107 } else {
108 attrs = {};
109 attrs[key] = value;
110 }
111
112 // check if we have a deeper nested setter mutation
113 if (isMutator === true && _.isObject(this.mutators[key]) === true) {
114
115 // check if we need to set a single value
116 if (_.isFunction(this.mutators[key].set) === true) {
117 ret = this.mutators[key].set.call(this, key, attrs[key], options, _.bind(oldSet, this));
118 } else if(_.isFunction(this.mutators[key])){
119 ret = this.mutators[key].call(this, key, attrs[key], options, _.bind(oldSet, this));
120 }
121 }
122
123 if (isMutator === true && _.isObject(attrs)) {
124 _.each(attrs, _.bind(function (attr, attrKey) {
125 if (_.isObject(this.mutators[attrKey]) === true) {
126 // check if we need to set a single value
127
128 var meth = this.mutators[attrKey];
129 if(_.isFunction(meth.set)){
130 meth = meth.set;
131 }
132
133 if(_.isFunction(meth)){
134 if (options === undef || (_.isObject(options) === true && options.silent !== true && (options.mutators !== undef && options.mutators.silent !== true))) {
135 this.trigger('mutators:set:' + attrKey);
136 }
137 meth.call(this, attrKey, attr, options, _.bind(oldSet, this));
138 }
139
140 }
141 }, this));
142 }
143
144 return ret;
145 };
146
147 // override toJSON functionality to serialize mutator properties
148 Mutator.prototype.toJSON = function () {
149 // fetch ye olde values
150 var attr = oldToJson.call(this);
151 // iterate over all mutators (if there are some)
152 _.each(this.mutators, _.bind(function (mutator, name) {
153 // check if we have some getter mutations
154 if (_.isObject(this.mutators[name]) === true && _.isFunction(this.mutators[name].get)) {
155 attr[name] = _.bind(this.mutators[name].get, this)();
156 } else {
157 attr[name] = _.bind(this.mutators[name], this)();
158 }
159 }, this));
160
161 return attr;
162 };
163
164 // override get functionality to get HTML-escaped the mutator props
165 Mutator.prototype.escape = function (attr){
166 var val = this.get(attr);
167 return _.escape(val == null ? '' : '' + val);
168 };
169
170 // extend the models prototype
171 _.extend(Backbone.Model.prototype, Mutator.prototype);
172
173 // make mutators globally available under the Backbone namespace
174 Backbone.Mutators = Mutator;
175 return Mutator;
176}));