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; |
+}; |
+ |