nyc-bookstores/node_modules/cheerio/lib/api/attributes.js
2013-05-27 13:45:59 -07:00

150 lines
3.6 KiB
JavaScript

var _ = require('underscore'),
utils = require('../utils'),
isTag = utils.isTag,
decode = utils.decode,
encode = utils.encode,
rspace = /\s+/,
// Attributes that are booleans
rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i;
var setAttr = function(el, name, value) {
if (typeof name === 'object') return _.extend(el.attribs, name);
if (value === null) {
removeAttribute(el, name);
} else {
el.attribs[name] = encode(value);
}
return el.attribs;
};
var attr = exports.attr = function(name, value) {
var elem = this[0];
if (!elem || !isTag(elem))
return undefined;
if (!elem.attribs) {
elem.attribs = {};
}
// Return the entire attribs object if no attribute specified
if (!name) {
for (var a in elem.attribs) {
elem.attribs[a] = decode(elem.attribs[a]);
}
return elem.attribs;
}
// Set the value (with attr map support)
if (typeof name === 'object' || value !== undefined) {
this.each(function(i, el) {
el.attribs = setAttr(el, name, value);
});
return this;
} else if (Object.hasOwnProperty.call(elem.attribs, name)) {
// Get the (decoded) attribute
return decode(elem.attribs[name]);
}
};
/**
* Remove an attribute
*/
var removeAttribute = function(elem, name) {
if (!isTag(elem.type) || !elem.attribs || !Object.hasOwnProperty.call(elem.attribs, name))
return;
if (rboolean.test(elem.attribs[name]))
elem.attribs[name] = false;
else
delete elem.attribs[name];
};
var removeAttr = exports.removeAttr = function(name) {
this.each(function(i, elem) {
removeAttribute(elem, name);
});
return this;
};
var hasClass = exports.hasClass = function(className) {
return _.any(this, function(elem) {
var attrs = elem.attribs;
return attrs && _.contains((attrs['class'] || '').split(rspace), className);
});
};
var addClass = exports.addClass = function(value) {
// Support functions
if (_.isFunction(value)) {
this.each(function(i) {
var className = this.attr('class') || '';
this.addClass(value.call(this, i, className));
});
}
// Return if no value or not a string or function
if (!value || !_.isString(value)) return this;
var classNames = value.split(rspace),
numElements = this.length,
numClasses,
setClass,
$elem;
for (var i = 0; i < numElements; i++) {
$elem = this.make(this[i]);
// If selected element isnt a tag, move on
if (!isTag(this[i])) continue;
// If we don't already have classes
if (!$elem.attr('class')) {
$elem.attr('class', classNames.join(' ').trim());
} else {
setClass = ' ' + $elem.attr('class') + ' ';
numClasses = classNames.length;
// Check if class already exists
for (var j = 0; j < numClasses; j++) {
if (!~setClass.indexOf(' ' + classNames[j] + ' '))
setClass += classNames[j] + ' ';
}
$elem.attr('class', setClass.trim());
}
}
return this;
};
var removeClass = exports.removeClass = function(value) {
var split = function(className) {
return className ? className.trim().split(rspace) : [];
};
var classes = split(value);
// Handle if value is a function
if (_.isFunction(value)) {
return this.each(function(i, el) {
this.removeClass(value.call(this, i, el.attribs['class'] || ''));
});
}
return this.each(function(i, el) {
if (!isTag(el)) return;
el.attribs['class'] = (!value) ? '' : _.reject(
split(el.attribs['class']),
function(name) { return _.contains(classes, name); }
).join(' ');
});
};