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