DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

SimpleSelector, Javascript DOM Selector

03.30.2010
| 3692 views |
  • submit to reddit
        SimpleSelector is a small DOM selector object with support for the most used selectors. It's also the default selector for the jLim JavaScript framework.

Why use SimpleSelector?
- very small, less than 2kb minified
- easy to use with $$()
- no overhead, no functions you hardly ever use
- ideal for smaller websites

/*!
 * $imple$elector
 *
 * Selector by id, className or tagName, f.e.:
 * $$( '#wrap' ) or $$( '.special' ) or $$( 'p' )
 *
 * Multiple selectors separated by comma, f.e.:
 * $$( '#id, .cls' )
 *
 * Give context as second param, f.e.:
 * $$( 'a', '#wrap' ) or $$( 'a', wrapNode ) or $$( 'a', [node1, node2] )
 *
 * @version   0.2
 * @author    Victor Villaverde Laan
 * @link      http://www.freelancephp.net/simpleselector-javascript-dom-selector/
 * @license   MIT license
 */
var SimpleSelector = {

	/**
	 * Find elements with the given selector within the context
	 * @param selector [string]
	 * @param context  [string | DOM node | array of DOM nodes]
	 * @return [DOM node | array of DOM nodes | empty array]
	 */
	find: function ( selector, context ) {
		var selectors = selector.split( ',' ),
			elements = [],
			wrappers = [];

		// set wrappers
		if ( typeof context == 'string' ) {
			var wraps = SimpleSelector.find( context );
			// set array to wrappers
			wrappers = ( wraps.constructor == Array ) ? wraps : [ wraps ];
		} else if ( context && context.constructor == Array ) {
			wrappers = context;
		} else {
			// document is default context
			wrappers.push( context || document );
		}

		// find matching elements within the wrappers (context)
		for ( var a = 0, b = wrappers.length; a < b; a++ ) {
			for ( var x = 0, y = selectors.length; x < y; x++ ) {
				// selector: trim spaces
				var s = selectors[x].replace( / /g, '' ),
					// get operator
					operator = s.substr( 0, 1 ),
					// get key
					key = s.substr( 1 ),
					els = [];

				// get matching elements
				if ( operator == '#' ) {
					// get element by id
					els[0] = document.getElementById( key );
					// check if element is part of context
					if ( els[0] && SimpleSelector.isDescendant( els[0], wrappers[ a ] ) )
						elements.push( els[0] );
				} else if ( operator == '.' ) {
					// get element by className
					els = SimpleSelector.getByClass( key, wrappers[ a ] );
					// convert type to array
					els = [].slice.call( els, 0 );
					// add to elements collection
					elements = elements.concat( els );
				} else {
					// get element by tagName
					els = wrappers[ a ].getElementsByTagName( s );
					// add to elements collection
					// in this case [].slice.call( els, 0 ) does not work
					// in IE, says constructor is undefined??
					for ( var i = 0, j = els.length; i < j; i++ )
						elements.push( els[ i ] );
				}
			}
		}

		// return single element or array of elements
		return ( elements.length == 1 ) ? elements[0] : elements;
	},

	/**
	 * Check wether an element is a descendant of the given ancestor
	 * @param descendant [DOM node]
	 * @param ancestor   [DOM node]
	 * @return [boolean]
	 */
	isDescendant: function ( descendant, ancestor ) {
		return ( ( descendant.parentNode == ancestor )
					|| ( descendant.parentNode != document )
				&& arguments.callee( descendant.parentNode, ancestor ) );
	},

	/**
	 * Cross browser function for getting elements by className
	 * @param className [string]
	 * @param context   [DOM node]
	 * @return [array of DOM nodes]
	 */
	getByClass: function ( className, context ) {
		var elements = [],
			expr = new RegExp('\\b' + className + '\\b'),
			wrapper = context || document,
			allElements = wrapper.getElementsByTagName( '*' );

		// filter all elements that contain the given className
		for ( var x = 0, y = allElements.length; x < y; x++ ) {
			if ( expr.test( allElements[ x ].className ) )
				elements.push( allElements[ x ] );
		}

		return elements;
	}

};

// if global $$ is not set
if ( ! window.$$ )
	window.$$ = SimpleSelector.find;