diff -r 000000000000 -r 40c8f766c9b8 src/cm/media/js/lib/yui/yui_3.0.0b1/build/dom/dom-debug.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cm/media/js/lib/yui/yui_3.0.0b1/build/dom/dom-debug.js Mon Nov 23 15:14:29 2009 +0100 @@ -0,0 +1,2720 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 3.0.0b1 +build: 1163 +*/ +YUI.add('dom-base', function(Y) { + +(function(Y) { +/** + * The DOM utility provides a cross-browser abtraction layer + * normalizing DOM tasks, and adds extra helper functionality + * for other common tasks. + * @module dom + * @submodule dom-base + * + */ + +/** + * Provides DOM helper methods. + * @class DOM + * + */ +var NODE_TYPE = 'nodeType', + OWNER_DOCUMENT = 'ownerDocument', + DOCUMENT_ELEMENT = 'documentElement', + DEFAULT_VIEW = 'defaultView', + PARENT_WINDOW = 'parentWindow', + TAG_NAME = 'tagName', + PARENT_NODE = 'parentNode', + FIRST_CHILD = 'firstChild', + LAST_CHILD = 'lastChild', + PREVIOUS_SIBLING = 'previousSibling', + NEXT_SIBLING = 'nextSibling', + CONTAINS = 'contains', + COMPARE_DOCUMENT_POSITION = 'compareDocumentPosition', + + re_tag = /<([a-z]+)/i; + +Y.DOM = { + /** + * Returns the HTMLElement with the given ID (Wrapper for document.getElementById). + * @method byId + * @param {String} id the id attribute + * @param {Object} doc optional The document to search. Defaults to current document + * @return {HTMLElement | null} The HTMLElement with the id, or null if none found. + */ + byId: function(id, doc) { + doc = doc || Y.config.doc; + // TODO: IE Name + return doc.getElementById(id); + }, + + /** + * 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: (document.documentElement.textContent !== undefined) ? + function(element) { + var ret = ''; + if (element) { + ret = element.textContent; + } + return ret || ''; + } : function(element) { + var ret = ''; + if (element) { + ret = element.innerText; + } + 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: (document.documentElement.textContent !== undefined) ? + function(element, content) { + if (element) { + element.textContent = content; + } + } : function(element, content) { + if (element) { + element.innerText = content; + } + }, + +// TODO: pull out sugar (rely on _childBy, byAxis, etc)? + /* + * Finds the firstChild of the given HTMLElement. + * @method firstChild + * @deprecated Use _childBy + * @param {HTMLElement} element The html element. + * @param {Function} fn optional An optional boolean test to apply. + * The optional function is passed the current HTMLElement being tested as its only argument. + * If no function is given, the first found is returned. + * @return {HTMLElement | null} The first matching child html element. + */ + firstChild: function(element, fn) { + return Y.DOM._childBy(element, null, fn); + }, + + // @deprecated Use _childBy + firstChildByTag: function(element, tag, fn) { + return Y.DOM._childBy(element, tag, fn); + }, + + /* + * Finds the lastChild of the given HTMLElement. + * @method lastChild + * @deprecated Use _childBy + * @param {HTMLElement} element The html element. + * @param {String} tag The tag to search for. + * @param {Function} fn optional An optional boolean test to apply. + * The optional function is passed the current HTMLElement being tested as its only argument. + * If no function is given, the first found is returned. + * @return {HTMLElement | null} The first matching child html element. + */ + lastChild: function(element, fn) { + return Y.DOM._childBy(element, null, fn, true); + }, + + // @deprecated Use _childBy + lastChildByTag: function(element, tag, fn) { + return Y.DOM._childBy(element, tag, fn, true); + }, + + /* + * Finds all HTMLElement childNodes matching the given tag. + * @method childrenByTag + * @deprecated Use Selector + * @param {HTMLElement} element The html element. + * @param {String} tag The tag to search for. + * @param {Function} fn optional An optional boolean test to apply. + * The optional function is passed the current HTMLElement being tested as its only argument. + * If no function is given, all children with the given tag are collected. + * @return {Array} The collection of child elements. + * TODO: Webkit children.tags() returns grandchildren + */ + _childrenByTag: function() { + if (document[DOCUMENT_ELEMENT].children) { + return function(element, tag, fn, toArray) { // TODO: keep toArray option? + tag = (tag && tag !== '*') ? tag.toUpperCase() : null; + var elements = [], + wrapFn = fn; + if (element) { + if (tag && !Y.UA.webkit) { // children.tags() broken in safari + elements = element.children.tags(tag); + } else { + elements = element.children; + if (tag) { + wrapFn = function(el) { + return el[TAG_NAME].toUpperCase() === tag && (!fn || fn(el)); + }; + } + } + + elements = Y.DOM.filterElementsBy(elements, wrapFn); + } + + return elements; + }; + } else { + return function(element, tag, fn) { + tag = (tag && tag !== '*') ? tag.toUpperCase() : null; + var elements = [], + wrapFn = fn; + + if (element) { + elements = element.childNodes; + if (tag) { // wrap fn and add tag test TODO: allow tag in filterElementsBy? + wrapFn = function(el) { + return el[TAG_NAME].toUpperCase() === tag && (!fn || fn(el)); + }; + } + + elements = Y.DOM.filterElementsBy(elements, wrapFn); + } + return elements; + }; + } + }(), + + /* + * Finds all HTMLElement childNodes. + * @method children + * @deprecated Use Selector + * @param {HTMLElement} element The html element. + * @param {Function} fn optional An optional boolean test to apply. + * The optional function is passed the current HTMLElement being tested as its only argument. + * If no function is given, all children are collected. + * @return {Array} The collection of child elements. + */ + children: function(element, fn) { + return Y.DOM._childrenByTag(element, null, fn); + }, + + /* + * Finds the previous sibling of the element. + * @method previous + * @deprecated Use elementByAxis + * @param {HTMLElement} element The html element. + * @param {Function} fn optional An optional boolean test to apply. + * The optional function is passed the current DOM node being tested as its only argument. + * If no function is given, the first sibling is returned. + * @param {Boolean} all optional Whether all node types should be scanned, or just element nodes. + * @return {HTMLElement | null} The matching DOM node or null if none found. + */ + previous: function(element, fn, all) { + return Y.DOM.elementByAxis(element, PREVIOUS_SIBLING, fn, all); + }, + + /* + * Finds the next sibling of the element. + * @method next + * @deprecated Use elementByAxis + * @param {HTMLElement} element The html element. + * @param {Function} fn optional An optional boolean test to apply. + * The optional function is passed the current DOM node being tested as its only argument. + * If no function is given, the first sibling is returned. + * @param {Boolean} all optional Whether all node types should be scanned, or just element nodes. + * @return {HTMLElement | null} The matching DOM node or null if none found. + */ + next: function(element, fn, all) { + return Y.DOM.elementByAxis(element, NEXT_SIBLING, fn, all); + }, + + /* + * Finds the ancestor of the element. + * @method ancestor + * @deprecated Use elementByAxis + * @param {HTMLElement} element The html element. + * @param {Function} fn optional An optional boolean test to apply. + * The optional function is passed the current DOM node being tested as its only argument. + * If no function is given, the parentNode is returned. + * @param {Boolean} all optional Whether all node types should be scanned, or just element nodes. + * @return {HTMLElement | null} The matching DOM node or null if none found. + */ + // TODO: optional stopAt node? + ancestor: function(element, fn, all) { + return Y.DOM.elementByAxis(element, PARENT_NODE, fn, all); + }, + + /** + * Searches the element by the given axis for the first matching element. + * @method elementByAxis + * @param {HTMLElement} element The html element. + * @param {String} axis The axis to search (parentNode, nextSibling, previousSibling). + * @param {Function} fn optional An optional boolean test to apply. + * @param {Boolean} all optional Whether all node types should be returned, or just element nodes. + * The optional function is passed the current HTMLElement being tested as its only argument. + * If no function is given, the first element is returned. + * @return {HTMLElement | null} The matching element or null if none found. + */ + elementByAxis: function(element, axis, fn, all) { + while (element && (element = element[axis])) { // NOTE: assignment + if ( (all || element[TAG_NAME]) && (!fn || fn(element)) ) { + return element; + } + } + return null; + }, + + /* + * Finds all elements with the given tag. + * @method byTag + * @deprecated Use Selector + * @param {String} tag The tag being search for. + * @param {HTMLElement} root optional An optional root element to start from. + * @param {Function} fn optional An optional boolean test to apply. + * The optional function is passed the current HTMLElement being tested as its only argument. + * If no function is given, all elements with the given tag are returned. + * @return {Array} The collection of matching elements. + */ + byTag: function(tag, root, fn) { + root = root || Y.config.doc; + + var elements = root.getElementsByTagName(tag), + retNodes = [], + i, len; + + for (i = 0, len = elements.length; i < len; ++i) { + if ( !fn || fn(elements[i]) ) { + retNodes[retNodes.length] = elements[i]; + } + } + return retNodes; + }, + + /* + * Finds the first element with the given tag. + * @method firstByTag + * @deprecated Use Selector + * @param {String} tag The tag being search for. + * @param {HTMLElement} root optional An optional root element to start from. + * @param {Function} fn optional An optional boolean test to apply. + * The optional function is passed the current HTMLElement being tested as its only argument. + * If no function is given, the first match is returned. + * @return {HTMLElement} The matching element. + */ + firstByTag: function(tag, root, fn) { + root = root || Y.config.doc; + + var elements = root.getElementsByTagName(tag), + ret = null, + i, len; + + for (i = 0, len = elements.length; i < len; ++i) { + if ( !fn || fn(elements[i]) ) { + ret = elements[i]; + break; + } + } + return ret; + }, + + /* + * Filters a collection of HTMLElements by the given attributes. + * @method filterElementsBy + * @param {Array} elements The collection of HTMLElements to filter. + * @param {Function} fn A boolean test to apply. + * The function is passed the current HTMLElement being tested as its only argument. + * If no function is given, all HTMLElements are kept. + * @return {Array} The filtered collection of HTMLElements. + */ + filterElementsBy: function(elements, fn, firstOnly) { + var ret = (firstOnly) ? null : [], + i, len; + for (i = 0, len = elements.length; i < len; ++i) { + if (elements[i][TAG_NAME] && (!fn || fn(elements[i]))) { + if (firstOnly) { + ret = elements[i]; + break; + } else { + ret[ret.length] = elements[i]; + } + } + } + + return ret; + }, + + /** + * Determines whether or not one HTMLElement is or contains another HTMLElement. + * @method contains + * @param {HTMLElement} element The containing html element. + * @param {HTMLElement} needle The html element that may be contained. + * @return {Boolean} Whether or not the element is or contains the needle. + */ + contains: function(element, needle) { + var ret = false; + + if ( !needle || !element || !needle[NODE_TYPE] || !element[NODE_TYPE]) { + ret = false; + } else if (element[CONTAINS]) { + if (Y.UA.opera || needle[NODE_TYPE] === 1) { // IE & SAF contains fail if needle not an ELEMENT_NODE + ret = element[CONTAINS](needle); + } else { + ret = Y.DOM._bruteContains(element, needle); + } + } else if (element[COMPARE_DOCUMENT_POSITION]) { // gecko + if (element === needle || !!(element[COMPARE_DOCUMENT_POSITION](needle) & 16)) { + ret = true; + } + } + + return ret; + }, + + /** + * Determines whether or not the HTMLElement is part of the document. + * @method inDoc + * @param {HTMLElement} element The containing html element. + * @param {HTMLElement} doc optional The document to check. + * @return {Boolean} Whether or not the element is attached to the document. + */ + inDoc: function(element, doc) { + doc = doc || element[OWNER_DOCUMENT]; + var id = element.id; + if (!id) { // TODO: remove when done? + id = element.id = Y.guid(); + } + + return !! (doc.getElementById(id)); + }, + + /** + * Inserts the new node as the previous sibling of the reference node + * @method insertBefore + * @param {String | HTMLElement} newNode The node to be inserted + * @param {String | HTMLElement} referenceNode The node to insert the new node before + * @return {HTMLElement} The node that was inserted (or null if insert fails) + */ + insertBefore: function(newNode, referenceNode) { + var ret = null, + parent; + if (newNode && referenceNode && (parent = referenceNode.parentNode)) { // NOTE: assignment + if (typeof newNode === 'string') { + newNode = Y.DOM.create(newNode); + } + ret = parent.insertBefore(newNode, referenceNode); + } else { + Y.log('insertBefore failed: missing or invalid arg(s)', 'error', 'dom'); + } + return ret; + }, + + /** + * Inserts the new node as the next sibling of the reference node + * @method insertAfter + * @param {String | HTMLElement} newNode The node to be inserted + * @param {String | HTMLElement} referenceNode The node to insert the new node after + * @return {HTMLElement} The node that was inserted (or null if insert fails) + */ + insertAfter: function(newNode, referenceNode) { + if (!newNode || !referenceNode || !referenceNode[PARENT_NODE]) { + Y.log('insertAfter failed: missing or invalid arg(s)', 'error', 'DOM'); + return null; + } + + if (typeof newNode === 'string') { + newNode = Y.DOM.create(newNode); + } + + if (referenceNode[NEXT_SIBLING]) { + return referenceNode[PARENT_NODE].insertBefore(newNode, referenceNode[NEXT_SIBLING]); + } else { + return referenceNode[PARENT_NODE].appendChild(newNode); + } + }, + + /** + * Creates a new dom node using the provided markup string. + * @method create + * @param {String} html The markup used to create the element + * @param {HTMLDocument} doc An optional document context + */ + create: function(html, doc) { + html = Y.Lang.trim(html); // match IE which trims whitespace from innerHTML + if (!doc && Y.DOM._cloneCache[html]) { + return Y.DOM._cloneCache[html].cloneNode(true); // NOTE: return + } + + doc = doc || Y.config.doc; + var m = re_tag.exec(html), + create = Y.DOM._create, + custom = Y.DOM.creators, + ret = null, + tag, nodes; + + if (m && custom[m[1]]) { + if (typeof custom[m[1]] === 'function') { + create = custom[m[1]]; + } else { + tag = custom[m[1]]; + } + } + + nodes = create(html, doc, tag).childNodes; + + if (nodes.length === 1) { // return single node, breaking parentNode ref from "fragment" + ret = nodes[0].parentNode.removeChild(nodes[0]); + } else { // return multiple nodes as a fragment + ret = doc.createDocumentFragment(); + while (nodes.length) { + ret.appendChild(nodes[0]); + } + } + + Y.DOM._cloneCache[html] = ret.cloneNode(true); + return ret; + }, + + CUSTOM_ATTRIBUTES: (!document.documentElement.hasAttribute) ? { // IE < 8 + 'for': 'htmlFor', + 'class': 'className' + } : { // w3c + 'htmlFor': 'for', + 'className': 'class' + }, + + /** + * Provides a normalized attribute interface. + * @method setAttibute + * @param {String | 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) { + if (el && el.setAttribute) { + attr = Y.DOM.CUSTOM_ATTRIBUTES[attr] || attr; + el.setAttribute(attr, val); + } + }, + + + /** + * Provides a normalized attribute interface. + * @method getAttibute + * @param {String | 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) { + var ret = ''; + if (el && el.getAttribute) { + attr = Y.DOM.CUSTOM_ATTRIBUTES[attr] || attr; + ret = el.getAttribute(attr, 2); + + if (ret === null) { + ret = ''; // per DOM spec + } + } + return ret; + }, + + // @deprecated + srcIndex: (document.documentElement.sourceIndex) ? + function(node) { + return (node && node.sourceIndex) ? node.sourceIndex : null; + } : + function(node) { + return (node && node[OWNER_DOCUMENT]) ? + [].indexOf.call(node[OWNER_DOCUMENT]. + getElementsByTagName('*'), node) : null; + }, + + isWindow: function(obj) { + return obj.alert && obj.document; + }, + + _fragClones: { + div: document.createElement('div') + }, + + _create: function(html, doc, tag) { + tag = tag || 'div'; + + var frag = Y.DOM._fragClones[tag]; + if (frag) { + frag = frag.cloneNode(false); + } else { + frag = Y.DOM._fragClones[tag] = doc.createElement(tag); + } + frag.innerHTML = html; + return frag; + }, + + _removeChildNodes: function(node) { + while (node.firstChild) { + node.removeChild(node.firstChild); + } + }, + + _cloneCache: {}, + + /** + * Inserts content in a node at the given location + * @method addHTML + * @param {HTMLElement} node The node to insert into + * @param {String} content The content to be inserted + * @param {String} where Where to insert the content; default is after lastChild + */ + addHTML: function(node, content, where) { + if (typeof content === 'string') { + content = Y.Lang.trim(content); // match IE which trims whitespace from innerHTML + } + + var newNode = Y.DOM._cloneCache[content]; + + if (newNode) { + newNode = newNode.cloneNode(true); + } else { + if (content.nodeType) { // domNode + newNode = content; + } else { // create from string and cache + newNode = Y.DOM.create(content); + } + } + + if (where) { + if (where.nodeType) { // insert regardless of relationship to node + // TODO: check if node.contains(where)? + where.parentNode.insertBefore(newNode, where); + } else { + switch (where) { + case 'replace': + while (node.firstChild) { + node.removeChild(node.firstChild); + } + node.appendChild(newNode); + break; + case 'before': + node.parentNode.insertBefore(newNode, node); + break; + case 'after': + if (node.nextSibling) { // IE errors if refNode is null + node.parentNode.insertBefore(newNode, node.nextSibling); + } else { + node.parentNode.appendChild(newNode); + } + break; + default: + node.appendChild(newNode); + } + } + } else { + node.appendChild(newNode); + } + + return newNode; + }, + + 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; + } + } + + 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()]; + + if (setter) { + setter(node, val); + } else { + node.value = val; + } + } + }, + + _stripScripts: function(node) { + var scripts = node.getElementsByTagName('script'), + i, script; + + for (i = 0, script; script = scripts[i++];) { + script.parentNode.removeChild(script); + } + }, + + _execScripts: function(scripts, startIndex) { + var newScript, + i, script; + + startIndex = startIndex || 0; + + for (i = startIndex, script; script = scripts[i++];) { + newScript = script.ownerDocument.createElement('script'); + script.parentNode.replaceChild(newScript, script); + if (script.text) { + newScript.text = script.text; + } else if (script.src) { + newScript.src = script.src; + + // "pause" while loading to ensure exec order + // FF reports typeof onload as "undefined", so try IE first + if (typeof newScript.onreadystatechange !== 'undefined') { + newScript.onreadystatechange = function() { + if (/loaded|complete/.test(script.readyState)) { + event.srcElement.onreadystatechange = null; + // timer to help ensure exec order + setTimeout(function() { + Y.DOM._execScripts(scripts, i++); + }, 0); + } + }; + } else { + newScript.onload = function(e) { + e.target.onload = null; + Y.DOM._execScripts(scripts, i++); + }; + } + return; // NOTE: early return to chain async loading + } + } + }, + + /** + * Brute force version of contains. + * Used for browsers without contains support for non-HTMLElement Nodes (textNodes, etc). + * @method _bruteContains + * @private + * @param {HTMLElement} element The containing html element. + * @param {HTMLElement} needle The html element that may be contained. + * @return {Boolean} Whether or not the element is or contains the needle. + */ + _bruteContains: function(element, needle) { + while (needle) { + if (element === needle) { + return true; + } + needle = needle.parentNode; + } + return false; + }, + +// TODO: move to Lang? + /** + * Memoizes dynamic regular expressions to boost runtime performance. + * @method _getRegExp + * @private + * @param {String} str The string to convert to a regular expression. + * @param {String} flags optional An optinal string of flags. + * @return {RegExp} An instance of RegExp + */ + _getRegExp: function(str, flags) { + flags = flags || ''; + Y.DOM._regexCache = Y.DOM._regexCache || {}; + if (!Y.DOM._regexCache[str + flags]) { + Y.DOM._regexCache[str + flags] = new RegExp(str, flags); + } + return Y.DOM._regexCache[str + flags]; + }, + +// TODO: make getDoc/Win true privates? + /** + * returns the appropriate document. + * @method _getDoc + * @private + * @param {HTMLElement} element optional Target element. + * @return {Object} The document for the given element or the default document. + */ + _getDoc: function(element) { + element = element || {}; + + return (element[NODE_TYPE] === 9) ? element : // element === document + element[OWNER_DOCUMENT] || // element === DOM node + element.document || // element === window + Y.config.doc; // default + }, + + /** + * returns the appropriate window. + * @method _getWin + * @private + * @param {HTMLElement} element optional Target element. + * @return {Object} The window for the given element or the default window. + */ + _getWin: function(element) { + var doc = Y.DOM._getDoc(element); + return doc[DEFAULT_VIEW] || doc[PARENT_WINDOW] || Y.config.win; + }, + + // @deprecated, use Selector + _childBy: function(element, tag, fn, rev) { + var ret = null, + root, axis; + + if (element) { + if (rev) { + root = element[LAST_CHILD]; + axis = PREVIOUS_SIBLING; + } else { + root = element[FIRST_CHILD]; + axis = NEXT_SIBLING; + } + + if (Y.DOM._testElement(root, tag, fn)) { // is the matching element + ret = root; + } else { // need to scan nextSibling axis of firstChild to find matching element + ret = Y.DOM.elementByAxis(root, axis, fn); + } + } + return ret; + + }, + + _batch: function(nodes, fn, arg1, arg2, arg3, etc) { + fn = (typeof name === 'string') ? Y.DOM[fn] : fn; + var result, + ret = []; + + if (fn && nodes) { + Y.each(nodes, function(node) { + if ((result = fn.call(Y.DOM, node, arg1, arg2, arg3, etc)) !== undefined) { + ret[ret.length] = result; + } + }); + } + + return ret.length ? ret : nodes; + }, + + _testElement: function(element, tag, fn) { + tag = (tag && tag !== '*') ? tag.toUpperCase() : null; + return (element && element[TAG_NAME] && + (!tag || element[TAG_NAME].toUpperCase() === tag) && + (!fn || fn(element))); + }, + + creators: {}, + + _IESimpleCreate: function(html, doc) { + doc = doc || Y.config.doc; + return doc.createElement(html); + } +}; + + +(function(Y) { + var creators = Y.DOM.creators, + create = Y.DOM.create, + re_tbody = /(?:\/(?:thead|tfoot|tbody|caption|col|colgroup)>)+\s*' + html + '', doc); + }, + + tr: function(html, doc) { + return create('' + html + '', doc); + }, + + td: function(html, doc) { + return create('' + html + '', doc); + }, + + tbody: function(html, doc) { + return create(TABLE_OPEN + html + TABLE_CLOSE, doc); + }, + + legend: 'fieldset' + }); + + creators.col = creators.tbody; // IE wraps in colgroup + } + + if (Y.UA.ie) { + Y.mix(creators, { + // TODO: thead/tfoot with nested tbody + // IE adds TBODY when creating TABLE elements (which may share this impl) + tbody: function(html, doc) { + var frag = create(TABLE_OPEN + html + TABLE_CLOSE, doc), + tb = frag.children.tags('tbody')[0]; + + if (frag.children.length > 1 && tb && !re_tbody.test(html)) { + tb[PARENT_NODE].removeChild(tb); // strip extraneous tbody + } + return frag; + }, + + script: function(html, doc) { + var frag = doc.createElement('div'); + + frag.innerHTML = '-' + html; + frag.removeChild(frag[FIRST_CHILD]); + return frag; + } + + }, true); + + 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; + } + }); + } + + if (Y.UA.gecko || Y.UA.ie) { + Y.mix(creators, { + th: creators.td, + thead: creators.tbody, + tfoot: creators.tbody, + caption: creators.tbody, + colgroup: creators.tbody, + col: creators.tbody, + optgroup: creators.option + }); + } + + 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 && val === '') { + if (node.multiple) { + Y.log('multiple select normalization not implemented', 'warn', 'DOM'); + } else { + val = Y.DOM.getValue(options[node.selectedIndex], 'value'); + } + } + + return val; + } + }); +})(Y); + +})(Y); +Y.mix(Y.DOM, { + /** + * Determines whether a DOM element has the given className. + * @method hasClass + * @param {HTMLElement} element The DOM element. + * @param {String} className the class name to search for + * @return {Boolean} Whether or not the element has the given class. + */ + hasClass: function(node, className) { + var re = Y.DOM._getRegExp('(?:^|\\s+)' + className + '(?:\\s+|$)'); + return re.test(node.className); + }, + + /** + * Adds a class name to a given DOM element. + * @method addClass + * @param {HTMLElement} element The DOM element. + * @param {String} className the class name to add to the class attribute + */ + addClass: function(node, className) { + if (!Y.DOM.hasClass(node, className)) { // skip if already present + node.className = Y.Lang.trim([node.className, className].join(' ')); + } + }, + + /** + * Removes a class name from a given element. + * @method removeClass + * @param {HTMLElement} element The DOM element. + * @param {String} className the class name to remove from the class attribute + */ + removeClass: function(node, className) { + if (className && Y.DOM.hasClass(node, className)) { + node.className = Y.Lang.trim(node.className.replace(Y.DOM._getRegExp('(?:^|\\s+)' + + className + '(?:\\s+|$)'), ' ')); + + if ( Y.DOM.hasClass(node, className) ) { // in case of multiple adjacent + Y.DOM.removeClass(node, className); + } + } + }, + + /** + * Replace a class with another class for a given element. + * If no oldClassName is present, the newClassName is simply added. + * @method replaceClass + * @param {HTMLElement} element The DOM element. + * @param {String} oldClassName the class name to be replaced + * @param {String} newClassName the class name that will be replacing the old class name + */ + replaceClass: function(node, oldC, newC) { + //Y.log('replaceClass replacing ' + oldC + ' with ' + newC, 'info', 'Node'); + Y.DOM.addClass(node, newC); + Y.DOM.removeClass(node, oldC); + }, + + /** + * If the className exists on the node it is removed, if it doesn't exist it is added. + * @method toggleClass + * @param {HTMLElement} element The DOM element. + * @param {String} className the class name to be toggled + */ + toggleClass: function(node, className) { + if (Y.DOM.hasClass(node, className)) { + Y.DOM.removeClass(node, className); + } else { + Y.DOM.addClass(node, className); + } + } +}); + + + +}, '3.0.0b1' ,{requires:['event'], skinnable:false}); +YUI.add('dom-style', function(Y) { + +(function(Y) { +/** + * Add style management functionality to DOM. + * @module dom + * @submodule dom-style + * @for DOM + */ + +var DOCUMENT_ELEMENT = 'documentElement', + DEFAULT_VIEW = 'defaultView', + OWNER_DOCUMENT = 'ownerDocument', + STYLE = 'style', + FLOAT = 'float', + CSS_FLOAT = 'cssFloat', + STYLE_FLOAT = 'styleFloat', + TRANSPARENT = 'transparent', + GET_COMPUTED_STYLE = 'getComputedStyle', + + DOCUMENT = Y.config.doc, + UNDEFINED = undefined, + + re_color = /color$/i; + + +Y.mix(Y.DOM, { + CUSTOM_STYLES: { + }, + + + /** + * Sets a style property for a given element. + * @method setStyle + * @param {HTMLElement} An HTMLElement to apply the style to. + * @param {String} att The style property to set. + * @param {String|Number} val The value. + */ + setStyle: function(node, att, val, style) { + style = style || node.style; + var CUSTOM_STYLES = Y.DOM.CUSTOM_STYLES; + + if (style) { + if (val === null) { + val = ''; // normalize for unsetting + } + if (att in CUSTOM_STYLES) { + if (CUSTOM_STYLES[att].set) { + CUSTOM_STYLES[att].set(node, val, style); + return; // NOTE: return + } else if (typeof CUSTOM_STYLES[att] === 'string') { + att = CUSTOM_STYLES[att]; + } + } + style[att] = val; + } + }, + + /** + * Returns the current style value for the given property. + * @method getStyle + * @param {HTMLElement} An HTMLElement to get the style from. + * @param {String} att The style property to get. + */ + getStyle: function(node, att) { + var style = node[STYLE], + CUSTOM_STYLES = Y.DOM.CUSTOM_STYLES, + val = ''; + + if (style) { + if (att in CUSTOM_STYLES) { + if (CUSTOM_STYLES[att].get) { + return CUSTOM_STYLES[att].get(node, att, style); // NOTE: return + } else if (typeof CUSTOM_STYLES[att] === 'string') { + att = CUSTOM_STYLES[att]; + } + } + val = style[att]; + if (val === '') { // TODO: is empty string sufficient? + val = Y.DOM[GET_COMPUTED_STYLE](node, att); + } + } + + return val; + }, + + /** + * Sets multiple style properties. + * @method setStyles + * @param {HTMLElement} node An HTMLElement to apply the styles to. + * @param {Object} hash An object literal of property:value pairs. + */ + setStyles: function(node, hash) { + var style = node.style; + Y.each(hash, function(v, n) { + Y.DOM.setStyle(node, n, v, style); + }, Y.DOM); + }, + + /** + * Returns the computed style for the given node. + * @method getComputedStyle + * @param {HTMLElement} An HTMLElement to get the style from. + * @param {String} att The style property to get. + * @return {String} The computed value of the style property. + */ + getComputedStyle: function(node, att) { + var val = '', + doc = node[OWNER_DOCUMENT]; + + if (node[STYLE]) { + val = doc[DEFAULT_VIEW][GET_COMPUTED_STYLE](node, null)[att]; + } + return val; + } +}); + +// normalize reserved word float alternatives ("cssFloat" or "styleFloat") +if (DOCUMENT[DOCUMENT_ELEMENT][STYLE][CSS_FLOAT] !== UNDEFINED) { + Y.DOM.CUSTOM_STYLES[FLOAT] = CSS_FLOAT; +} else if (DOCUMENT[DOCUMENT_ELEMENT][STYLE][STYLE_FLOAT] !== UNDEFINED) { + Y.DOM.CUSTOM_STYLES[FLOAT] = STYLE_FLOAT; +} + +// fix opera computedStyle default color unit (convert to rgb) +if (Y.UA.opera) { + Y.DOM[GET_COMPUTED_STYLE] = function(node, att) { + var view = node[OWNER_DOCUMENT][DEFAULT_VIEW], + val = view[GET_COMPUTED_STYLE](node, '')[att]; + + if (re_color.test(att)) { + val = Y.Color.toRGB(val); + } + + return val; + }; + +} + +// safari converts transparent to rgba(), others use "transparent" +if (Y.UA.webkit) { + Y.DOM[GET_COMPUTED_STYLE] = function(node, att) { + var view = node[OWNER_DOCUMENT][DEFAULT_VIEW], + val = view[GET_COMPUTED_STYLE](node, '')[att]; + + if (val === 'rgba(0, 0, 0, 0)') { + val = TRANSPARENT; + } + + return val; + }; + +} +})(Y); +(function(Y) { +var TO_STRING = 'toString', + PARSE_INT = parseInt, + RE = RegExp; + +Y.Color = { + KEYWORDS: { + black: '000', + silver: 'c0c0c0', + gray: '808080', + white: 'fff', + maroon: '800000', + red: 'f00', + purple: '800080', + fuchsia: 'f0f', + green: '008000', + lime: '0f0', + olive: '808000', + yellow: 'ff0', + navy: '000080', + blue: '00f', + teal: '008080', + aqua: '0ff' + }, + + re_RGB: /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i, + re_hex: /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i, + re_hex3: /([0-9A-F])/gi, + + toRGB: function(val) { + if (!Y.Color.re_RGB.test(val)) { + val = Y.Color.toHex(val); + } + + if(Y.Color.re_hex.exec(val)) { + val = 'rgb(' + [ + PARSE_INT(RE.$1, 16), + PARSE_INT(RE.$2, 16), + PARSE_INT(RE.$3, 16) + ].join(', ') + ')'; + } + return val; + }, + + toHex: function(val) { + val = Y.Color.KEYWORDS[val] || val; + if (Y.Color.re_RGB.exec(val)) { + var r = (RE.$1.length === 1) ? '0' + RE.$1 : Number(RE.$1), + g = (RE.$2.length === 1) ? '0' + RE.$2 : Number(RE.$2), + b = (RE.$3.length === 1) ? '0' + RE.$3 : Number(RE.$3); + + val = [ + r[TO_STRING](16), + g[TO_STRING](16), + b[TO_STRING](16) + ].join(''); + } + + if (val.length < 6) { + val = val.replace(Y.Color.re_hex3, '$1$1'); + } + + if (val !== 'transparent' && val.indexOf('#') < 0) { + val = '#' + val; + } + + return val.toLowerCase(); + } +}; +})(Y); + +(function(Y) { +var CLIENT_TOP = 'clientTop', + CLIENT_LEFT = 'clientLeft', + HAS_LAYOUT = 'hasLayout', + PX = 'px', + FILTER = 'filter', + FILTERS = 'filters', + OPACITY = 'opacity', + AUTO = 'auto', + BORDER_TOP_WIDTH = 'borderTopWidth', + BORDER_RIGHT_WIDTH = 'borderRightWidth', + BORDER_BOTTOM_WIDTH = 'borderBottomWidth', + BORDER_LEFT_WIDTH = 'borderLeftWidth', + WIDTH = 'width', + HEIGHT = 'height', + TRANSPARENT = 'transparent', + VISIBLE = 'visible', + GET_COMPUTED_STYLE = 'getComputedStyle', + UNDEFINED = undefined, + documentElement = document.documentElement, + + // TODO: unit-less lineHeight (e.g. 1.22) + re_size = /^width|height$/, + re_unit = /^(\d[.\d]*)+(em|ex|px|gd|rem|vw|vh|vm|ch|mm|cm|in|pt|pc|deg|rad|ms|s|hz|khz|%){1}?/i, + + _getStyleObj = function(node) { + return node.currentStyle || node.style; + }, + + ComputedStyle = { + CUSTOM_STYLES: {}, + + get: function(el, property) { + var value = '', + current; + + if (el) { + current = _getStyleObj(el)[property]; + + if (property === OPACITY) { + value = Y.DOM.CUSTOM_STYLES[OPACITY].get(el); + } else if (!current || (current.indexOf && current.indexOf(PX) > -1)) { // no need to convert + value = current; + } else if (Y.DOM.IE.COMPUTED[property]) { // use compute function + value = Y.DOM.IE.COMPUTED[property](el, property); + } else if (re_unit.test(current)) { // convert to pixel + value = ComputedStyle.getPixel(el, property) + PX; + } else { + value = current; + } + } + + return value; + }, + + getOffset: function(el, prop) { + var current = _getStyleObj(el)[prop], // value of "width", "top", etc. + capped = prop.charAt(0).toUpperCase() + prop.substr(1), // "Width", "Top", etc. + offset = 'offset' + capped, // "offsetWidth", "offsetTop", etc. + pixel = 'pixel' + capped, // "pixelWidth", "pixelTop", etc. + actual, + value = ''; + + if (current === AUTO) { + actual = el[offset]; // offsetHeight/Top etc. + if (actual === UNDEFINED) { // likely "right" or "bottom" + value = 0; + } + + value = actual; + if (re_size.test(prop)) { // account for box model diff + el.style[prop] = actual; + if (el[offset] > actual) { + // the difference is padding + border (works in Standards & Quirks modes) + value = actual - (el[offset] - actual); + } + el.style[prop] = AUTO; // revert to auto + } + } else { // convert units to px + if (current.indexOf('%') > -1) { // IE pixelWidth incorrect for percent; manually compute + current = el.clientWidth - // offsetWidth - borderWidth + ComputedStyle.getPixel(el, 'paddingRight') - + ComputedStyle.getPixel(el, 'paddingLeft'); + } + if (!el.style[pixel] && !el.style[prop]) { // need to map style.width to currentStyle (no currentStyle.pixelWidth) + el.style[prop] = current; // no style.pixelWidth if no style.width + } + value = el.style[pixel]; + } + return value + PX; + }, + + getBorderWidth: function(el, property) { + // clientHeight/Width = paddingBox (e.g. offsetWidth - borderWidth) + // clientTop/Left = borderWidth + var value = null; + if (!el.currentStyle || !el.currentStyle[HAS_LAYOUT]) { // TODO: unset layout? + el.style.zoom = 1; // need layout to measure client + } + + switch(property) { + case BORDER_TOP_WIDTH: + value = el[CLIENT_TOP]; + break; + case BORDER_BOTTOM_WIDTH: + value = el.offsetHeight - el.clientHeight - el[CLIENT_TOP]; + break; + case BORDER_LEFT_WIDTH: + value = el[CLIENT_LEFT]; + break; + case BORDER_RIGHT_WIDTH: + value = el.offsetWidth - el.clientWidth - el[CLIENT_LEFT]; + break; + } + return value + PX; + }, + + getPixel: function(node, att) { + // use pixelRight to convert to px + var val = null, + style = _getStyleObj(node), + styleRight = style.right, + current = style[att]; + + node.style.right = current; + val = node.style.pixelRight; + node.style.right = styleRight; // revert + + return val; + }, + + getMargin: function(node, att) { + var val, + style = _getStyleObj(node); + + if (style[att] == AUTO) { + val = 0; + } else { + val = ComputedStyle.getPixel(node, att); + } + return val + PX; + }, + + getVisibility: function(node, att) { + var current; + while ( (current = node.currentStyle) && current[att] == 'inherit') { // NOTE: assignment in test + node = node.parentNode; + } + return (current) ? current[att] : VISIBLE; + }, + + getColor: function(node, att) { + var current = _getStyleObj(node)[att]; + + if (!current || current === TRANSPARENT) { + Y.DOM.elementByAxis(node, 'parentNode', null, function(parent) { + current = _getStyleObj(parent)[att]; + if (current && current !== TRANSPARENT) { + node = parent; + return true; + } + }); + } + + return Y.Color.toRGB(current); + }, + + getBorderColor: function(node, att) { + var current = _getStyleObj(node), + val = current[att] || current.color; + return Y.Color.toRGB(Y.Color.toHex(val)); + } + }, + + //fontSize: getPixelFont, + IEComputed = {}; + +// use alpha filter for IE opacity +if (documentElement.style[OPACITY] === UNDEFINED && + documentElement[FILTERS]) { + Y.DOM.CUSTOM_STYLES[OPACITY] = { + get: function(node) { + var val = 100; + try { // will error if no DXImageTransform + val = node[FILTERS]['DXImageTransform.Microsoft.Alpha'][OPACITY]; + + } catch(e) { + try { // make sure its in the document + val = node[FILTERS]('alpha')[OPACITY]; + } catch(err) { + Y.log('getStyle: IE opacity filter not found; returning 1', 'warn', 'dom-style'); + } + } + return val / 100; + }, + + set: function(node, val, style) { + var current, + styleObj; + + if (val === '') { // normalize inline style behavior + styleObj = _getStyleObj(node); + current = (OPACITY in styleObj) ? styleObj[OPACITY] : 1; // revert to original opacity + val = current; + } + + if (typeof style[FILTER] == 'string') { // in case not appended + style[FILTER] = 'alpha(' + OPACITY + '=' + val * 100 + ')'; + + if (!node.currentStyle || !node.currentStyle[HAS_LAYOUT]) { + style.zoom = 1; // needs layout + } + } + } + }; +} + +try { + document.createElement('div').style.height = '-1px'; +} catch(e) { // IE throws error on invalid style set; trap common cases + Y.DOM.CUSTOM_STYLES.height = { + set: function(node, val, style) { + if (parseInt(val, 10) >= 0) { + style.height = val; + } else { + Y.log('invalid style value for height: ' + val, 'warn', 'dom-style'); + } + } + }; + + Y.DOM.CUSTOM_STYLES.width = { + set: function(node, val, style) { + if (parseInt(val, 10) >= 0) { + style.width = val; + } else { + Y.log('invalid style value for width: ' + val, 'warn', 'dom-style'); + } + } + }; +} + +// TODO: top, right, bottom, left +IEComputed[WIDTH] = IEComputed[HEIGHT] = ComputedStyle.getOffset; + +IEComputed.color = IEComputed.backgroundColor = ComputedStyle.getColor; + +IEComputed[BORDER_TOP_WIDTH] = IEComputed[BORDER_RIGHT_WIDTH] = + IEComputed[BORDER_BOTTOM_WIDTH] = IEComputed[BORDER_LEFT_WIDTH] = + ComputedStyle.getBorderWidth; + +IEComputed.marginTop = IEComputed.marginRight = IEComputed.marginBottom = + IEComputed.marginLeft = ComputedStyle.getMargin; + +IEComputed.visibility = ComputedStyle.getVisibility; +IEComputed.borderColor = IEComputed.borderTopColor = + IEComputed.borderRightColor = IEComputed.borderBottomColor = + IEComputed.borderLeftColor = ComputedStyle.getBorderColor; + +if (!Y.config.win[GET_COMPUTED_STYLE]) { + Y.DOM[GET_COMPUTED_STYLE] = ComputedStyle.get; +} + +Y.namespace('DOM.IE'); +Y.DOM.IE.COMPUTED = IEComputed; +Y.DOM.IE.ComputedStyle = ComputedStyle; + +})(Y); + + +}, '3.0.0b1' ,{skinnable:false, requires:['dom-base']}); +YUI.add('dom-screen', function(Y) { + +(function(Y) { + +/** + * Adds position and region management functionality to DOM. + * @module dom + * @submodule dom-screen + * @for DOM + */ + +var DOCUMENT_ELEMENT = 'documentElement', + COMPAT_MODE = 'compatMode', + POSITION = 'position', + FIXED = 'fixed', + RELATIVE = 'relative', + LEFT = 'left', + TOP = 'top', + _BACK_COMPAT = 'BackCompat', + MEDIUM = 'medium', + BORDER_LEFT_WIDTH = 'borderLeftWidth', + BORDER_TOP_WIDTH = 'borderTopWidth', + GET_BOUNDING_CLIENT_RECT = 'getBoundingClientRect', + GET_COMPUTED_STYLE = 'getComputedStyle', + + // TODO: how about thead/tbody/tfoot/tr? + // TODO: does caption matter? + RE_TABLE = /^t(?:able|d|h)$/i; + +Y.mix(Y.DOM, { + /** + * Returns the inner height of the viewport (exludes scrollbar). + * @method winHeight + * @return {Number} The current height of the viewport. + */ + winHeight: function(node) { + var h = Y.DOM._getWinSize(node).height; + Y.log('winHeight returning ' + h, 'info', 'dom-screen'); + return h; + }, + + /** + * Returns the inner width of the viewport (exludes scrollbar). + * @method winWidth + * @return {Number} The current width of the viewport. + */ + winWidth: function(node) { + var w = Y.DOM._getWinSize(node).width; + Y.log('winWidth returning ' + w, 'info', 'dom-screen'); + return w; + }, + + /** + * Document height + * @method docHeight + * @return {Number} The current height of the document. + */ + docHeight: function(node) { + var h = Y.DOM._getDocSize(node).height; + Y.log('docHeight returning ' + h, 'info', 'dom-screen'); + return Math.max(h, Y.DOM._getWinSize(node).height); + }, + + /** + * Document width + * @method docWidth + * @return {Number} The current width of the document. + */ + docWidth: function(node) { + var w = Y.DOM._getDocSize(node).width; + Y.log('docWidth returning ' + w, 'info', 'dom-screen'); + return Math.max(w, Y.DOM._getWinSize(node).width); + }, + + /** + * Amount page has been scroll horizontally + * @method docScrollX + * @return {Number} The current amount the screen is scrolled horizontally. + */ + docScrollX: function(node) { + var doc = Y.DOM._getDoc(node); + return Math.max(doc[DOCUMENT_ELEMENT].scrollLeft, doc.body.scrollLeft); + }, + + /** + * Amount page has been scroll vertically + * @method docScrollY + * @return {Number} The current amount the screen is scrolled vertically. + */ + docScrollY: function(node) { + var doc = Y.DOM._getDoc(node); + return Math.max(doc[DOCUMENT_ELEMENT].scrollTop, doc.body.scrollTop); + }, + + /** + * Gets the current position of an element based on page coordinates. + * Element must be part of the DOM tree to have page coordinates + * (display:none or elements not appended return false). + * @method getXY + * @param element The target element + * @return {Array} The XY position of the element + + TODO: test inDocument/display? + */ + getXY: function() { + if (document[DOCUMENT_ELEMENT][GET_BOUNDING_CLIENT_RECT]) { + return function(node) { + var xy = null, + scrollLeft, + scrollTop, + box, + off1, off2, + bLeft, bTop, + mode, + doc; + + if (node) { + if (Y.DOM.inDoc(node)) { + scrollLeft = Y.DOM.docScrollX(node); + scrollTop = Y.DOM.docScrollY(node); + box = node[GET_BOUNDING_CLIENT_RECT](); + doc = Y.DOM._getDoc(node); + xy = [box.left, box.top]; + + if (Y.UA.ie) { + off1 = 2; + off2 = 2; + mode = doc[COMPAT_MODE]; + bLeft = Y.DOM[GET_COMPUTED_STYLE](doc[DOCUMENT_ELEMENT], BORDER_LEFT_WIDTH); + bTop = Y.DOM[GET_COMPUTED_STYLE](doc[DOCUMENT_ELEMENT], BORDER_TOP_WIDTH); + + if (Y.UA.ie === 6) { + if (mode !== _BACK_COMPAT) { + off1 = 0; + off2 = 0; + } + } + + if ((mode == _BACK_COMPAT)) { + if (bLeft !== MEDIUM) { + off1 = parseInt(bLeft, 10); + } + if (bTop !== MEDIUM) { + off2 = parseInt(bTop, 10); + } + } + + xy[0] -= off1; + xy[1] -= off2; + + } + + if ((scrollTop || scrollLeft)) { + xy[0] += scrollLeft; + xy[1] += scrollTop; + } + } else { // default to current offsets + xy = Y.DOM._getOffset(node); + } + } + return xy; + }; + } else { + return function(node) { // manually calculate by crawling up offsetParents + //Calculate the Top and Left border sizes (assumes pixels) + var xy = null, + parentNode, + bCheck, + scrollTop, + scrollLeft; + + if (node) { + if (Y.DOM.inDoc(node)) { + xy = [node.offsetLeft, node.offsetTop]; + parentNode = node; + // TODO: refactor with !! or just falsey + bCheck = ((Y.UA.gecko || Y.UA.webkit > 519) ? true : false); + + // TODO: worth refactoring for TOP/LEFT only? + while ((parentNode = parentNode.offsetParent)) { + xy[0] += parentNode.offsetLeft; + xy[1] += parentNode.offsetTop; + if (bCheck) { + xy = Y.DOM._calcBorders(parentNode, xy); + } + } + + // account for any scrolled ancestors + if (Y.DOM.getStyle(node, POSITION) != FIXED) { + parentNode = node; + + while ((parentNode = parentNode.parentNode)) { + scrollTop = parentNode.scrollTop; + scrollLeft = parentNode.scrollLeft; + + //Firefox does something funky with borders when overflow is not visible. + if (Y.UA.gecko && (Y.DOM.getStyle(parentNode, 'overflow') !== 'visible')) { + xy = Y.DOM._calcBorders(parentNode, xy); + } + + + if (scrollTop || scrollLeft) { + xy[0] -= scrollLeft; + xy[1] -= scrollTop; + } + } + xy[0] += Y.DOM.docScrollX(node); + xy[1] += Y.DOM.docScrollY(node); + + } else { + //Fix FIXED position -- add scrollbars + xy[0] += Y.DOM.docScrollX(node); + xy[1] += Y.DOM.docScrollY(node); + } + } else { + xy = Y.DOM._getOffset(node); + } + } + + return xy; + }; + } + }(),// NOTE: Executing for loadtime branching + + _getOffset: function(node) { + var pos, + xy = null; + + if (node) { + pos = Y.DOM.getStyle(node, POSITION); + xy = [ + parseInt(Y.DOM[GET_COMPUTED_STYLE](node, LEFT), 10), + parseInt(Y.DOM[GET_COMPUTED_STYLE](node, TOP), 10) + ]; + + if ( isNaN(xy[0]) ) { // in case of 'auto' + xy[0] = parseInt(Y.DOM.getStyle(node, LEFT), 10); // try inline + if ( isNaN(xy[0]) ) { // default to offset value + xy[0] = (pos === RELATIVE) ? 0 : node.offsetLeft || 0; + } + } + + if ( isNaN(xy[1]) ) { // in case of 'auto' + xy[1] = parseInt(Y.DOM.getStyle(node, TOP), 10); // try inline + if ( isNaN(xy[1]) ) { // default to offset value + xy[1] = (pos === RELATIVE) ? 0 : node.offsetTop || 0; + } + } + } + + return xy; + + }, + + /** + * Gets the current X position of an element based on page coordinates. + * Element must be part of the DOM tree to have page coordinates + * (display:none or elements not appended return false). + * @method getX + * @param element The target element + * @return {Int} The X position of the element + */ + + getX: function(node) { + return Y.DOM.getXY(node)[0]; + }, + + /** + * Gets the current Y position of an element based on page coordinates. + * Element must be part of the DOM tree to have page coordinates + * (display:none or elements not appended return false). + * @method getY + * @param element The target element + * @return {Int} The Y position of the element + */ + + getY: function(node) { + return Y.DOM.getXY(node)[1]; + }, + + /** + * Set the position of an html element in page coordinates. + * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false). + * @method setXY + * @param element The target element + * @param {Array} xy Contains X & Y values for new position (coordinates are page-based) + * @param {Boolean} noRetry By default we try and set the position a second time if the first fails + */ + setXY: function(node, xy, noRetry) { + var setStyle = Y.DOM.setStyle, + pos, + delta, + newXY, + currentXY; + + if (node && xy) { + pos = Y.DOM.getStyle(node, POSITION); + + delta = Y.DOM._getOffset(node); + + if (pos == 'static') { // default to relative + pos = RELATIVE; + setStyle(node, POSITION, pos); + } + + currentXY = Y.DOM.getXY(node); + + if (xy[0] !== null) { + setStyle(node, LEFT, xy[0] - currentXY[0] + delta[0] + 'px'); + } + + if (xy[1] !== null) { + setStyle(node, TOP, xy[1] - currentXY[1] + delta[1] + 'px'); + } + + if (!noRetry) { + newXY = Y.DOM.getXY(node); + if (newXY[0] !== xy[0] || newXY[1] !== xy[1]) { + Y.DOM.setXY(node, xy, true); + } + } + + Y.log('setXY setting position to ' + xy, 'info', 'dom-screen'); + } else { + Y.log('setXY failed to set ' + node + ' to ' + xy, 'info', 'dom-screen'); + } + }, + + /** + * Set the X position of an html element in page coordinates, regardless of how the element is positioned. + * The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false). + * @method setX + * @param element The target element + * @param {Int} x The X values for new position (coordinates are page-based) + */ + setX: function(node, x) { + return Y.DOM.setXY(node, [x, null]); + }, + + /** + * Set the Y position of an html element in page coordinates, regardless of how the element is positioned. + * The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false). + * @method setY + * @param element The target element + * @param {Int} y The Y values for new position (coordinates are page-based) + */ + setY: function(node, y) { + return Y.DOM.setXY(node, [null, y]); + }, + + _calcBorders: function(node, xy2) { + var t = parseInt(Y.DOM[GET_COMPUTED_STYLE](node, BORDER_TOP_WIDTH), 10) || 0, + l = parseInt(Y.DOM[GET_COMPUTED_STYLE](node, BORDER_LEFT_WIDTH), 10) || 0; + if (Y.UA.gecko) { + if (RE_TABLE.test(node.tagName)) { + t = 0; + l = 0; + } + } + xy2[0] += l; + xy2[1] += t; + return xy2; + }, + + _getWinSize: function(node) { + var doc = Y.DOM._getDoc(), + win = doc.defaultView || doc.parentWindow, + mode = doc[COMPAT_MODE], + h = win.innerHeight, + w = win.innerWidth, + root = doc[DOCUMENT_ELEMENT]; + + if ( mode && !Y.UA.opera ) { // IE, Gecko + if (mode != 'CSS1Compat') { // Quirks + root = doc.body; + } + h = root.clientHeight; + w = root.clientWidth; + } + return { height: h, width: w }; + }, + + _getDocSize: function(node) { + var doc = Y.DOM._getDoc(), + root = doc[DOCUMENT_ELEMENT]; + + if (doc[COMPAT_MODE] != 'CSS1Compat') { + root = doc.body; + } + + return { height: root.scrollHeight, width: root.scrollWidth }; + } +}); +})(Y); +(function(Y) { +var TOP = 'top', + RIGHT = 'right', + BOTTOM = 'bottom', + LEFT = 'left', + + getOffsets = function(r1, r2) { + var t = Math.max(r1[TOP], r2[TOP]), + r = Math.min(r1[RIGHT], r2[RIGHT]), + b = Math.min(r1[BOTTOM], r2[BOTTOM]), + l = Math.max(r1[LEFT], r2[LEFT]), + ret = {}; + + ret[TOP] = t; + ret[RIGHT] = r; + ret[BOTTOM] = b; + ret[LEFT] = l; + return ret; + }, + + DOM = Y.DOM; + +Y.mix(DOM, { + /** + * Returns an Object literal containing the following about this element: (top, right, bottom, left) + * @method region + * @param {HTMLElement} element The DOM element. + @return {Object} Object literal containing the following about this element: (top, right, bottom, left) + */ + region: function(node) { + var xy = DOM.getXY(node), + ret = false; + + if (node && xy) { + ret = DOM._getRegion( + xy[1], // top + xy[0] + node.offsetWidth, // right + xy[1] + node.offsetHeight, // bottom + xy[0] // left + ); + } + + return ret; + }, + + /** + * Find the intersect information for the passes nodes. + * @method intersect + * @param {HTMLElement} element The first element + * @param {HTMLElement | Object} element2 The element or region to check the interect with + * @param {Object} altRegion An object literal containing the region for the first element if we already have the data (for performance i.e. DragDrop) + @return {Object} Object literal containing the following intersection data: (top, right, bottom, left, area, yoff, xoff, inRegion) + */ + intersect: function(node, node2, altRegion) { + var r = altRegion || DOM.region(node), region = {}, + n = node2, + off; + + if (n.tagName) { + region = DOM.region(n); + } else if (Y.Lang.isObject(node2)) { + region = node2; + } else { + return false; + } + + off = getOffsets(region, r); + return { + top: off[TOP], + right: off[RIGHT], + bottom: off[BOTTOM], + left: off[LEFT], + area: ((off[BOTTOM] - off[TOP]) * (off[RIGHT] - off[LEFT])), + yoff: ((off[BOTTOM] - off[TOP])), + xoff: (off[RIGHT] - off[LEFT]), + inRegion: DOM.inRegion(node, node2, false, altRegion) + }; + + }, + /** + * Check if any part of this node is in the passed region + * @method inRegion + * @param {Object} node2 The node to get the region from or an Object literal of the region + * $param {Boolean} all Should all of the node be inside the region + * @param {Object} altRegion An object literal containing the region for this node if we already have the data (for performance i.e. DragDrop) + * @return {Boolean} True if in region, false if not. + */ + inRegion: function(node, node2, all, altRegion) { + var region = {}, + r = altRegion || DOM.region(node), + n = node2, + off; + + if (n.tagName) { + region = DOM.region(n); + } else if (Y.Lang.isObject(node2)) { + region = node2; + } else { + return false; + } + + if (all) { + return ( + r[LEFT] >= region[LEFT] && + r[RIGHT] <= region[RIGHT] && + r[TOP] >= region[TOP] && + r[BOTTOM] <= region[BOTTOM] ); + } else { + off = getOffsets(region, r); + if (off[BOTTOM] >= off[TOP] && off[RIGHT] >= off[LEFT]) { + return true; + } else { + return false; + } + + } + }, + + /** + * Check if any part of this element is in the viewport + * @method inViewportRegion + * @param {HTMLElement} element The DOM element. + * @param {Boolean} all Should all of the node be inside the region + * @param {Object} altRegion An object literal containing the region for this node if we already have the data (for performance i.e. DragDrop) + * @return {Boolean} True if in region, false if not. + */ + inViewportRegion: function(node, all, altRegion) { + return DOM.inRegion(node, DOM.viewportRegion(node), all, altRegion); + + }, + + _getRegion: function(t, r, b, l) { + var region = {}; + + region[TOP] = region[1] = t; + region[LEFT] = region[0] = l; + region[BOTTOM] = b; + region[RIGHT] = r; + region.width = region[RIGHT] - region[LEFT]; + region.height = region[BOTTOM] - region[TOP]; + + return region; + }, + + /** + * Returns an Object literal containing the following about the visible region of viewport: (top, right, bottom, left) + * @method viewportRegion + @return {Object} Object literal containing the following about the visible region of the viewport: (top, right, bottom, left) + */ + viewportRegion: function(node) { + node = node || Y.config.doc.documentElement; + var ret = false, + scrollX, + scrollY; + + if (node) { + scrollX = DOM.docScrollX(node); + scrollY = DOM.docScrollY(node); + + ret = DOM._getRegion(scrollY, // top + DOM.winWidth(node) + scrollX, // right + scrollY + DOM.winHeight(node), // bottom + scrollX); // left + } + + return ret; + } +}); +})(Y); + + +}, '3.0.0b1' ,{requires:['dom-base', 'dom-style'], skinnable:false}); +YUI.add('selector-native', function(Y) { + +(function(Y) { +/** + * The selector-native module provides support for native querySelector + * @module dom + * @submodule selector-native + * @for Selector + */ + +/** + * Provides support for using CSS selectors to query the DOM + * @class Selector + * @static + * @for Selector + */ + +Y.namespace('Selector'); // allow native module to standalone + +var NativeSelector = { + _reLead: /^\s*([>+~]|:self)/, + _reUnSupported: /!./, + + _foundCache: [], + + _supportsNative: function() { + // whitelist and feature detection to manage + // future implementations manually + return ( (Y.UA.ie >= 8 || Y.UA.webkit > 525) && + document.querySelectorAll); + }, + + _toArray: function(nodes) { // TODO: move to Y.Array + var ret = nodes, + i, len; + + if (!nodes.slice) { + try { + ret = Array.prototype.slice.call(nodes); + } catch(e) { // IE: requires manual copy + ret = []; + for (i = 0, len = nodes.length; i < len; ++i) { + ret[i] = nodes[i]; + } + } + } + return ret; + }, + + _clearFoundCache: function() { + var foundCache = NativeSelector._foundCache, + i, len; + + for (i = 0, len = foundCache.length; i < len; ++i) { + try { // IE no like delete + delete foundCache[i]._found; + } catch(e) { + foundCache[i].removeAttribute('_found'); + } + } + foundCache = []; + }, + + _sort: function(nodes) { + if (nodes) { + nodes = NativeSelector._toArray(nodes); + if (nodes.sort) { + nodes.sort(function(a, b) { + return Y.DOM.srcIndex(a) - Y.DOM.srcIndex(b); + }); + } + } + + return nodes; + }, + + _deDupe: function(nodes) { + var ret = [], + cache = NativeSelector._foundCache, + i, node; + + for (i = 0, node; node = nodes[i++];) { + if (!node._found) { + ret[ret.length] = cache[cache.length] = node; + node._found = true; + } + } + NativeSelector._clearFoundCache(); + return ret; + }, + + // allows element scoped queries to begin with combinator + // e.g. query('> p', document.body) === query('body > p') + _prepQuery: function(root, selector) { + var groups = selector.split(','), + queries = [], + isDocRoot = (root && root.nodeType === 9), + i, len; + + if (root) { + if (!isDocRoot) { + root.id = root.id || Y.guid(); + // break into separate queries for element scoping + for (i = 0, len = groups.length; i < len; ++i) { + selector = '#' + root.id + ' ' + groups[i]; // prepend with root ID + queries.push({root: root.ownerDocument, selector: selector}); + } + } else { + queries.push({root: root, selector: selector}); + } + } + + return queries; + }, + + _query: function(selector, root, firstOnly) { + if (NativeSelector._reUnSupported.test(selector)) { + return Y.Selector._brute.query(selector, root, firstOnly); + } + + var ret = firstOnly ? null : [], + queryName = firstOnly ? 'querySelector' : 'querySelectorAll', + result, + queries, + i, query; + + root = root || Y.config.doc; + + if (selector) { + queries = NativeSelector._prepQuery(root, selector); + ret = []; + + for (i = 0, query; query = queries[i++];) { + try { + result = query.root[queryName](query.selector); + if (queryName === 'querySelectorAll') { // convert NodeList to Array + result = NativeSelector._toArray(result); + } + ret = ret.concat(result); + } catch(e) { + Y.log('native selector error: ' + e, 'error', 'Selector'); + } + } + + if (queries.length > 1) { // remove dupes and sort by doc order + ret = NativeSelector._sort(NativeSelector._deDupe(ret)); + } + ret = (!firstOnly) ? ret : ret[0] || null; + } + return ret; + }, + + _filter: function(nodes, selector) { + var ret = [], + i, node; + + if (nodes && selector) { + for (i = 0, node; (node = nodes[i++]);) { + if (Y.Selector._test(node, selector)) { + ret[ret.length] = node; + } + } + } else { + Y.log('invalid filter input (nodes: ' + nodes + + ', selector: ' + selector + ')', 'warn', 'Selector'); + } + + return ret; + }, + + _test: function(node, selector) { + var ret = false, + groups = selector.split(','), + item, + i, group; + + if (node && node.tagName) { // only test HTMLElements + node.id = node.id || Y.guid(); + for (i = 0, group; group = groups[i++];) { + group += '#' + node.id; // add ID for uniqueness + item = Y.Selector.query(group, null, true); + ret = (item === node); + if (ret) { + break; + } + } + } + + return ret; + } +}; + +if (Y.UA.ie && Y.UA.ie <= 8) { + NativeSelector._reUnSupported = /:(?:nth|not|root|only|checked|first|last|empty)/; +} + + + +Y.mix(Y.Selector, NativeSelector, true); + +// allow standalone selector-native module +if (NativeSelector._supportsNative()) { + Y.Selector.query = NativeSelector._query; + //Y.Selector.filter = NativeSelector._filter; + //Y.Selector.test = NativeSelector._test; +} +Y.Selector.test = NativeSelector._test; +Y.Selector.filter = NativeSelector._filter; + +})(Y); + + +}, '3.0.0b1' ,{requires:['dom-base'], skinnable:false}); +YUI.add('selector-css2', function(Y) { + +/** + * The selector module provides helper methods allowing CSS2 Selectors to be used with DOM elements. + * @module dom + * @submodule selector-css2 + * @for Selector + */ + +/** + * Provides helper methods for collecting and filtering DOM elements. + */ + +var PARENT_NODE = 'parentNode', + TAG_NAME = 'tagName', + ATTRIBUTES = 'attributes', + COMBINATOR = 'combinator', + PSEUDOS = 'pseudos', + PREVIOUS = 'previous', + PREVIOUS_SIBLING = 'previousSibling', + + _childCache = [], // cache to cleanup expando node.children + + Selector = Y.Selector, + + SelectorCSS2 = { + SORT_RESULTS: true, + _children: function(node) { + var ret = node.children, + i, n; + + if (!ret && node[TAG_NAME]) { // only HTMLElements have children + ret = []; + for (i = 0, n; n = node.childNodes[i++];) { + if (n.tagName) { + ret[ret.length] = n; + } + } + _childCache[_childCache.length] = node; + node.children = ret; + } + + return ret || []; + }, + + _regexCache: {}, + + _re: { + attr: /(\[.*\])/g, + urls: /^(?:href|src)/ + }, + + /** + * Mapping of shorthand tokens to corresponding attribute selector + * @property shorthand + * @type object + */ + shorthand: { + '\\#(-?[_a-z]+[-\\w]*)': '[id=$1]', + '\\.(-?[_a-z]+[-\\w]*)': '[className~=$1]' + }, + + /** + * List of operators and corresponding boolean functions. + * These functions are passed the attribute and the current node's value of the attribute. + * @property operators + * @type object + */ + operators: { + '': function(node, m) { return Y.DOM.getAttribute(node, m[0]) !== ''; }, // Just test for existence of attribute + //'': '.+', + '=': '^{val}$', // equality + '~=': '(?:^|\\s+){val}(?:\\s+|$)', // space-delimited + '|=': '^{val}-?' // optional hyphen-delimited + }, + + pseudos: { + 'first-child': function(node) { + return Y.Selector._children(node[PARENT_NODE])[0] === node; + } + }, + + _brute: { + /** + * Retrieves a set of nodes based on a given CSS selector. + * @method query + * + * @param {string} selector The CSS Selector to test the node against. + * @param {HTMLElement} root optional An HTMLElement to start the query from. Defaults to Y.config.doc + * @param {Boolean} firstOnly optional Whether or not to return only the first match. + * @return {Array} An array of nodes that match the given selector. + * @static + */ + query: function(selector, root, firstOnly) { + var ret = []; + if (selector) { + ret = Selector._query(selector, root, firstOnly); + } + + Y.log('query: ' + selector + ' returning: ' + ret.length, 'info', 'Selector'); + Selector._cleanup(); + return (firstOnly) ? (ret[0] || null) : ret; + } + + }, + + // TODO: make extensible? events? + _cleanup: function() { + for (var i = 0, node; node = _childCache[i++];) { + delete node.children; + } + + _childCache = []; + }, + + _query: function(selector, root, firstOnly, deDupe) { + var ret = [], + groups = selector.split(','), // TODO: handle comma in attribute/pseudo + nodes = [], + tokens, + token, + i, len; + + if (groups.length > 1) { + for (i = 0, len = groups.length; i < len; ++i) { + ret = ret.concat(arguments.callee(groups[i], + root, firstOnly, true)); + } + + ret = Selector.SORT_RESULTS ? Selector._sort(ret) : ret; + Selector._clearFoundCache(); + } else { + root = root || Y.config.doc; + + if (root.nodeType !== 9) { // enforce element scope + if (!root.id) { + root.id = Y.guid(); + } + // fast-path ID when possible + if (root.ownerDocument.getElementById(root.id)) { + selector = '#' + root.id + ' ' + selector; + root = root.ownerDocument; + + } + } + + tokens = Selector._tokenize(selector, root); + token = tokens.pop(); + + if (token) { + if (deDupe) { + token.deDupe = true; // TODO: better approach? + } + if (tokens[0] && tokens[0].id && root.nodeType === 9 && root.getElementById(tokens[0].id)) { + root = root.getElementById(tokens[0].id); + } + + // TODO: no prefilter for off-dom id + if (root && !nodes.length && token.prefilter) { + nodes = token.prefilter(root, token); + } + + if (nodes.length) { + if (firstOnly) { + Y.Array.some(nodes, Selector._testToken, token); + } else { + Y.Array.each(nodes, Selector._testToken, token); + } + } + ret = token.result; + } + } + + return ret; + }, + + _testToken: function(node, index, nodes, token) { + token = token || this; + var tag = token.tag, + previous = token[PREVIOUS], + result = token.result, + i = 0, + nextTest = previous && previous[COMBINATOR] ? + Selector.combinators[previous[COMBINATOR]] : + null, + test, + attr; + + if (//node[TAG_NAME] && // tagName limits to HTMLElements + (tag === '*' || tag === node[TAG_NAME]) && + !(token.last && node._found) ) { + while ((attr = token.tests[i])) { + i++; + test = attr.test; + if (test.test) { + if (!test.test(Y.DOM.getAttribute(node, attr.name))) { + return false; + } + } else if (!test(node, attr.match)) { + return false; + } + } + + if (nextTest && !nextTest(node, token)) { + return false; + } + + if (token.root && token.root.nodeType !== 9 && !Y.DOM.contains(token.root, node)) { + return false; + } + + result[result.length] = node; + if (token.deDupe && token.last) { + node._found = true; + Selector._foundCache.push(node); + } + return true; + } + return false; + }, + + + _getRegExp: function(str, flags) { + var regexCache = Selector._regexCache; + flags = flags || ''; + if (!regexCache[str + flags]) { + regexCache[str + flags] = new RegExp(str, flags); + } + return regexCache[str + flags]; + }, + + combinators: { + ' ': function(node, token) { + var test = Selector._testToken, + previous = token[PREVIOUS]; + while ( (node = node[PARENT_NODE]) ) { + if (test(node, null, null, previous)) { + return true; + } + } + return false; + }, + + '>': function(node, token) { + return Selector._testToken(node[PARENT_NODE], null, null, token[PREVIOUS]); + }, + + + '+': function(node, token) { + var sib = node[PREVIOUS_SIBLING]; + while (sib && sib.nodeType !== 1) { + sib = sib[PREVIOUS_SIBLING]; + } + + if (sib && Y.Selector._testToken(sib, null, null, token[PREVIOUS])) { + return true; + } + return false; + } + + }, + + _parsers: [ + { + name: TAG_NAME, + re: /^((?:-?[_a-z]+[\w-]*)|\*)/i, + fn: function(token, match) { + token.tag = match[1].toUpperCase(); + token.prefilter = function(root) { + return root.getElementsByTagName(token.tag); + }; + return true; + } + }, + { + name: ATTRIBUTES, + re: /^\[([a-z]+\w*)+([~\|\^\$\*!=]=?)?['"]?([^\]]*?)['"]?\]/i, + fn: function(token, match) { + var val = match[3], + operator = !(match[2] && val) ? '' : match[2], + test = Selector.operators[operator]; + + // might be a function + if (typeof test === 'string') { + test = Selector._getRegExp(test.replace('{val}', val)); + } + + if (match[1] === 'id' && val) { // store ID for fast-path match + token.id = val; + token.prefilter = function(root) { + var doc = root.nodeType === 9 ? root : root.ownerDocument, + node = doc.getElementById(val); + + return node ? [node] : []; + }; + } else if (document.documentElement.getElementsByClassName && + match[1].indexOf('class') === 0) { + if (!token.prefilter) { + token.prefilter = function(root) { + return root.getElementsByClassName(val); + }; + test = true; // skip class test + } + } + return test; + + } + + }, + { + name: COMBINATOR, + re: /^\s*([>+~]|\s)\s*/, + fn: function(token, match) { + token[COMBINATOR] = match[1]; + return !! Selector.combinators[token[COMBINATOR]]; + } + }, + { + name: PSEUDOS, + re: /^:([\-\w]+)(?:\(['"]?(.+)['"]?\))*/i, + fn: function(token, match) { + return Selector[PSEUDOS][match[1]]; + + } + } + ], + + _getToken: function(token) { + return { + previous: token, + combinator: ' ', + tag: '*', + prefilter: function(root) { + return root.getElementsByTagName('*'); + }, + tests: [], + result: [] + }; + }, + + /** + Break selector into token units per simple selector. + Combinator is attached to the previous token. + */ + _tokenize: function(selector, root) { + selector = selector || ''; + selector = Selector._replaceShorthand(Y.Lang.trim(selector)); + var token = Selector._getToken(), // one token per simple selector (left selector holds combinator) + query = selector, // original query for debug report + tokens = [], // array of tokens + found = false, // whether or not any matches were found this pass + test, + match, // the regex match + i, parser; + + /* + Search for selector patterns, store, and strip them from the selector string + until no patterns match (invalid selector) or we run out of chars. + + Multiple attributes and pseudos are allowed, in any order. + for example: + 'form:first-child[type=button]:not(button)[lang|=en]' + */ + outer: + do { + found = false; // reset after full pass + for (i = 0, parser; parser = Selector._parsers[i++];) { + if ( (match = parser.re.exec(selector)) ) { // note assignment + test = parser.fn(token, match); + if (test) { + if (test !== true) { // auto-pass + token.tests.push({ + name: match[1], + test: test, + match: match.slice(1) + }); + } + + found = true; + selector = selector.replace(match[0], ''); // strip current match from selector + if (!selector.length || parser.name === COMBINATOR) { + token.root = root; + tokens.push(token); + token = Selector._getToken(token); + } + } else { + found = false; + break outer; + } + } + } + } while (found && selector.length); + + if (!found || selector.length) { // not fully parsed + Y.log('query: ' + query + ' contains unsupported token in: ' + selector, 'warn', 'Selector'); + tokens = []; + } else if (tokens.length) { + tokens[tokens.length - 1].last = true; + } + return tokens; + }, + + _replaceShorthand: function(selector) { + var shorthand = Selector.shorthand, + attrs = selector.match(Selector._re.attr), // pull attributes to avoid false pos on "." and "#" + re, i, len; + + if (attrs) { + selector = selector.replace(Selector._re.attr, 'REPLACED_ATTRIBUTE'); + } + + for (re in shorthand) { + if (shorthand.hasOwnProperty(re)) { + selector = selector.replace(Selector._getRegExp(re, 'gi'), shorthand[re]); + } + } + + if (attrs) { + for (i = 0, len = attrs.length; i < len; ++i) { + selector = selector.replace('REPLACED_ATTRIBUTE', attrs[i]); + } + } + return selector; + } + }; + +Y.mix(Y.Selector, SelectorCSS2, true); + +// only override native when not supported +if (!Y.Selector._supportsNative()) { + Y.Selector.query = Selector._brute.query; +} + + +}, '3.0.0b1' ,{requires:['dom-base', 'selector-native'], skinnable:false}); + + +YUI.add('dom', function(Y){}, '3.0.0b1' ,{skinnable:false, use:['dom-base', 'dom-style', 'dom-screen', 'selector-native', 'selector-css2']}); +