4 * Class to help modify attributes.
6 * @param {object} object
7 * An object to initialize attributes with.
11 var Attributes = function (object) {
12 this.data = object && _.isObject(object) && _.clone(object) || {};
16 * Renders the attributes object as a string to inject into an HTML element.
20 Attributes.prototype.toString = function () {
23 var checkPlain = function (str) {
24 return str && str.toString().replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>') || '';
26 for (name in this.data) {
27 if (!this.data.hasOwnProperty(name)) continue;
28 value = this.data[name];
29 if (_.isFunction(value)) value = value();
30 if (_.isObject(value)) value = _.values(value);
31 if (_.isArray(value)) value = value.join(' ');
32 output += ' ' + checkPlain(name) + '="' + checkPlain(value) + '"';
38 * Add class(es) to the array.
40 * @param {string|Array} value
41 * An individual class or an array of classes to add.
43 * @return {Attributes}
47 Attributes.prototype.addClass = function (value) {
48 var classes = this.getClasses();
49 value = [].concat(classes, value);
50 this.set('class', _.uniq(value));
55 * Returns whether the requested attribute exists.
57 * @param {string} name
58 * An attribute name to check.
63 Attributes.prototype.exists = function (name) {
64 return this.data[name] !== void(0) && this.data[name] !== null;
68 * Retrieve a specific attribute from the array.
70 * @param {string} name
71 * The specific attribute to retrieve.
72 * @param {*} defaultValue
73 * (optional) The default value to set if the attribute does not exist.
76 * A specific attribute value, passed by reference.
78 Attributes.prototype.get = function (name, defaultValue) {
79 if (!this.exists(name)) this.data[name] = defaultValue;
80 return this.data[name];
84 * Retrieves a cloned copy of the internal attributes data object.
88 Attributes.prototype.getData = function () {
89 return _.clone(this.data);
93 * Retrieves classes from the array.
98 Attributes.prototype.getClasses = function () {
99 var classes = [].concat(this.get('class', []));
100 return _.uniq(classes);
104 * Indicates whether a class is present in the array.
106 * @param {string|Array} name
107 * The class(es) to search for.
112 Attributes.prototype.hasClass = function (name) {
113 name = [].concat(name);
114 var classes = this.getClasses();
116 _.each(name, function (value) { if (_.indexOf(classes, value) !== -1) found = true; });
121 * Merges multiple values into the array.
123 * @param {object} values
124 * An associative key/value array.
125 * @param {boolean} [recursive]
126 * Flag determining whether or not to recursively merge key/value pairs.
128 * @return {Attributes}
132 Attributes.prototype.merge = function (values, recursive) {
133 values = values instanceof Attributes ? values.getData() : values;
134 if (recursive === void(0) || recursive) {
135 this.data = $.extend(true, {}, this.data, values);
138 $.extend(this.data, values);
144 * Removes an attribute from the array.
146 * @param {string} name
147 * The name of the attribute to remove.
149 * @return {Attributes}
153 Attributes.prototype.remove = function (name) {
154 if (this.exists(name)) delete this.data[name];
159 * Removes a class from the attributes array.
161 * @param {string|Array} value
162 * An individual class or an array of classes to remove.
164 * @return {Attributes}
168 Attributes.prototype.removeClass = function (value) {
169 this.set('class', _.without(this.getClasses(), [].concat(value)));
174 * Replaces a class in the attributes array.
176 * @param {string} oldValue
177 * The old class to remove.
178 * @param {string} newValue
179 * The new class. It will not be added if the old class does not exist.
181 * @return {Attributes}
185 Attributes.prototype.replaceClass = function (oldValue, newValue) {
186 var classes = this.getClasses();
187 var i = _.indexOf(oldValue, classes);
189 classes[i] = newValue;
190 this.set('class', classes);
196 * Sets an attribute on the array.
198 * @param {string} name
199 * The name of the attribute to set.
201 * The value of the attribute to set.
203 * @return {Attributes}
207 Attributes.prototype.set = function (name, value) {
208 this.data[name] = value;
213 * Creates an Attributes instance.
215 * @param {object|Attributes} object
216 * An object to initialize attributes with.
218 * @returns {Attributes}
224 window.Attributes = function (object) {
225 return object instanceof Attributes ? object : new Attributes(object);
228 })(window.jQuery, window._);