1 //This is used so IE 8 can use the classList api
  2 /*
  3  * classList.js: Cross-browser full element.classList implementation.
  4  * 2011-06-15
  5  *
  6  * By Eli Grey, http://eligrey.com
  7  * Public Domain.
  8  * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
  9  */
 10 
 11 if (typeof document !== "undefined" && !("classList" in document.createElement("a")))
 12 {
 13 	(function (view){
 14 	
 15 		var classListProp = "classList",
 16 			protoProp = "prototype",
 17 			elemCtrProto = (view.HTMLElement || view.Element)[protoProp],
 18 			objCtr = Object,
 19 			strTrim = String[protoProp].trim ||
 20 			function ()
 21 			{
 22 				return this.replace(/^\s+|\s+$/g, "");
 23 			},
 24 			arrIndexOf = Array[protoProp].indexOf ||
 25 			function (item)
 26 			{
 27 				var
 28 				i = 0,
 29 					len = this.length;
 30 				for (; i < len; i++)
 31 				{
 32 					if (i in this && this[i] === item)
 33 					{
 34 						return i;
 35 					}
 36 				}
 37 				return -1;
 38 			}
 39 			// Vendors: please allow content code to instantiate DOMExceptions
 40 			,
 41 			/**
 42 			 * @private
 43 			 */
 44 			DOMEx = function (type, message)
 45 			{
 46 				this.name = type;
 47 				this.code = DOMException[type];
 48 				this.message = message;
 49 			},
 50 			/**
 51 			 * @private
 52 			 */
 53 			checkTokenAndGetIndex = function (classList, token)
 54 			{
 55 				if (token === "")
 56 				{
 57 					throw new DOMEx("SYNTAX_ERR", "An invalid or illegal string was specified");
 58 				}
 59 				if (/\s/.test(token))
 60 				{
 61 					throw new DOMEx("INVALID_CHARACTER_ERR", "String contains an invalid character");
 62 				}
 63 				return arrIndexOf.call(classList, token);
 64 			},
 65 			/**
 66 			 * @private
 67 			 */
 68 			ClassList = function (elem)
 69 			{
 70 				var
 71 				trimmedClasses = strTrim.call(elem.className),
 72 					classes = trimmedClasses ? trimmedClasses.split(/\s+/) : [],
 73 					i = 0,
 74 					len = classes.length;
 75 				for (; i < len; i++)
 76 				{
 77 					this.push(classes[i]);
 78 				}
 79 				this._updateClassName = function ()
 80 				{
 81 					elem.className = this.toString();
 82 				};
 83 			},
 84 			classListProto = ClassList[protoProp] = [],
 85 			/**
 86 			 * @private
 87 			 */
 88 			classListGetter = function ()
 89 			{
 90 				return new ClassList(this);
 91 			};
 92 		// Most DOMException implementations don't allow calling DOMException's toString()
 93 		// on non-DOMExceptions. Error's toString() is sufficient here.
 94 		DOMEx[protoProp] = Error[protoProp];
 95 		classListProto.item = function (i)
 96 		{
 97 			return this[i] || null;
 98 		};
 99 		classListProto.contains = function (token)
100 		{
101 			token += "";
102 			return checkTokenAndGetIndex(this, token) !== -1;
103 		};
104 		classListProto.add = function (token)
105 		{
106 			token += "";
107 			if (checkTokenAndGetIndex(this, token) === -1)
108 			{
109 				this.push(token);
110 				this._updateClassName();
111 			}
112 		};
113 		classListProto.remove = function (token)
114 		{
115 			token += "";
116 			var index = checkTokenAndGetIndex(this, token);
117 			if (index !== -1)
118 			{
119 				this.splice(index, 1);
120 				this._updateClassName();
121 			}
122 		};
123 		classListProto.toggle = function (token)
124 		{
125 			token += "";
126 			if (checkTokenAndGetIndex(this, token) === -1)
127 			{
128 				this.add(token);
129 			}
130 			else
131 			{
132 				this.remove(token);
133 			}
134 		};
135 		classListProto.toString = function ()
136 		{
137 			return this.join(" ");
138 		};
139 
140 		if (objCtr.defineProperty)
141 		{
142 			var classListPropDesc = {
143 				get: classListGetter,
144 				enumerable: true,
145 				configurable: true
146 			};
147 			try
148 			{
149 				objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
150 			}
151 			catch (ex)
152 			{ // IE 8 doesn't support enumerable:true
153 				if (ex.number === -0x7FF5EC54)
154 				{
155 					classListPropDesc.enumerable = false;
156 					objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
157 				}
158 			}
159 		}
160 		else if (objCtr[protoProp].__defineGetter__)
161 		{
162 			elemCtrProto.__defineGetter__(classListProp, classListGetter);
163 		}
164 
165 	}(self));
166 }
167 
168 /**
169  * DOM
170  * 
171  * Dom manipulation module
172  */
173 (function (){
174 
175 	"use strict";
176 
177 	var d;
178 	
179 	//Private function for getting/setting attributes/properties
180 	function _attr(sel, name, value)
181 	{
182 		var oldVal, doAttr;
183 
184 		//Get the value of the attribute, if it exists
185 		if (typeof sel.hasAttribute !== "undefined")
186 		{
187 			if (sel.hasAttribute(name))
188 			{
189 				oldVal = sel.getAttribute(name);
190 			}
191 
192 			doAttr = true;
193 		}
194 		else if (typeof sel[name] !== "undefined")
195 		{
196 			oldVal = sel[name];
197 			doAttr = false;
198 		}
199 		else if (name === "class" && typeof sel.className !== "undefined") //className attribute
200 		{
201 			name = "className";
202 			oldVal = sel.className;
203 			doAttr = false;
204 		}
205 
206 		//Well, I guess that attribute doesn't exist
207 		if (typeof oldVal === "undefined" && (typeof value === "undefined" || value === null))
208 		{
209 			console.log(value);
210 			console.log(sel);
211 			console.log("Element does not have the selected attribute");
212 			return;
213 		}
214 
215 		//No value to set? Return the current value
216 		if (typeof value === "undefined")
217 		{
218 			return oldVal;
219 		}
220 
221 		//Determine what to do with the attribute
222 		if (typeof value !== "undefined" && value !== null)
223 		{
224 			if(doAttr === true)
225 			{
226 				sel.setAttribute(name, value);
227 			}
228 			else
229 			{
230 				sel[name] = value;
231 			} 
232 		}
233 		else if (value === null)
234 		{
235 			if(doAttr === true)
236 			{
237 				sel.removeAttribute(name);
238 			}
239 			else
240 			{
241 				delete sel[name];
242 			} 
243 		}
244 
245 		return (typeof value !== "undefined") ? value : oldVal;
246 	}
247 	
248 	function _toCamel(s)
249 	{
250 		return s.replace(/(\-[a-z])/g, function($1){
251 			return $1.toUpperCase().replace('-','');
252 		});
253 	}
254 
255 	function _css(sel, prop, val)
256 	{
257 		var equi;
258 		
259 		//Camel-case
260 		prop = _toCamel(prop);
261 
262 		//Equivalent properties for 'special' browsers
263 		equi = {
264 			outerHeight: "offsetHeight",
265 			outerWidth: "offsetWidth",
266 			top: "posTop"
267 		};
268 		
269 		
270 		//If you don't define a value, try returning the existing value
271 		if(typeof val === "undefined" && sel.style[prop] !== "undefined")
272 		{
273 			return sel.style[prop];
274 		}
275 		else if(typeof val === "undefined" && sel.style[equi[prop]] !== "undefined")
276 		{
277 			return sel.style[equi[prop]];
278 		}
279 
280 		//Let's try the easy way first
281 		if(typeof sel.style[prop] !== "undefined")
282 		{
283 			sel.style[prop] = val;
284 
285 			//Short circuit
286 			return;
287 		}
288 		else if(sel.style[equi[prop]])
289 		{
290 			sel.style[equi[prop]] = val;
291 			return;
292 		}
293 		
294 		//No matches? Well, lets log it for now
295 		console.log("Property " + prop + " nor an equivalent seems to exist");
296 	}
297 	
298 	// --------------------------------------------------------------------------
299 
300 	/**
301 	 * DOM
302 	 * 
303 	 * Dom manipulation module
304 	 * @namespace
305 	 * @memberOf $_
306 	 * @name dom
307 	 */
308 	d = {
309 		/**
310 		 * Adds a class to the element(s) specified by the current
311 		 * selector
312 		 * 
313 		 * @name addClass
314 		 * @memberOf $_.dom
315 		 * @function
316 		 * @param string class
317 		 */
318 		addClass: function (c)
319 		{
320 			$_.each(function (e){
321 				e.classList.add(c);
322 			});
323 		},
324 		/**
325 		 * Removes a class from the element(s) specified by the current
326 		 * selector
327 		 * 
328 		 * @name removeClass
329 		 * @memberOf $_.dom
330 		 * @function
331 		 * @param string class
332 		 */
333 		removeClass: function (c)
334 		{
335 			$_.each(function (e){
336 				e.classList.remove(c);
337 			});
338 		},
339 		/**
340 		 * Hides the element(s) specified by the current selector
341 		 * 
342 		 * @name hide
343 		 * @memberOf $_.dom
344 		 * @function
345 		 */
346 		hide: function ()
347 		{
348 			this.css('display', 'none');
349 		},
350 		/**
351 		 * Shows the element(s) specified by the current selector. 
352 		 * if type is specified, the element will have it's style
353 		 * property set to "display:[your type]". If type is not
354 		 * specified, the element is set to "display:block".
355 		 * 
356 		 * @name  show
357 		 * @memberOf $_.dom
358 		 * @function
359 		 * @param [string] type
360 		 */
361 		show: function (type)
362 		{
363 			if (typeof type === "undefined")
364 			{
365 				type = "block";
366 			}
367 
368 			this.css("display", type);
369 		},
370 		/**
371 		 * Sets attributes on element(s) specified by the current 
372 		 * selector, or, if name is not specified, returns the 
373 		 * value of the attribute of the element specified by the
374 		 * current selector.
375 		 *
376 		 * @name attr
377 		 * @memberOf $_.dom
378 		 * @function
379 		 * @param string name
380 		 * @param [string] value
381 		 * @return string
382 		 * @type string
383 		 */
384 		attr: function (name, value)
385 		{
386 			var sel = this.el;
387 
388 			//Make sure you don't try to get a bunch of elements
389 			if (sel.length > 1 && typeof value === "undefined")
390 			{
391 				console.log(sel);
392 				console.log("Must be a singular element");
393 				return;
394 			}
395 			else if (sel.length > 1 && typeof value !== "undefined") //You can set a bunch, though
396 			{
397 				$_.each(function (e){
398 					return _attr(e, name, value);
399 				});
400 			}
401 			else //Normal behavior
402 			{
403 				return _attr(sel, name, value);
404 			}
405 		},
406 		/**
407 		 * Sets or retrieves the text content of the element
408 		 * specified by the current selector. If a value is 
409 		 * passed, it will set that value on the current element,
410 		 * otherwise it will return the value of the current element
411 		 *
412 		 * @name text
413 		 * @memberOf $_.dom
414 		 * @function
415 		 * @param [string] value
416 		 * @return string
417 		 * @type string
418 		 */
419 		text: function (value)
420 		{
421 			var oldValue, set, type, sel;
422 		
423 			sel = this.el;
424 			
425 			set = (typeof value !== "undefined") ? true : false;
426 			
427 			type = (typeof sel.innerText !== "undefined")
428 				? "innerText"
429 				: (typeof sel.textContent !== "undefined")
430 					? "textContent"
431 					: "innerHTML";
432 
433 			oldValue = sel[type];
434 			
435 			if(set)
436 			{
437 				sel[type] = value;
438 				return value;
439 			}
440 			else
441 			{
442 				return oldValue;
443 			}
444 		},
445 		/**
446 		 * Sets or retrieves a css property of the element
447 		 * specified by the current selector. If a value is 
448 		 * passed, it will set that value on the current element,
449 		 * otherwise it will return the value of the css property
450 		 * on the current element
451 		 *
452 		 * @name css
453 		 * @memberOf $_.dom
454 		 * @function
455 		 * @param string property
456 		 * @param [string] value
457 		 * @return string
458 		 * @type string
459 		 */
460 		css: function (prop, val)
461 		{
462 			//Return the current value if a value is not set
463 			if(typeof val === "undefined")
464 			{
465 				return _css(this.el, prop);
466 			}
467 		
468 			$_.each(function (e){
469 				_css(e, prop, val);
470 			});
471 		},
472 		/**
473 		 * Adds to the innerHTML of the current element, after the last child.
474 		 * 
475 		 * @example $_("ul").dom.append("<li></li>") adds an li element to the end of the selected ul element
476 		 * @name append
477 		 * @memberOf $_.dom
478 		 * @function
479 		 * @param string htm
480 		 */
481 		append: function(htm)
482 		{
483 			if(typeof document.insertAdjacentHTML !== "undefined")
484 			{
485 				this.el.insertAdjacentHTML('beforeend', htm);
486 			}
487 			else
488 			{
489 				this.el.innerHTML += htm;
490 			}
491 		},
492 		/**
493 		 * Adds to the innerHTML of the selected element, before the current children
494 		 * 
495 		 * @name prepend
496 		 * @memberOf $_.dom
497 		 * @function
498 		 * @param string htm
499 		 */
500 		 prepend: function(htm)
501 		 {
502 		 	if(typeof document.insertAdjacentHTML !== "undefined")
503 		 	{
504 		 		this.el.insertAdjacentHTML('afterbegin', htm);
505 		 	}
506 		 	else
507 		 	{
508 		 		this.el.innerHTML = htm + this.el.innerHTML;
509 		 	}
510 		 },
511 		/**
512 		 * Sets or gets the innerHTML propery of the element(s) passed
513 		 *
514 		 * @name html
515 		 * @memberOf $_.dom
516 		 * @function
517 		 * @param [string] htm
518 		 * @return string
519 		 * @type string
520 		 */
521 		html: function(htm)
522 		{
523 			
524 			if(typeof htm !== "undefined")
525 			{
526 				this.el.innerHTML = htm;
527 			}
528 			
529 			//If the parameter is undefined, just return the current value
530 			return this.el.innerHTML;
531 		}
532 	};
533 
534 	$_.ext('dom', d);
535 	
536 }());
537