1 /**
  2  * Nornix common JavaScript routines.
  3  * 
  4  * @version     @version@
  5  */
  6 
  7 /**
  8  * The root namespace for all Nornix JavaScript.
  9  */
 10 if (!Nornix) var Nornix = {
 11 /**
 12  * @namespace Namespace for Event functions
 13  */
 14 	events:{}, 
 15 /**
 16  * @namespace Namespace for Cookie functions
 17  */
 18 	cookies:{},
 19 /**
 20  * @namespace Namespace for CSS functions.
 21  */
 22 	css:{},
 23 /**
 24  * @namespace Namespace for DOM functions.
 25  */
 26 	dom:{},
 27 /**
 28  * @namespace Namespace for Utility functions.
 29  */
 30 	util:{}};
 31 
 32 if (document.addEventListener)
 33 {
 34 /**
 35  * Function to add events to objects.
 36  * @see http://www.quirksmode.org/blog/archives/2005/10/_and_the_winner_1.html
 37  * @see http://ejohn.org/projects/flexible-javascript-events/
 38  * @see http://dean.edwards.name/weblog/2005/12/js-tip1
 39  * @param {Object} obj object to add the event to
 40  * @param {String} type event type, like "load", "click"
 41  * @param {Function} fn the function that should be run when the event fires
 42  * @param {boolean} capture if true, indicates that the user wishes to initiate capture
 43  */
 44 	Nornix.events.add = function ( obj, type, fn, capture )
 45 	{
 46 		obj.addEventListener( type, fn, capture );
 47 	};
 48 /**
 49  * Function to remove events from objects.
 50  * You should use the same parameters as in {@link event#addEvent} to remove the same event listener.
 51  * @see http://www.quirksmode.org/blog/archives/2005/10/_and_the_winner_1.html
 52  * @see http://ejohn.org/projects/flexible-javascript-events/
 53  * @see http://dean.edwards.name/weblog/2005/12/js-tip1
 54  * @param {Object} obj object to add the event to
 55  * @param {String} type event type, like "load", "click"
 56  * @param {Function} fn the function that should be run when the event fires
 57  * @param {boolean} capture if true, indicates that the user wishes to initiate capture
 58  */
 59 	Nornix.events.remove = function ( obj, type, fn, capture )
 60 	{
 61 		obj.removeEventListener( type, fn, capture );
 62 	};
 63 }
 64 else if (document.attachEvent)
 65 {
 66 	/**
 67 	 * @ignore
 68 	 */
 69 	Nornix.events.add = function( obj, type, fn )
 70 	{
 71 		obj["e"+type+fn] = fn;
 72 		obj[type+fn] = function()
 73 		{
 74 			var e = window.event;
 75 			e.target = window.event.srcElement;
 76 			obj["e"+type+fn]( e );
 77 		};
 78 		obj.attachEvent( "on"+type, obj[type+fn] );
 79 	};
 80 	/**
 81 	 * @ignore
 82 	 */
 83 	Nornix.events.remove = function( obj, type, fn )
 84 	{
 85 		obj.detachEvent( "on"+type, obj[type+fn] );
 86 		obj[type+fn] = null;
 87 		obj["e"+type+fn] = null;
 88 	};
 89 }
 90 else
 91 {
 92 	// sorry, no support!
 93 	Nornix.events.add = Function;
 94 	Nornix.events.remove = Function;
 95 }
 96 
 97 /**
 98  * Function to stop normal browser action on events.
 99  * Function you can call within your event handlers to stop them performing
100  * the normal browser action or kill the event entirely.
101  * @see http://www.twinhelix.com
102  * @param {Event} e the event object
103  * @param {boolean} c set to true to cancel event bubbling
104  */
105 Nornix.events.cancel = function(e, c)
106 {
107 	e.returnValue = false;
108 	if (e.preventDefault) e.preventDefault();
109 	if (c)
110 	{
111 		e.cancelBubble = true;
112 		if (e.stopPropagation) e.stopPropagation();
113 	}
114 };
115 
116 /**
117  * Function to run an initialization after an element
118  * has became available in the DOM.
119  *
120  * The element will be sent to the initializing function as an object.
121  * @param {String} id ID of element to wait for
122  * @param {Function} initFunc the function that should be run when the element is available
123  * @param {number} interval time in milliseconds
124  */
125 Nornix.events.delayedInit = function (id, initFunc, interval)
126 {
127 	var el;
128 	if (interval === undefined) interval = 10;
129 	var intervalId = window.setInterval( function ()
130 		{
131 			if (el = document.getElementById(id))
132 			{
133 				window.clearInterval(intervalId);
134 				initFunc(el);
135 			}
136 		},
137 		interval
138 	);
139 };
140 
141 /**
142  * Function to create a browser cookie.
143  * @param {String} name name of cookie
144  * @param {String} value value of cookie
145  * @param {Number} days number of days browser should save the cookie
146  */
147 Nornix.cookies.create = function (name, value, days)
148 {
149 	var expire;
150 	if (days)
151 	{
152 		var date = new Date();
153 		date.setTime(date.getTime()+(days*24*60*60*1000));
154 		expire = "; expires="+date.toGMTString();
155 	}
156 	else
157 	{
158 		expire = "";
159 	}
160 	document.cookie = name+"="+value+expire+"; path=/";
161 };
162 
163 /**
164  * Function to read a browser cookie.
165  * @param {String} name name of cookie
166  * @return value of cookie
167  * @type String
168  */
169 Nornix.cookies.read = function (name)
170 {
171 	var nameEQ = name + "=";
172 	var ca = document.cookie.split(';'), i = 0, c;
173 	while (c = ca[i++])
174 	{
175 		c = Nornix.util.trim(c);
176 		if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
177 	}
178 	return '';
179 };
180 
181 /**
182  * Function to erase a browser cookie.
183  * @param {String} name name of cookie
184  */
185 Nornix.cookies.erase = function (name)
186 {
187 	createCookie(name, "", -1);
188 };
189 
190 /**
191  * Function to swap, remove or add a class name on an object.
192  * @param {HTMLElement} el the object to work on
193  * @param {String} oldstr the old class -- set to null to add class
194  * @param {String} newstr the new class -- leave empty to remove class
195  */
196 Nornix.css.swap = function (el, oldstr, newstr)
197 {
198 	if (!el) return;
199 	if (!el.className || el.className.length === 0)
200 	{
201 		el.className = newstr ? newstr : "";
202 		return;
203 	}
204 	var arr = el.className.split(" "), i = 0, t;
205 	while (t = arr[i++])
206 	{
207 		if (t === oldstr)
208 		{
209 			if (newstr)
210 			{
211 				arr[i-1] = newstr;
212 				el.className = arr.join(" ");
213 				return;
214 			}
215 			else
216 			{
217 				delete arr[i-1];
218 				el.className = arr.join(" ");
219 				return;
220 			}
221 		}
222 		else if (t === newstr)
223 		{
224 				el.className = arr.join(" ");
225 				return;
226 		}
227 	}
228 	if (newstr) arr[arr.length] = newstr;
229 	el.className = arr.join(" ");
230 };
231 
232 /**
233  * Function to add a class name on an object.
234  * @param {HTMLElement} el the object to work on
235  * @param {String} className the new class
236  */
237 Nornix.css.add = function (el, className)
238 {
239 	return Nornix.css.swap(el, null, className);
240 };
241 
242 /**
243  * Function to remove a class name from an object.
244  * @function
245  * @param {HTMLElement} el the object to work on
246  * @param {String} className class to remove
247  */
248 Nornix.css.remove = function (el, className)
249 {
250 	return Nornix.css.swap;
251 }(); // create alias for swapClasses()
252 
253 /**
254  * Check if class exists on element.
255  * @param {HTMLElement} el the object to work on
256  * @param {String} s class name
257  * @return true if the class exists
258  */
259 Nornix.css.contains = function (el, s)
260 {
261 	if (!el || !el.className) return false;
262 	var arr = el.className.split(" "), i = 0, t;
263 	while (t = arr[i++])
264 	{
265 		if (t === s) return true;
266 	}
267 	return false;
268 };
269 
270 /**
271  * Get position of node.
272  * @param {HTMLElement} obj the object to work on
273  * @return absolute position as .x and .y of return value.
274  */
275 Nornix.css.getPos = function (obj)
276 {
277 	var pos = {x: obj.offsetLeft || 0, y: obj.offsetTop || 0};
278 	while (obj = obj.offsetParent)
279 	{
280 		pos.x += obj.offsetLeft || 0;
281 		pos.y += obj.offsetTop || 0;
282 	}
283 	return pos;
284 };
285 
286 /**
287  * Get current style of element.
288  * @function
289  * @param {HTMLElement} el element to get the style from
290  * @param {String} styleProp CSS style propterty to fetch
291  * @return current setting of style property
292  */
293 Nornix.css.getProperty = function (el, styleProp)
294 {
295 	if (window.getComputedStyle)
296 	{
297 		return function (el, styleProp)
298 		{
299 			return window.getComputedStyle(el, "").getPropertyValue(styleProp);
300 		};
301 	}
302 	return function (el, styleProp)
303 	{
304 		return el.currentStyle ? el.currentStyle[Nornix.css.prop2Js(styleProp)] : null;
305 	};
306 }();
307 
308 /**
309  * Convert CSS property to JS equivalent.
310  * @param {String} p property to convert
311  * @return JS property
312  */
313 Nornix.css.prop2Js = function (p)
314 {
315 	var arr = p.split("-");
316 	if (arr.length > 1)
317 	{
318 		var sum = arr[0], i = 1, part;
319 		while (part = arr[i++])
320 		{
321 			sum += part.charAt(0).toUpperCase() + part.substr(1);
322 		}
323 		return sum;
324 	}
325 	return p;
326 };
327 
328 
329 /**
330  * Create static copy of a live collection.
331  * This makes it much faster to work with the elements.
332  * @param {HTMLCollection} collection a live collection
333  * @return static copy of the live collection
334  */
335 Nornix.dom.live2copy = function (collection)
336 {
337 	var elements = [], i = 0, el;
338 	while (el = collection[i++])
339 	{
340 		elements[elements.length] = el;
341 	}
342 	return elements;
343 }
344 
345 /**
346  * Function that reads the text content of a DOM node.
347  * IE FIX for .textContent
348  * @param {Node} node DOM node to get text content from
349  * @return text content of node
350  * @type String
351  */
352 Nornix.dom.getTextContent = function (node)
353 {
354 	if (typeof node.textContent != "undefined")
355 	{
356 		return node.textContent;
357 	}
358 	else
359 	{
360 		return node.innerText;
361 	}
362 };
363 
364 /**
365  * Preload image files for faster rendering.
366  * @param {Array} imgs array of images
367  * @param {String} path path to images
368  */
369 Nornix.dom.imagePreload = function (imgs, path, extension)
370 {
371 	if (Nornix.cookies.read("preImg")) return;
372 	var i = 0, img, loadedImgs = [], loadedImgsCount = 0, imgsCount = imgs.length, imgO;
373 	function checkFinished ()
374 	{
375 		loadedImgsCount++;
376 		if (loadedImgsCount === imgsCount)
377 		{
378 			loadedImgs = null;
379 			Nornix.cookies.create("preImg", "x");
380 		}
381 	}
382 	while (img = imgs[i++])
383 	{
384 		imgO = new Image();
385 		imgO.onload = checkFinished;
386 		imgO.src = path + img + extension;
387 		loadedImgs[i] = imgO;
388 	}
389 };
390 
391 /**
392  * Find first or last children of element type.
393  * @param {HTMLElement} nodes node, which children nodes will be searched
394  * @param {String} nodeName type of HTML element we are looking for
395  * @param {Function} nodeAction closure for action to execute
396  * @param {boolean} backwards search from the end of the child list when true
397  * @return value of action closure.
398  */
399 Nornix.dom.findChildOfType = function (nodes, nodeName, nodeAction, backwards)
400 {
401 	var e;
402 	if (!backwards)
403 	{
404 		var i = 0;
405 		while (e = nodes.childNodes[i++])
406 		{
407 			if (Nornix.dom.eqNodeName(e, nodeName))
408 			{
409 				return nodeAction(e);
410 			}
411 		}
412 	}
413 	else
414 	{
415 		var i = nodes.childNodes.length - 1;
416 		while (e = nodes.childNodes[i--])
417 		{
418 			if (Nornix.dom.eqNodeName(e, nodeName))
419 			{
420 				return nodeAction(e);
421 			}
422 		}
423 	}
424 };
425 
426 /**
427  * Check if node name of element is equal to a string.
428  * @param {HTMLElement} el the object to work on
429  * @param {String} nodeName
430  * @return true if the node name is equivalent
431  */
432 Nornix.dom.eqNodeName = function  (el, nodeName)
433 {
434 	if (el && el.nodeName && el.nodeName.toLowerCase() === nodeName)
435 	{
436 		return true;
437 	}
438 	return false;
439 };
440 
441 /**
442  * String function that removes whitespace from the start and end of a string.
443  * @param {String} s the string to use
444  * @return {String} the string with whitespace removed
445  * @type String
446  */
447 Nornix.util.trim = function (s)
448 {
449 	return s.replace(/^\s*|\s*$/g, "");
450 };
451 
452 /**
453  * True when browser is Internet Exlorer.
454  * @type boolean
455  */
456 Nornix.util.isIe = document.all && window.opera === undefined;
457