Source: core/DOMCollection.js

/**
 * DOMCollection
 * 
 * @namespace core
 * @author Georgi Popov
 * @version 1.0.0
 * @license http://www.gnu.org/licenses/gpl-3.0.en.html GPLv3
 * @requires com/magadanski/core/core.js
 */

define('com.magadanski.core.DOMCollection', function () {
	var that;
	
	// private properties
	var selection = null;
	var callFunction = 'querySelectorAll';
	
	// private methods
	
	/**
	 * Wrapper that holds a collection of DOM elements and allows for easy group modifications to each of them
	 * 
	 * @class DOMCollection
	 * @since 1.0.0
	 * @param {string} selector A CSS selector to be used to fetch elements
	 * @param {?DOMNode} context The context in which the CSS selector will be used. If empty then document will be used a context. If some DOMNode element is passed, the collection will load only elements within that context that match the selector
	 */
	var DOMCollection = function (selector, context) {
		that = this;
		
		// priviledged properties
		/**
		 * A list of the DOMNode elements that fall within the collection
		 * 
		 * @access public
		 * @instance
		 * @member {Array} elements
		 * @memberOf DOMCollection
		 */
		that.elements = [];
		
		// priviledged methods
		
		// constructor
		if (context instanceof HTMLElement) {
			// all OK -- no need to do anything
		} else if (context instanceof DOMCollection) {
			callFunction = 'find';
		} else {
			context = document;
		}
		
		if (typeof(selector) == 'string') {
			selection = context[callFunction](selector);
		} else if (typeof(selector) == 'object') { // support to pass a result of querySelectorAll or similar
			selection = selector;
		} else {
			selection = false;
		}
		
		if (!!selection) {
			for (var i = 0; i < selection.length; i++) {
				that.elements.push(selection.item(i));
			}
		}
	}
	com.magadanski.core.DOMCollection = DOMCollection;
	
	// public methods
	/**
	 * Adds event listener to all DOMNode elements within the collection
	 * 
	 * @access public
	 * @instance
	 * @method addEventListener
	 * @memberof DOMCollection
	 * @param {eventType} eventType The type of the event to listen for
	 * @param {function(event:Event)} callback The function to be executed when the event occurs
	 * @return {void}
	 */
	DOMCollection.prototype.addEventListener = function (eventType, callback) {
		this.elements.map(function (el) {
			el.addEventListener(eventType, callback);
		});
	}
	
	/**
	 * Remves a previously assigned event listener to all of the elements from the collection. The same reference to the callback function must be provided, otherwise the method will not work.
	 * 
	 * @access public
	 * @instance
	 * @method removeEventListener
	 * @memberof DOMCollection
	 * @param  {string} eventType The type of the event to remove listener for
	 * @param  {function(event:Event)} callback The function to be removed as handler
	 * @return {void}
	 */
	DOMCollection.prototype.removeEventListener = function (eventType, callback) {
		this.elements.map(function (el) {
			el.removeEventListener(eventType, callback);
		});
	}
	
	/**
	 * Adds a CSS class to all elements from the collection
	 * 
	 * @access public
	 * @instance
	 * @method addClass
	 * @memberof DOMCollection
	 * @param {string} className The CSS class to be applied
	 * @return {void}
	 */
	DOMCollection.prototype.addClass = function (className) {
		this.elements.map(function (el) {
			el.classList.add(className);
		});
	}
	
	/**
	 * Removes a CSS class from all elements from the collection
	 * 
	 * @access public
	 * @instance
	 * @method removeClass
	 * @memberof DOMCollection
	 * @param  {string} className The CSS class to be removed
	 * @return {void}
	 */
	DOMCollection.prototype.removeClass = function (className) {
		this.elements.map(function (el) {
			el.classList.remove(className);
		});
	}
	
	/**
	 * Executes a function for all elements from the collection
	 * 
	 * @acces public
	 * @instance
	 * @method each
	 * @memberof DOMCollection
	 * @param  {function(element:DOMElement, i:int)} callback The function to be executed for each of the elements
	 * @return {void}
	 */
	DOMCollection.prototype.each = function (callback) {
		this.elements.map(function (el, i) {
			callback(el, i);
		});
	}
	
	/**
	 * Applies CSS styles to all elements from the collection
	 * 
	 * @access public
	 * @instance
	 * @method css
	 * @memberof DOMCollection
	 * @param  {object} styles An object representation of the CSS styles to be applied to the elements from the collection
	 * @return {void}
	 */
	DOMCollection.prototype.css = function (styles) {
		this.elements.map(function (el) {
			for (att in styles) {
				el.style[att] = styles[att];
			}
		});
	}
	
	/**
	 * Filters elements from the collection, so only ones that meet a provided CSS selector remain
	 * 
	 * @access public
	 * @instance
	 * @method filter
	 * @memberof DOMCollection
	 * @param  {string} selector CSS selector to test the elements against
	 * @return {DOMCollection}
	 */
	DOMCollection.prototype.filter = function (selector) {
		var filteredElements = new DOMCollection();
		
		this.elements.map(function (el) {
			if (el.matches(selector)) {
				filteredElements.elements.push(el);
			}
		});
		
		return filteredElements;
	}
	
	/**
	 * Finds child elements to the ones from the collection that match a specific CSS selector
	 * 
	 * @access public
	 * @instance
	 * @method find
	 * @memberof DOMCollection
	 * @param  {string} selector CSS selector to describe desired child elements
	 * @return {DOMCollection}
	 */
	DOMCollection.prototype.find = function (selector) {
		var foundElements = new DOMCollection();
		
		this.elements.map(function (el) {
			var subset = new DOMCollection(selector, el);
			foundElements.elements = foundElements.elements.concat(subset.elements);
		});
		
		return foundElements;
	}
	
	/**
	 * Detaches from the DOM all elements from the collection
	 * 
	 * @access public
	 * @instance
	 * @method remove
	 * @memberof DOMCollection
	 * @return {void}
	 */
	DOMCollection.prototype.remove = function () {
		this.elements.map(function (el) {
			el.remove();
		});
	}
});