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 }());