diff -r 000000000000 -r 40c8f766c9b8 src/cm/media/js/lib/yui/yui_3.0.0b1/api/selector-css2.js.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cm/media/js/lib/yui/yui_3.0.0b1/api/selector-css2.js.html Mon Nov 23 15:14:29 2009 +0100 @@ -0,0 +1,573 @@ + + +
+ +/**
+ * 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;
+}
+