/** * @for DOM * @module dom */ var documentElement = Y.config.doc.documentElement, Y_DOM = Y.DOM, TAG_NAME = 'tagName', OWNER_DOCUMENT = 'ownerDocument', EMPTY_STRING = '', addFeature = Y.Features.add, testFeature = Y.Features.test; Y.mix(Y_DOM, { /** * Returns the text content of the HTMLElement. * @method getText * @param {HTMLElement} element The html element. * @return {String} The text content of the element (includes text of any descending elements). */ getText: (documentElement.textContent !== undefined) ? function(element) { var ret = ''; if (element) { ret = element.textContent; } return ret || ''; } : function(element) { var ret = ''; if (element) { ret = element.innerText || element.nodeValue; // might be a textNode } return ret || ''; }, /** * Sets the text content of the HTMLElement. * @method setText * @param {HTMLElement} element The html element. * @param {String} content The content to add. */ setText: (documentElement.textContent !== undefined) ? function(element, content) { if (element) { element.textContent = content; } } : function(element, content) { if ('innerText' in element) { element.innerText = content; } else if ('nodeValue' in element) { element.nodeValue = content; } }, CUSTOM_ATTRIBUTES: (!documentElement.hasAttribute) ? { // IE < 8 'for': 'htmlFor', 'class': 'className' } : { // w3c 'htmlFor': 'for', 'className': 'class' }, /** * Provides a normalized attribute interface. * @method setAttribute * @param {HTMLElement} el The target element for the attribute. * @param {String} attr The attribute to set. * @param {String} val The value of the attribute. */ setAttribute: function(el, attr, val, ieAttr) { if (el && attr && el.setAttribute) { attr = Y_DOM.CUSTOM_ATTRIBUTES[attr] || attr; el.setAttribute(attr, val, ieAttr); } else { Y.log('bad input to setAttribute', 'warn', 'dom'); } }, /** * Provides a normalized attribute interface. * @method getAttribute * @param {HTMLElement} el The target element for the attribute. * @param {String} attr The attribute to get. * @return {String} The current value of the attribute. */ getAttribute: function(el, attr, ieAttr) { ieAttr = (ieAttr !== undefined) ? ieAttr : 2; var ret = ''; if (el && attr && el.getAttribute) { attr = Y_DOM.CUSTOM_ATTRIBUTES[attr] || attr; // BUTTON value issue for IE < 8 ret = (el.tagName === "BUTTON" && attr === 'value') ? Y_DOM.getValue(el) : el.getAttribute(attr, ieAttr); if (ret === null) { ret = ''; // per DOM spec } } else { Y.log('bad input to getAttribute', 'warn', 'dom'); } return ret; }, VALUE_SETTERS: {}, VALUE_GETTERS: {}, getValue: function(node) { var ret = '', // TODO: return null? getter; if (node && node[TAG_NAME]) { getter = Y_DOM.VALUE_GETTERS[node[TAG_NAME].toLowerCase()]; if (getter) { ret = getter(node); } else { ret = node.value; } } // workaround for IE8 JSON stringify bug // which converts empty string values to null if (ret === EMPTY_STRING) { ret = EMPTY_STRING; // for real } return (typeof ret === 'string') ? ret : ''; }, setValue: function(node, val) { var setter; if (node && node[TAG_NAME]) { setter = Y_DOM.VALUE_SETTERS[node[TAG_NAME].toLowerCase()]; val = (val === null) ? '' : val; if (setter) { setter(node, val); } else { node.value = val; } } }, creators: {} }); addFeature('value-set', 'select', { test: function() { var node = Y.config.doc.createElement('select'); node.innerHTML = '<option>1</option><option>2</option>'; node.value = '2'; return (node.value && node.value === '2'); } }); if (!testFeature('value-set', 'select')) { Y_DOM.VALUE_SETTERS.select = function(node, val) { for (var i = 0, options = node.getElementsByTagName('option'), option; option = options[i++];) { if (Y_DOM.getValue(option) === val) { option.selected = true; //Y_DOM.setAttribute(option, 'selected', 'selected'); break; } } }; } Y.mix(Y_DOM.VALUE_GETTERS, { button: function(node) { return (node.attributes && node.attributes.value) ? node.attributes.value.value : ''; } }); Y.mix(Y_DOM.VALUE_SETTERS, { // IE: node.value changes the button text, which should be handled via innerHTML button: function(node, val) { var attr = node.attributes.value; if (!attr) { attr = node[OWNER_DOCUMENT].createAttribute('value'); node.setAttributeNode(attr); } attr.value = val; } }); Y.mix(Y_DOM.VALUE_GETTERS, { option: function(node) { var attrs = node.attributes; return (attrs.value && attrs.value.specified) ? node.value : node.text; }, select: function(node) { var val = node.value, options = node.options; if (options && options.length) { // TODO: implement multipe select if (node.multiple) { Y.log('multiple select normalization not implemented', 'warn', 'DOM'); } else if (node.selectedIndex > -1) { val = Y_DOM.getValue(options[node.selectedIndex]); } } return val; } });