| Index: node_modules/vulcanize/node_modules/whacko/lib/api/attributes.js
|
| diff --git a/node_modules/vulcanize/node_modules/whacko/lib/api/attributes.js b/node_modules/vulcanize/node_modules/whacko/lib/api/attributes.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..22783f7251e072deab96e88ed7ae75018ff97c5a
|
| --- /dev/null
|
| +++ b/node_modules/vulcanize/node_modules/whacko/lib/api/attributes.js
|
| @@ -0,0 +1,416 @@
|
| +var _ = require('lodash'),
|
| + utils = require('../utils'),
|
| + isTag = utils.isTag,
|
| + domEach = utils.domEach,
|
| + hasOwn = Object.prototype.hasOwnProperty,
|
| + camelCase = utils.camelCase,
|
| + cssCase = utils.cssCase,
|
| + rspace = /\s+/,
|
| + dataAttrPrefix = 'data-',
|
| +
|
| + // Lookup table for coercing string data-* attributes to their corresponding
|
| + // JavaScript primitives
|
| + primitives = {
|
| + null: null,
|
| + true: true,
|
| + false: false
|
| + },
|
| +
|
| + // Attributes that are booleans
|
| + rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
|
| + // Matches strings that look like JSON objects or arrays
|
| + rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/;
|
| +
|
| +
|
| +var getAttr = function(elem, name) {
|
| + if (!elem || !isTag(elem)) return;
|
| +
|
| + if (!elem.attribs) {
|
| + elem.attribs = {};
|
| + }
|
| +
|
| + // Return the entire attribs object if no attribute specified
|
| + if (!name) {
|
| + return elem.attribs;
|
| + }
|
| +
|
| + if (hasOwn.call(elem.attribs, name)) {
|
| + // Get the (decoded) attribute
|
| + return rboolean.test(name) ? name : elem.attribs[name];
|
| + }
|
| +};
|
| +
|
| +var setAttr = function(el, name, value) {
|
| +
|
| + if (value === null) {
|
| + removeAttribute(el, name);
|
| + } else {
|
| + el.attribs[name] = value+'';
|
| + }
|
| +};
|
| +
|
| +exports.attr = function(name, value) {
|
| + // Set the value (with attr map support)
|
| + if (typeof name === 'object' || value !== undefined) {
|
| + if (typeof value === 'function') {
|
| + return domEach(this, function(i, el) {
|
| + setAttr(el, name, value.call(el, i, el.attribs[name]));
|
| + });
|
| + }
|
| + return domEach(this, function(i, el) {
|
| + if (!isTag(el)) return;
|
| +
|
| + if (typeof name === 'object') {
|
| + _.each(name, function(name, key) {
|
| + el.attribs[key] = name+'';
|
| + });
|
| + } else {
|
| + setAttr(el, name, value);
|
| + }
|
| + });
|
| + }
|
| +
|
| + return getAttr(this[0], name);
|
| +};
|
| +
|
| +var setData = function(el, name, value) {
|
| + if (typeof name === 'object') return _.extend(el.data, name);
|
| + if (typeof name === 'string' && value !== undefined) {
|
| + el.data[name] = value;
|
| + } else if (typeof name === 'object') {
|
| + _.exend(el.data, name);
|
| + }
|
| +};
|
| +
|
| +// Read the specified attribute from the equivalent HTML5 `data-*` attribute,
|
| +// and (if present) cache the value in the node's internal data store. If no
|
| +// attribute name is specified, read *all* HTML5 `data-*` attributes in this
|
| +// manner.
|
| +var readData = function(el, name) {
|
| + var readAll = arguments.length === 1;
|
| + var domNames, domName, jsNames, jsName, value, idx, length;
|
| +
|
| + if (readAll) {
|
| + domNames = Object.keys(el.attribs).filter(function(attrName) {
|
| + return attrName.slice(0, dataAttrPrefix.length) === dataAttrPrefix;
|
| + });
|
| + jsNames = domNames.map(function(domName) {
|
| + return camelCase(domName.slice(dataAttrPrefix.length));
|
| + });
|
| + } else {
|
| + domNames = [dataAttrPrefix + cssCase(name)];
|
| + jsNames = [name];
|
| + }
|
| +
|
| + for (idx = 0, length = domNames.length; idx < length; ++idx) {
|
| + domName = domNames[idx];
|
| + jsName = jsNames[idx];
|
| + if (hasOwn.call(el.attribs, domName)) {
|
| + value = el.attribs[domName];
|
| +
|
| + if (hasOwn.call(primitives, value)) {
|
| + value = primitives[value];
|
| + } else if (value === String(Number(value))) {
|
| + value = Number(value);
|
| + } else if (rbrace.test(value)) {
|
| + value = JSON.parse(value);
|
| + }
|
| +
|
| + el.data[jsName] = value;
|
| + }
|
| + }
|
| +
|
| + return readAll ? el.data : value;
|
| +};
|
| +
|
| +exports.data = function(name, value) {
|
| + var elem = this[0];
|
| +
|
| + if (!elem || !isTag(elem)) return;
|
| +
|
| + if (!elem.data) {
|
| + elem.data = {};
|
| + }
|
| +
|
| + // Return the entire data object if no data specified
|
| + if (!name) {
|
| + return readData(elem);
|
| + }
|
| +
|
| + // Set the value (with attr map support)
|
| + if (typeof name === 'object' || value !== undefined) {
|
| + domEach(this, function(i, el) {
|
| + setData(el, name, value);
|
| + });
|
| + return this;
|
| + } else if (hasOwn.call(elem.data, name)) {
|
| + return elem.data[name];
|
| + }
|
| +
|
| + return readData(elem, name);
|
| +};
|
| +
|
| +/**
|
| + * Get the value of an element
|
| + */
|
| +
|
| +exports.val = function(value) {
|
| + var querying = arguments.length === 0,
|
| + element = this[0];
|
| +
|
| + if(!element) return;
|
| +
|
| + switch (element.name) {
|
| + case 'textarea':
|
| + return this.text(value);
|
| + case 'input':
|
| + switch (this.attr('type')) {
|
| + case 'radio':
|
| + var queryString = 'input[type=radio][name="' + this.attr('name') + '"]:checked';
|
| + var parentEl, root;
|
| +
|
| + // Go up until we hit a form or root
|
| + parentEl = this.closest('form');
|
| + if (parentEl.length === 0) {
|
| + root = (this.parents().last()[0] || this[0]).root;
|
| + parentEl = this._make(root);
|
| + }
|
| +
|
| + if (querying) {
|
| + return parentEl.find(queryString).attr('value');
|
| + } else {
|
| + parentEl.find(':checked').removeAttr('checked');
|
| + parentEl.find('input[type=radio][value="' + value + '"]').attr('checked', '');
|
| + return this;
|
| + }
|
| + break;
|
| + default:
|
| + return this.attr('value', value);
|
| + }
|
| + return;
|
| + case 'select':
|
| + var option = this.find('option:selected'),
|
| + returnValue;
|
| + if (option === undefined) return undefined;
|
| + if (!querying) {
|
| + if (!this.attr().hasOwnProperty('multiple') && typeof value == 'object') {
|
| + return this;
|
| + }
|
| + if (typeof value != 'object') {
|
| + value = [value];
|
| + }
|
| + this.find('option').removeAttr('selected');
|
| + for (var i = 0; i < value.length; i++) {
|
| + this.find('option[value="' + value[i] + '"]').attr('selected', '');
|
| + }
|
| + return this;
|
| + }
|
| + returnValue = option.attr('value');
|
| + if (this.attr().hasOwnProperty('multiple')) {
|
| + returnValue = [];
|
| + domEach(option, function(i, el) {
|
| + returnValue.push(el.attribs.value);
|
| + });
|
| + }
|
| + return returnValue;
|
| + case 'option':
|
| + if (!querying) {
|
| + this.attr('value', value);
|
| + return this;
|
| + }
|
| + return this.attr('value');
|
| + }
|
| +};
|
| +
|
| +/**
|
| + * Remove an attribute
|
| + */
|
| +
|
| +var removeAttribute = function(elem, name) {
|
| + if (!elem.attribs || !hasOwn.call(elem.attribs, name))
|
| + return;
|
| +
|
| + delete elem.attribs[name];
|
| +};
|
| +
|
| +
|
| +exports.removeAttr = function(name) {
|
| + domEach(this, function(i, elem) {
|
| + removeAttribute(elem, name);
|
| + });
|
| +
|
| + return this;
|
| +};
|
| +
|
| +exports.hasClass = function(className) {
|
| + return _.any(this, function(elem) {
|
| + var attrs = elem.attribs,
|
| + clazz = attrs && attrs['class'],
|
| + idx = -1,
|
| + end;
|
| +
|
| + if (clazz) {
|
| + while ((idx = clazz.indexOf(className, idx+1)) > -1) {
|
| + end = idx + className.length;
|
| +
|
| + if ((idx === 0 || rspace.test(clazz[idx-1]))
|
| + && (end === clazz.length || rspace.test(clazz[end]))) {
|
| + return true;
|
| + }
|
| + }
|
| + }
|
| + });
|
| +};
|
| +
|
| +exports.addClass = function(value) {
|
| + // Support functions
|
| + if (typeof value === 'function') {
|
| + return domEach(this, function(i, el) {
|
| + var className = el.attribs['class'] || '';
|
| + exports.addClass.call([el], value.call(el, i, className));
|
| + });
|
| + }
|
| +
|
| + // Return if no value or not a string or function
|
| + if (!value || typeof value !== 'string') return this;
|
| +
|
| + var classNames = value.split(rspace),
|
| + numElements = this.length;
|
| +
|
| +
|
| + for (var i = 0; i < numElements; i++) {
|
| + // If selected element isn't a tag, move on
|
| + if (!isTag(this[i])) continue;
|
| +
|
| + // If we don't already have classes
|
| + var className = getAttr(this[i], 'class'),
|
| + numClasses,
|
| + setClass;
|
| +
|
| + if (!className) {
|
| + setAttr(this[i], 'class', classNames.join(' ').trim());
|
| + } else {
|
| + setClass = ' ' + className + ' ';
|
| + numClasses = classNames.length;
|
| +
|
| + // Check if class already exists
|
| + for (var j = 0; j < numClasses; j++) {
|
| + var appendClass = classNames[j] + ' ';
|
| + if (!~setClass.indexOf(' ' + appendClass))
|
| + setClass += appendClass;
|
| + }
|
| +
|
| + setAttr(this[i], 'class', setClass.trim());
|
| + }
|
| + }
|
| +
|
| + return this;
|
| +};
|
| +
|
| +var splitClass = function(className) {
|
| + return className ? className.trim().split(rspace) : [];
|
| +};
|
| +
|
| +exports.removeClass = function(value) {
|
| + var classes,
|
| + numClasses,
|
| + removeAll;
|
| +
|
| + // Handle if value is a function
|
| + if (typeof value === 'function') {
|
| + return domEach(this, function(i, el) {
|
| + exports.removeClass.call(
|
| + [el], value.call(el, i, el.attribs['class'] || '')
|
| + );
|
| + });
|
| + }
|
| +
|
| + classes = splitClass(value);
|
| + numClasses = classes.length;
|
| + removeAll = arguments.length === 0;
|
| +
|
| + return domEach(this, function(i, el) {
|
| + if (!isTag(el)) return;
|
| +
|
| + if (removeAll) {
|
| + // Short circuit the remove all case as this is the nice one
|
| + el.attribs.class = '';
|
| + } else {
|
| + var elClasses = splitClass(el.attribs.class),
|
| + index,
|
| + changed;
|
| +
|
| + for (var j = 0; j < numClasses; j++) {
|
| + index = elClasses.indexOf(classes[j]);
|
| +
|
| + if (index >= 0) {
|
| + elClasses.splice(index, 1);
|
| + changed = true;
|
| +
|
| + // We have to do another pass to ensure that there are not duplicate
|
| + // classes listed
|
| + j--;
|
| + }
|
| + }
|
| + if (changed) {
|
| + el.attribs.class = elClasses.join(' ');
|
| + }
|
| + }
|
| + });
|
| +};
|
| +
|
| +exports.toggleClass = function(value, stateVal) {
|
| + // Support functions
|
| + if (typeof value === 'function') {
|
| + return domEach(this, function(i, el) {
|
| + exports.toggleClass.call(
|
| + [el],
|
| + value.call(el, i, el.attribs['class'] || '', stateVal),
|
| + stateVal
|
| + );
|
| + });
|
| + }
|
| +
|
| + // Return if no value or not a string or function
|
| + if (!value || typeof value !== 'string') return this;
|
| +
|
| + var classNames = value.split(rspace),
|
| + numClasses = classNames.length,
|
| + state = typeof stateVal === 'boolean' ? stateVal ? 1 : -1 : 0,
|
| + numElements = this.length,
|
| + elementClasses,
|
| + index;
|
| +
|
| + for (var i = 0; i < numElements; i++) {
|
| + // If selected element isn't a tag, move on
|
| + if (!isTag(this[i])) continue;
|
| +
|
| + elementClasses = splitClass(this[i].attribs.class);
|
| +
|
| + // Check if class already exists
|
| + for (var j = 0; j < numClasses; j++) {
|
| + // Check if the class name is currently defined
|
| + index = elementClasses.indexOf(classNames[j]);
|
| +
|
| + // Add if stateValue === true or we are toggling and there is no value
|
| + if (state >= 0 && index < 0) {
|
| + elementClasses.push(classNames[j]);
|
| + } else if (state <= 0 && index >= 0) {
|
| + // Otherwise remove but only if the item exists
|
| + elementClasses.splice(index, 1);
|
| + }
|
| + }
|
| +
|
| + this[i].attribs.class = elementClasses.join(' ');
|
| + }
|
| +
|
| + return this;
|
| +};
|
| +
|
| +exports.is = function (selector) {
|
| + if (selector) {
|
| + return this.filter(selector).length > 0;
|
| + }
|
| + return false;
|
| +};
|
| +
|
|
|