1 /**
  2  * @fileOverview Functionality for setting up Selector based Function mappings.
  3  * @author <a href="http://www.bobs-bits.com">Stephen Reay</a>
  4  */
  5 
  6 /**
  7  * @namespace CSS Selector Based function mappings
  8  */
  9 BTM.Mapping = {};
 10 
 11 /**
 12  * BTM Mappings on/off flag
 13  * @name BTM.options.runMappings
 14  * @see BTM.Mapping.init
 15  * @type Boolean
 16  * @default true
 17  * @field
 18  */
 19 BTM.loadOption('runMappings', true);
 20 
 21 /**
 22  * The Array containing the functions to run
 23  * @type {Array}
 24  */
 25 BTM.Mapping.callbacks = [];
 26 
 27 /**
 28  * Flag to indicate if mappings have been run for the page
 29  * @type {Boolean}
 30  */
 31 BTM.Mapping.mappingsHaveRun = false;
 32 
 33 /**
 34  * Add an entry for a function to run on specified elements
 35  * @param {String} selector the CSS selector string representing the target Elements
 36  * @param {Function} callback the Function to call for each Element. The target Element will be passed as the first argument to the Function
 37  * @param {Number} [initOrder=5] the "run-level" for this Mapping, lower levels run earlier.
 38  * @returns {Number} the index where the new Mapping was created. This (along with the selector String) can be used to refer to the Mapping later, e.g. to remove it
 39  */
 40 BTM.Mapping.add = function add(selector, callback, initOrder) {
 41 
 42 	initOrder = Object.isUndefined(initOrder) ? 5 : initOrder;
 43 
 44 	if (BTM.Mapping.mappingsHaveRun) {
 45 		return BTM.$$(selector).forEach(callback);
 46 	}
 47 	
 48 	if (!BTM.Mapping.callbacks[initOrder]) {
 49 		BTM.Mapping.callbacks[initOrder] = {};
 50 	}
 51 	
 52 	if (!BTM.Mapping.callbacks[initOrder][selector]) {
 53 		BTM.Mapping.callbacks[initOrder][selector] = [];
 54 	}
 55 	var index = BTM.Mapping.callbacks[initOrder][selector].push(callback);
 56 	
 57 	return index;
 58 };
 59 
 60 /**
 61  * Remove an entry from the Mappings Array
 62  * @param {String} selector the CSS selector string representing the target Elements
 63  * @param {Number} index the index of the Function in the Array. This is the value returned by @link{BTM.Mapping.add}
 64  * @param {Number} [initOrder=5] the "run-level" to remove the Mapping from
 65  * @returns {Function|Boolean} the Function that has been removed from the Mappings Array, or false if not found
 66  */	
 67 BTM.Mapping.remove = function remove(selector, index, initOrder) {
 68 	
 69 	initOrder = Object.isUndefined(initOrder) ? 5 : initOrder;
 70 	
 71 	if (BTM.Mapping.callbacks[initOrder] && BTM.Mapping.callbacks[initOrder][selector] && BTM.Mapping.callbacks[initOrder][selector][index]) {
 72 		var func = delete BTM.Mapping.callbacks[initOrder][selector][index];
 73 		return func;
 74 	}
 75 	return false;
 76 };
 77 
 78 /**
 79  * Worker Function to run mappings
 80  * @private
 81  * @param {HTMLElement} container the Element to use as a base location when finding Elements to run Mappings on
 82  * @param {Object|Function[]} mappings an Object containing an Array of Functions & the CSS Selector, or the Array of Functions
 83  * @param {Number|String} level the Level of Mappings to run, or the CSS Selector to identify Elements
 84  * @see BTM.Mapping.init
 85  */
 86 BTM.Mapping.run = function run(container, mappings, level) {
 87 	if (Object.isObject(mappings)) {
 88 		BTM.log('Running Mappings at Level: ' + level);
 89 		Object.forEach(mappings, BTM.Mapping.run.curry(container), this);
 90 	}
 91 	else if (Object.isArray(mappings)) {
 92 		BTM.log('Running Mappings for Selector: ' + level);
 93 		var elements = BTM.$$(level, container);
 94 		for (var i = 0; i < mappings.length; i++) {
 95 			if (Object.isFunction(mappings[i])) {
 96 				elements.forEach(mappings[i]);
 97 			}
 98 		}
 99 	}
100 };
101 
102 /**
103  * Run the Mappings. If the BTM option "runMappings" is set to false, this will return false and not run
104  * @param {HTMLElement|String} [container=document.body] element ID or element reference to use as the base when selecting target Elements
105  * @returns {Number} time taken to run all Mappings
106  * @see BTM.options.runMappings
107  */
108 BTM.Mapping.init = function init(container) {
109 	if (!BTM.options.runMappings) {
110 		return false;
111 	}
112 	container = BTM.$(container) || document;
113 	BTM.log("Running all Mappings", container);
114 	BTM.Mapping.mappingsHaveRun = true;
115 	var startTime = new Date();
116 	BTM.Mapping.callbacks.forEach(BTM.Mapping.run.curry(container), this);
117 	var finishTime = new Date();
118 	BTM.log("Mappings finished in " + ((finishTime - startTime)/1000) + " seconds");
119 	return finishTime - startTime;
120 };
121 
122 BTM.observe(document, 'DOMContentLoaded', BTM.Mapping.init);