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 null; 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 /** 249 * Change css property name to it's 250 * javascript camel case equivalent 251 */ 252 function _toCamel(s) 253 { 254 return s.replace(/(\-[a-z])/g, function($1){ 255 return $1.toUpperCase().replace('-',''); 256 }); 257 } 258 259 function _css(sel, prop, val) 260 { 261 var equi; 262 263 //Camel-case 264 prop = _toCamel(prop); 265 266 //Equivalent properties for 'special' browsers 267 equi = { 268 outerHeight: "offsetHeight", 269 outerWidth: "offsetWidth", 270 top: "posTop" 271 }; 272 273 274 //If you don't define a value, try returning the existing value 275 if(typeof val === "undefined" && sel.style[prop] !== "undefined") 276 { 277 return sel.style[prop]; 278 } 279 else if(typeof val === "undefined" && sel.style[equi[prop]] !== "undefined") 280 { 281 return sel.style[equi[prop]]; 282 } 283 284 //Let's try the easy way first 285 if(typeof sel.style[prop] !== "undefined") 286 { 287 sel.style[prop] = val; 288 289 //Short circuit 290 return null; 291 } 292 else if(sel.style[equi[prop]]) 293 { 294 sel.style[equi[prop]] = val; 295 return null; 296 } 297 298 //No matches? Well, lets log it for now 299 console.log("Property " + prop + " nor an equivalent seems to exist"); 300 } 301 302 // -------------------------------------------------------------------------- 303 304 /** 305 * DOM 306 * 307 * Dom manipulation module 308 * @namespace 309 * @memberOf $_ 310 * @name dom 311 */ 312 d = { 313 /** 314 * Adds a class to the element(s) specified by the current 315 * selector 316 * 317 * @name addClass 318 * @memberOf $_.dom 319 * @function 320 * @param string class 321 */ 322 addClass: function (c) 323 { 324 $_.each(function (e){ 325 e.classList.add(c); 326 }); 327 }, 328 /** 329 * Removes a class from the element(s) specified by the current 330 * selector 331 * 332 * @name removeClass 333 * @memberOf $_.dom 334 * @function 335 * @param string class 336 */ 337 removeClass: function (c) 338 { 339 $_.each(function (e){ 340 e.classList.remove(c); 341 }); 342 }, 343 /** 344 * Hides the element(s) specified by the current selector 345 * 346 * @name hide 347 * @memberOf $_.dom 348 * @function 349 */ 350 hide: function () 351 { 352 this.css('display', 'none'); 353 }, 354 /** 355 * Shows the element(s) specified by the current selector. 356 * if type is specified, the element will have it's style 357 * property set to "display:[your type]". If type is not 358 * specified, the element is set to "display:block". 359 * 360 * @name show 361 * @memberOf $_.dom 362 * @function 363 * @param [string] type 364 */ 365 show: function (type) 366 { 367 if (typeof type === "undefined") 368 { 369 type = "block"; 370 } 371 372 this.css("display", type); 373 }, 374 /** 375 * Sets attributes on element(s) specified by the current 376 * selector, or, if name is not specified, returns the 377 * value of the attribute of the element specified by the 378 * current selector. 379 * 380 * @name attr 381 * @memberOf $_.dom 382 * @function 383 * @param string name 384 * @param [string] value 385 * @return string 386 * @type string 387 */ 388 attr: function (name, value) 389 { 390 var sel = this.el; 391 392 //Make sure you don't try to get a bunch of elements 393 if (sel.length > 1 && typeof value === "undefined") 394 { 395 console.log(sel); 396 console.log("Must be a singular element"); 397 return; 398 } 399 else if (sel.length > 1 && typeof value !== "undefined") //You can set a bunch, though 400 { 401 $_.each(function (e){ 402 return _attr(e, name, value); 403 }); 404 } 405 else //Normal behavior 406 { 407 return _attr(sel, name, value); 408 } 409 }, 410 /** 411 * Sets or retrieves the text content of the element 412 * specified by the current selector. If a value is 413 * passed, it will set that value on the current element, 414 * otherwise it will return the value of the current element 415 * 416 * @name text 417 * @memberOf $_.dom 418 * @function 419 * @param [string] value 420 * @return string 421 * @type string 422 */ 423 text: function (value) 424 { 425 var oldValue, set, type, sel; 426 427 sel = this.el; 428 429 set = (typeof value !== "undefined") ? true : false; 430 431 type = (typeof sel.textContent !== "undefined") 432 ? "textContent" 433 : (typeof sel.innerText !== "undefined") 434 ? "innerText" 435 : "innerHTML"; 436 437 oldValue = sel[type]; 438 439 if(set) 440 { 441 sel[type] = value; 442 return value; 443 } 444 else 445 { 446 return oldValue; 447 } 448 }, 449 /** 450 * Sets or retrieves a css property of the element 451 * specified by the current selector. If a value is 452 * passed, it will set that value on the current element, 453 * otherwise it will return the value of the css property 454 * on the current element 455 * 456 * @name css 457 * @memberOf $_.dom 458 * @function 459 * @param string property 460 * @param [string] value 461 * @return string 462 * @type string 463 */ 464 css: function (prop, val) 465 { 466 //Return the current value if a value is not set 467 if(typeof val === "undefined") 468 { 469 return _css(this.el, prop); 470 } 471 472 $_.each(function (e){ 473 _css(e, prop, val); 474 }); 475 }, 476 /** 477 * Adds to the innerHTML of the current element, after the last child. 478 * 479 * @example $_("ul").dom.append("<li></li>") adds an li element to the end of the selected ul element 480 * @name append 481 * @memberOf $_.dom 482 * @function 483 * @param string htm 484 */ 485 append: function(htm) 486 { 487 if(typeof document.insertAdjacentHTML !== "undefined") 488 { 489 this.el.insertAdjacentHTML('beforeend', htm); 490 } 491 else 492 { 493 this.el.innerHTML += htm; 494 } 495 }, 496 /** 497 * Adds to the innerHTML of the selected element, before the current children 498 * 499 * @name prepend 500 * @memberOf $_.dom 501 * @function 502 * @param string htm 503 */ 504 prepend: function(htm) 505 { 506 if(typeof document.insertAdjacentHTML !== "undefined") 507 { 508 this.el.insertAdjacentHTML('afterbegin', htm); 509 } 510 else 511 { 512 this.el.innerHTML = htm + this.el.innerHTML; 513 } 514 }, 515 /** 516 * Sets or gets the innerHTML propery of the element(s) passed 517 * 518 * @name html 519 * @memberOf $_.dom 520 * @function 521 * @param [string] htm 522 * @return string 523 * @type string 524 */ 525 html: function(htm) 526 { 527 528 if(typeof htm !== "undefined") 529 { 530 this.el.innerHTML = htm; 531 } 532 533 //If the parameter is undefined, just return the current value 534 return this.el.innerHTML; 535 } 536 }; 537 538 $_.ext('dom', d); 539 540 }());