1 /* 2 --- 3 MooTools: the javascript framework 4 5 web build: 6 - http://mootools.net/core/8423c12ffd6a6bfcde9ea22554aec795 7 8 packager build: 9 - packager build Core/Core Core/Array Core/String Core/Number Core/Function Core/Object Core/Event Core/Browser Core/Class Core/Class.Extras Core/Slick.Parser Core/Slick.Finder Core/Element Core/Element.Style Core/Element.Event Core/Element.Delegation Core/Element.Dimensions Core/Fx Core/Fx.CSS Core/Fx.Tween Core/Fx.Morph Core/Fx.Transitions Core/Request Core/Request.HTML Core/Request.JSON Core/Cookie Core/JSON Core/DOMReady 10 11 ... 12 */ 13 14 /* 15 --- 16 17 name: Core 18 19 description: The heart of MooTools. 20 21 license: MIT-style license. 22 23 copyright: Copyright (c) 2006-2014 [Valerio Proietti](http://mad4milk.net/). 24 25 authors: The MooTools production team (http://mootools.net/developers/) 26 27 inspiration: 28 - Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php) 29 - Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php) 30 31 provides: [Core, MooTools, Type, typeOf, instanceOf, Native] 32 33 ... 34 */ 35 36 (function(){ 37 38 this.MooTools = { 39 version: '1.5.0', 40 build: '0f7b690afee9349b15909f33016a25d2e4d9f4e3' 41 }; 42 43 // typeOf, instanceOf 44 45 var typeOf = this.typeOf = function(item){ 46 if (item == null) return 'null'; 47 if (item.$family != null) return item.$family(); 48 49 if (item.nodeName){ 50 if (item.nodeType == 1) return 'element'; 51 if (item.nodeType == 3) return (/\S/).test(item.nodeValue) ? 'textnode' : 'whitespace'; 52 } else if (typeof item.length == 'number'){ 53 if ('callee' in item) return 'arguments'; 54 if ('item' in item) return 'collection'; 55 } 56 57 return typeof item; 58 }; 59 60 var instanceOf = this.instanceOf = function(item, object){ 61 if (item == null) return false; 62 var constructor = item.$constructor || item.constructor; 63 while (constructor){ 64 if (constructor === object) return true; 65 constructor = constructor.parent; 66 } 67 /*<ltIE8>*/ 68 if (!item.hasOwnProperty) return false; 69 /*</ltIE8>*/ 70 return item instanceof object; 71 }; 72 73 // Function overloading 74 75 var Function = this.Function; 76 77 var enumerables = true; 78 for (var i in {toString: 1}) enumerables = null; 79 if (enumerables) enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'constructor']; 80 81 Function.prototype.overloadSetter = function(usePlural){ 82 var self = this; 83 return function(a, b){ 84 if (a == null) return this; 85 if (usePlural || typeof a != 'string'){ 86 for (var k in a) self.call(this, k, a[k]); 87 if (enumerables) for (var i = enumerables.length; i--;){ 88 k = enumerables[i]; 89 if (a.hasOwnProperty(k)) self.call(this, k, a[k]); 90 } 91 } else { 92 self.call(this, a, b); 93 } 94 return this; 95 }; 96 }; 97 98 Function.prototype.overloadGetter = function(usePlural){ 99 var self = this; 100 return function(a){ 101 var args, result; 102 if (typeof a != 'string') args = a; 103 else if (arguments.length > 1) args = arguments; 104 else if (usePlural) args = [a]; 105 if (args){ 106 result = {}; 107 for (var i = 0; i < args.length; i++) result[args[i]] = self.call(this, args[i]); 108 } else { 109 result = self.call(this, a); 110 } 111 return result; 112 }; 113 }; 114 115 Function.prototype.extend = function(key, value){ 116 this[key] = value; 117 }.overloadSetter(); 118 119 Function.prototype.implement = function(key, value){ 120 this.prototype[key] = value; 121 }.overloadSetter(); 122 123 // From 124 125 var slice = Array.prototype.slice; 126 127 Function.from = function(item){ 128 return (typeOf(item) == 'function') ? item : function(){ 129 return item; 130 }; 131 }; 132 133 Array.from = function(item){ 134 if (item == null) return []; 135 return (Type.isEnumerable(item) && typeof item != 'string') ? (typeOf(item) == 'array') ? item : slice.call(item) : [item]; 136 }; 137 138 Number.from = function(item){ 139 var number = parseFloat(item); 140 return isFinite(number) ? number : null; 141 }; 142 143 String.from = function(item){ 144 return item + ''; 145 }; 146 147 // hide, protect 148 149 Function.implement({ 150 151 hide: function(){ 152 this.$hidden = true; 153 return this; 154 }, 155 156 protect: function(){ 157 this.$protected = true; 158 return this; 159 } 160 161 }); 162 163 // Type 164 165 var Type = this.Type = function(name, object){ 166 if (name){ 167 var lower = name.toLowerCase(); 168 var typeCheck = function(item){ 169 return (typeOf(item) == lower); 170 }; 171 172 Type['is' + name] = typeCheck; 173 if (object != null){ 174 object.prototype.$family = (function(){ 175 return lower; 176 }).hide(); 177 178 } 179 } 180 181 if (object == null) return null; 182 183 object.extend(this); 184 object.$constructor = Type; 185 object.prototype.$constructor = object; 186 187 return object; 188 }; 189 190 var toString = Object.prototype.toString; 191 192 Type.isEnumerable = function(item){ 193 return (item != null && typeof item.length == 'number' && toString.call(item) != '[object Function]' ); 194 }; 195 196 var hooks = {}; 197 198 var hooksOf = function(object){ 199 var type = typeOf(object.prototype); 200 return hooks[type] || (hooks[type] = []); 201 }; 202 203 var implement = function(name, method){ 204 if (method && method.$hidden) return; 205 206 var hooks = hooksOf(this); 207 208 for (var i = 0; i < hooks.length; i++){ 209 var hook = hooks[i]; 210 if (typeOf(hook) == 'type') implement.call(hook, name, method); 211 else hook.call(this, name, method); 212 } 213 214 var previous = this.prototype[name]; 215 if (previous == null || !previous.$protected) this.prototype[name] = method; 216 217 if (this[name] == null && typeOf(method) == 'function') extend.call(this, name, function(item){ 218 return method.apply(item, slice.call(arguments, 1)); 219 }); 220 }; 221 222 var extend = function(name, method){ 223 if (method && method.$hidden) return; 224 var previous = this[name]; 225 if (previous == null || !previous.$protected) this[name] = method; 226 }; 227 228 Type.implement({ 229 230 implement: implement.overloadSetter(), 231 232 extend: extend.overloadSetter(), 233 234 alias: function(name, existing){ 235 implement.call(this, name, this.prototype[existing]); 236 }.overloadSetter(), 237 238 mirror: function(hook){ 239 hooksOf(this).push(hook); 240 return this; 241 } 242 243 }); 244 245 new Type('Type', Type); 246 247 // Default Types 248 249 var force = function(name, object, methods){ 250 var isType = (object != Object), 251 prototype = object.prototype; 252 253 if (isType) object = new Type(name, object); 254 255 for (var i = 0, l = methods.length; i < l; i++){ 256 var key = methods[i], 257 generic = object[key], 258 proto = prototype[key]; 259 260 if (generic) generic.protect(); 261 if (isType && proto) object.implement(key, proto.protect()); 262 } 263 264 if (isType){ 265 var methodsEnumerable = prototype.propertyIsEnumerable(methods[0]); 266 object.forEachMethod = function(fn){ 267 if (!methodsEnumerable) for (var i = 0, l = methods.length; i < l; i++){ 268 fn.call(prototype, prototype[methods[i]], methods[i]); 269 } 270 for (var key in prototype) fn.call(prototype, prototype[key], key); 271 }; 272 } 273 274 return force; 275 }; 276 277 force('String', String, [ 278 'charAt', 'charCodeAt', 'concat', 'contains', 'indexOf', 'lastIndexOf', 'match', 'quote', 'replace', 'search', 279 'slice', 'split', 'substr', 'substring', 'trim', 'toLowerCase', 'toUpperCase' 280 ])('Array', Array, [ 281 'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice', 282 'indexOf', 'lastIndexOf', 'filter', 'forEach', 'every', 'map', 'some', 'reduce', 'reduceRight' 283 ])('Number', Number, [ 284 'toExponential', 'toFixed', 'toLocaleString', 'toPrecision' 285 ])('Function', Function, [ 286 'apply', 'call', 'bind' 287 ])('RegExp', RegExp, [ 288 'exec', 'test' 289 ])('Object', Object, [ 290 'create', 'defineProperty', 'defineProperties', 'keys', 291 'getPrototypeOf', 'getOwnPropertyDescriptor', 'getOwnPropertyNames', 292 'preventExtensions', 'isExtensible', 'seal', 'isSealed', 'freeze', 'isFrozen' 293 ])('Date', Date, ['now']); 294 295 Object.extend = extend.overloadSetter(); 296 297 Date.extend('now', function(){ 298 return +(new Date); 299 }); 300 301 new Type('Boolean', Boolean); 302 303 // fixes NaN returning as Number 304 305 Number.prototype.$family = function(){ 306 return isFinite(this) ? 'number' : 'null'; 307 }.hide(); 308 309 // Number.random 310 311 Number.extend('random', function(min, max){ 312 return Math.floor(Math.random() * (max - min + 1) + min); 313 }); 314 315 // forEach, each 316 317 var hasOwnProperty = Object.prototype.hasOwnProperty; 318 Object.extend('forEach', function(object, fn, bind){ 319 for (var key in object){ 320 if (hasOwnProperty.call(object, key)) fn.call(bind, object[key], key, object); 321 } 322 }); 323 324 Object.each = Object.forEach; 325 326 Array.implement({ 327 328 /*<!ES5>*/ 329 forEach: function(fn, bind){ 330 for (var i = 0, l = this.length; i < l; i++){ 331 if (i in this) fn.call(bind, this[i], i, this); 332 } 333 }, 334 /*</!ES5>*/ 335 336 each: function(fn, bind){ 337 Array.forEach(this, fn, bind); 338 return this; 339 } 340 341 }); 342 343 // Array & Object cloning, Object merging and appending 344 345 var cloneOf = function(item){ 346 switch (typeOf(item)){ 347 case 'array': return item.clone(); 348 case 'object': return Object.clone(item); 349 default: return item; 350 } 351 }; 352 353 Array.implement('clone', function(){ 354 var i = this.length, clone = new Array(i); 355 while (i--) clone[i] = cloneOf(this[i]); 356 return clone; 357 }); 358 359 var mergeOne = function(source, key, current){ 360 switch (typeOf(current)){ 361 case 'object': 362 if (typeOf(source[key]) == 'object') Object.merge(source[key], current); 363 else source[key] = Object.clone(current); 364 break; 365 case 'array': source[key] = current.clone(); break; 366 default: source[key] = current; 367 } 368 return source; 369 }; 370 371 Object.extend({ 372 373 merge: function(source, k, v){ 374 if (typeOf(k) == 'string') return mergeOne(source, k, v); 375 for (var i = 1, l = arguments.length; i < l; i++){ 376 var object = arguments[i]; 377 for (var key in object) mergeOne(source, key, object[key]); 378 } 379 return source; 380 }, 381 382 clone: function(object){ 383 var clone = {}; 384 for (var key in object) clone[key] = cloneOf(object[key]); 385 return clone; 386 }, 387 388 append: function(original){ 389 for (var i = 1, l = arguments.length; i < l; i++){ 390 var extended = arguments[i] || {}; 391 for (var key in extended) original[key] = extended[key]; 392 } 393 return original; 394 } 395 396 }); 397 398 // Object-less types 399 400 ['Object', 'WhiteSpace', 'TextNode', 'Collection', 'Arguments'].each(function(name){ 401 new Type(name); 402 }); 403 404 // Unique ID 405 406 var UID = Date.now(); 407 408 String.extend('uniqueID', function(){ 409 return (UID++).toString(36); 410 }); 411 412 413 414 })(); 415 416 417 /* 418 --- 419 420 name: Array 421 422 description: Contains Array Prototypes like each, contains, and erase. 423 424 license: MIT-style license. 425 426 requires: [Type] 427 428 provides: Array 429 430 ... 431 */ 432 433 Array.implement({ 434 435 /*<!ES5>*/ 436 every: function(fn, bind){ 437 for (var i = 0, l = this.length >>> 0; i < l; i++){ 438 if ((i in this) && !fn.call(bind, this[i], i, this)) return false; 439 } 440 return true; 441 }, 442 443 filter: function(fn, bind){ 444 var results = []; 445 for (var value, i = 0, l = this.length >>> 0; i < l; i++) if (i in this){ 446 value = this[i]; 447 if (fn.call(bind, value, i, this)) results.push(value); 448 } 449 return results; 450 }, 451 452 indexOf: function(item, from){ 453 var length = this.length >>> 0; 454 for (var i = (from < 0) ? Math.max(0, length + from) : from || 0; i < length; i++){ 455 if (this[i] === item) return i; 456 } 457 return -1; 458 }, 459 460 map: function(fn, bind){ 461 var length = this.length >>> 0, results = Array(length); 462 for (var i = 0; i < length; i++){ 463 if (i in this) results[i] = fn.call(bind, this[i], i, this); 464 } 465 return results; 466 }, 467 468 some: function(fn, bind){ 469 for (var i = 0, l = this.length >>> 0; i < l; i++){ 470 if ((i in this) && fn.call(bind, this[i], i, this)) return true; 471 } 472 return false; 473 }, 474 /*</!ES5>*/ 475 476 clean: function(){ 477 return this.filter(function(item){ 478 return item != null; 479 }); 480 }, 481 482 invoke: function(methodName){ 483 var args = Array.slice(arguments, 1); 484 return this.map(function(item){ 485 return item[methodName].apply(item, args); 486 }); 487 }, 488 489 associate: function(keys){ 490 var obj = {}, length = Math.min(this.length, keys.length); 491 for (var i = 0; i < length; i++) obj[keys[i]] = this[i]; 492 return obj; 493 }, 494 495 link: function(object){ 496 var result = {}; 497 for (var i = 0, l = this.length; i < l; i++){ 498 for (var key in object){ 499 if (object[key](this[i])){ 500 result[key] = this[i]; 501 delete object[key]; 502 break; 503 } 504 } 505 } 506 return result; 507 }, 508 509 contains: function(item, from){ 510 return this.indexOf(item, from) != -1; 511 }, 512 513 append: function(array){ 514 this.push.apply(this, array); 515 return this; 516 }, 517 518 getLast: function(){ 519 return (this.length) ? this[this.length - 1] : null; 520 }, 521 522 getRandom: function(){ 523 return (this.length) ? this[Number.random(0, this.length - 1)] : null; 524 }, 525 526 include: function(item){ 527 if (!this.contains(item)) this.push(item); 528 return this; 529 }, 530 531 combine: function(array){ 532 for (var i = 0, l = array.length; i < l; i++) this.include(array[i]); 533 return this; 534 }, 535 536 erase: function(item){ 537 for (var i = this.length; i--;){ 538 if (this[i] === item) this.splice(i, 1); 539 } 540 return this; 541 }, 542 543 empty: function(){ 544 this.length = 0; 545 return this; 546 }, 547 548 flatten: function(){ 549 var array = []; 550 for (var i = 0, l = this.length; i < l; i++){ 551 var type = typeOf(this[i]); 552 if (type == 'null') continue; 553 array = array.concat((type == 'array' || type == 'collection' || type == 'arguments' || instanceOf(this[i], Array)) ? Array.flatten(this[i]) : this[i]); 554 } 555 return array; 556 }, 557 558 pick: function(){ 559 for (var i = 0, l = this.length; i < l; i++){ 560 if (this[i] != null) return this[i]; 561 } 562 return null; 563 }, 564 565 hexToRgb: function(array){ 566 if (this.length != 3) return null; 567 var rgb = this.map(function(value){ 568 if (value.length == 1) value += value; 569 return parseInt(value, 16); 570 }); 571 return (array) ? rgb : 'rgb(' + rgb + ')'; 572 }, 573 574 rgbToHex: function(array){ 575 if (this.length < 3) return null; 576 if (this.length == 4 && this[3] == 0 && !array) return 'transparent'; 577 var hex = []; 578 for (var i = 0; i < 3; i++){ 579 var bit = (this[i] - 0).toString(16); 580 hex.push((bit.length == 1) ? '0' + bit : bit); 581 } 582 return (array) ? hex : '#' + hex.join(''); 583 } 584 585 }); 586 587 588 589 590 /* 591 --- 592 593 name: String 594 595 description: Contains String Prototypes like camelCase, capitalize, test, and toInt. 596 597 license: MIT-style license. 598 599 requires: [Type, Array] 600 601 provides: String 602 603 ... 604 */ 605 606 String.implement({ 607 608 //<!ES6> 609 contains: function(string, index){ 610 return (index ? String(this).slice(index) : String(this)).indexOf(string) > -1; 611 }, 612 //</!ES6> 613 614 test: function(regex, params){ 615 return ((typeOf(regex) == 'regexp') ? regex : new RegExp('' + regex, params)).test(this); 616 }, 617 618 trim: function(){ 619 return String(this).replace(/^\s+|\s+$/g, ''); 620 }, 621 622 clean: function(){ 623 return String(this).replace(/\s+/g, ' ').trim(); 624 }, 625 626 camelCase: function(){ 627 return String(this).replace(/-\D/g, function(match){ 628 return match.charAt(1).toUpperCase(); 629 }); 630 }, 631 632 hyphenate: function(){ 633 return String(this).replace(/[A-Z]/g, function(match){ 634 return ('-' + match.charAt(0).toLowerCase()); 635 }); 636 }, 637 638 capitalize: function(){ 639 return String(this).replace(/\b[a-z]/g, function(match){ 640 return match.toUpperCase(); 641 }); 642 }, 643 644 escapeRegExp: function(){ 645 return String(this).replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1'); 646 }, 647 648 toInt: function(base){ 649 return parseInt(this, base || 10); 650 }, 651 652 toFloat: function(){ 653 return parseFloat(this); 654 }, 655 656 hexToRgb: function(array){ 657 var hex = String(this).match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); 658 return (hex) ? hex.slice(1).hexToRgb(array) : null; 659 }, 660 661 rgbToHex: function(array){ 662 var rgb = String(this).match(/\d{1,3}/g); 663 return (rgb) ? rgb.rgbToHex(array) : null; 664 }, 665 666 substitute: function(object, regexp){ 667 return String(this).replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){ 668 if (match.charAt(0) == '\\') return match.slice(1); 669 return (object[name] != null) ? object[name] : ''; 670 }); 671 } 672 673 }); 674 675 676 677 678 /* 679 --- 680 681 name: Number 682 683 description: Contains Number Prototypes like limit, round, times, and ceil. 684 685 license: MIT-style license. 686 687 requires: Type 688 689 provides: Number 690 691 ... 692 */ 693 694 Number.implement({ 695 696 limit: function(min, max){ 697 return Math.min(max, Math.max(min, this)); 698 }, 699 700 round: function(precision){ 701 precision = Math.pow(10, precision || 0).toFixed(precision < 0 ? -precision : 0); 702 return Math.round(this * precision) / precision; 703 }, 704 705 times: function(fn, bind){ 706 for (var i = 0; i < this; i++) fn.call(bind, i, this); 707 }, 708 709 toFloat: function(){ 710 return parseFloat(this); 711 }, 712 713 toInt: function(base){ 714 return parseInt(this, base || 10); 715 } 716 717 }); 718 719 Number.alias('each', 'times'); 720 721 (function(math){ 722 var methods = {}; 723 math.each(function(name){ 724 if (!Number[name]) methods[name] = function(){ 725 return Math[name].apply(null, [this].concat(Array.from(arguments))); 726 }; 727 }); 728 Number.implement(methods); 729 })(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']); 730 731 732 /* 733 --- 734 735 name: Function 736 737 description: Contains Function Prototypes like create, bind, pass, and delay. 738 739 license: MIT-style license. 740 741 requires: Type 742 743 provides: Function 744 745 ... 746 */ 747 748 Function.extend({ 749 750 attempt: function(){ 751 for (var i = 0, l = arguments.length; i < l; i++){ 752 try { 753 return arguments[i](); 754 } catch (e){} 755 } 756 return null; 757 } 758 759 }); 760 761 Function.implement({ 762 763 attempt: function(args, bind){ 764 try { 765 return this.apply(bind, Array.from(args)); 766 } catch (e){} 767 768 return null; 769 }, 770 771 /*<!ES5-bind>*/ 772 bind: function(that){ 773 var self = this, 774 args = arguments.length > 1 ? Array.slice(arguments, 1) : null, 775 F = function(){}; 776 777 var bound = function(){ 778 var context = that, length = arguments.length; 779 if (this instanceof bound){ 780 F.prototype = self.prototype; 781 context = new F; 782 } 783 var result = (!args && !length) 784 ? self.call(context) 785 : self.apply(context, args && length ? args.concat(Array.slice(arguments)) : args || arguments); 786 return context == that ? result : context; 787 }; 788 return bound; 789 }, 790 /*</!ES5-bind>*/ 791 792 pass: function(args, bind){ 793 var self = this; 794 if (args != null) args = Array.from(args); 795 return function(){ 796 return self.apply(bind, args || arguments); 797 }; 798 }, 799 800 delay: function(delay, bind, args){ 801 return setTimeout(this.pass((args == null ? [] : args), bind), delay); 802 }, 803 804 periodical: function(periodical, bind, args){ 805 return setInterval(this.pass((args == null ? [] : args), bind), periodical); 806 } 807 808 }); 809 810 811 812 813 /* 814 --- 815 816 name: Object 817 818 description: Object generic methods 819 820 license: MIT-style license. 821 822 requires: Type 823 824 provides: [Object, Hash] 825 826 ... 827 */ 828 829 (function(){ 830 831 var hasOwnProperty = Object.prototype.hasOwnProperty; 832 833 Object.extend({ 834 835 subset: function(object, keys){ 836 var results = {}; 837 for (var i = 0, l = keys.length; i < l; i++){ 838 var k = keys[i]; 839 if (k in object) results[k] = object[k]; 840 } 841 return results; 842 }, 843 844 map: function(object, fn, bind){ 845 var results = {}; 846 for (var key in object){ 847 if (hasOwnProperty.call(object, key)) results[key] = fn.call(bind, object[key], key, object); 848 } 849 return results; 850 }, 851 852 filter: function(object, fn, bind){ 853 var results = {}; 854 for (var key in object){ 855 var value = object[key]; 856 if (hasOwnProperty.call(object, key) && fn.call(bind, value, key, object)) results[key] = value; 857 } 858 return results; 859 }, 860 861 every: function(object, fn, bind){ 862 for (var key in object){ 863 if (hasOwnProperty.call(object, key) && !fn.call(bind, object[key], key)) return false; 864 } 865 return true; 866 }, 867 868 some: function(object, fn, bind){ 869 for (var key in object){ 870 if (hasOwnProperty.call(object, key) && fn.call(bind, object[key], key)) return true; 871 } 872 return false; 873 }, 874 875 keys: function(object){ 876 var keys = []; 877 for (var key in object){ 878 if (hasOwnProperty.call(object, key)) keys.push(key); 879 } 880 return keys; 881 }, 882 883 values: function(object){ 884 var values = []; 885 for (var key in object){ 886 if (hasOwnProperty.call(object, key)) values.push(object[key]); 887 } 888 return values; 889 }, 890 891 getLength: function(object){ 892 return Object.keys(object).length; 893 }, 894 895 keyOf: function(object, value){ 896 for (var key in object){ 897 if (hasOwnProperty.call(object, key) && object[key] === value) return key; 898 } 899 return null; 900 }, 901 902 contains: function(object, value){ 903 return Object.keyOf(object, value) != null; 904 }, 905 906 toQueryString: function(object, base){ 907 var queryString = []; 908 909 Object.each(object, function(value, key){ 910 if (base) key = base + '[' + key + ']'; 911 var result; 912 switch (typeOf(value)){ 913 case 'object': result = Object.toQueryString(value, key); break; 914 case 'array': 915 var qs = {}; 916 value.each(function(val, i){ 917 qs[i] = val; 918 }); 919 result = Object.toQueryString(qs, key); 920 break; 921 default: result = key + '=' + encodeURIComponent(value); 922 } 923 if (value != null) queryString.push(result); 924 }); 925 926 return queryString.join('&'); 927 } 928 929 }); 930 931 })(); 932 933 934 935 936 /* 937 --- 938 939 name: Browser 940 941 description: The Browser Object. Contains Browser initialization, Window and Document, and the Browser Hash. 942 943 license: MIT-style license. 944 945 requires: [Array, Function, Number, String] 946 947 provides: [Browser, Window, Document] 948 949 ... 950 */ 951 952 (function(){ 953 954 var document = this.document; 955 var window = document.window = this; 956 957 var parse = function(ua, platform){ 958 ua = ua.toLowerCase(); 959 platform = (platform ? platform.toLowerCase() : ''); 960 961 var UA = ua.match(/(opera|ie|firefox|chrome|trident|crios|version)[\s\/:]([\w\d\.]+)?.*?(safari|(?:rv[\s\/:]|version[\s\/:])([\w\d\.]+)|$)/) || [null, 'unknown', 0]; 962 963 if (UA[1] == 'trident'){ 964 UA[1] = 'ie'; 965 if (UA[4]) UA[2] = UA[4]; 966 } else if (UA[1] == 'crios') { 967 UA[1] = 'chrome'; 968 } 969 970 var platform = ua.match(/ip(?:ad|od|hone)/) ? 'ios' : (ua.match(/(?:webos|android)/) || platform.match(/mac|win|linux/) || ['other'])[0]; 971 if (platform == 'win') platform = 'windows'; 972 973 return { 974 extend: Function.prototype.extend, 975 name: (UA[1] == 'version') ? UA[3] : UA[1], 976 version: parseFloat((UA[1] == 'opera' && UA[4]) ? UA[4] : UA[2]), 977 platform: platform 978 }; 979 }; 980 981 var Browser = this.Browser = parse(navigator.userAgent, navigator.platform); 982 983 if (Browser.ie){ 984 Browser.version = document.documentMode; 985 } 986 987 Browser.extend({ 988 Features: { 989 xpath: !!(document.evaluate), 990 air: !!(window.runtime), 991 query: !!(document.querySelector), 992 json: !!(window.JSON) 993 }, 994 parseUA: parse 995 }); 996 997 998 999 // Request 1000 1001 Browser.Request = (function(){ 1002 1003 var XMLHTTP = function(){ 1004 return new XMLHttpRequest(); 1005 }; 1006 1007 var MSXML2 = function(){ 1008 return new ActiveXObject('MSXML2.XMLHTTP'); 1009 }; 1010 1011 var MSXML = function(){ 1012 return new ActiveXObject('Microsoft.XMLHTTP'); 1013 }; 1014 1015 return Function.attempt(function(){ 1016 XMLHTTP(); 1017 return XMLHTTP; 1018 }, function(){ 1019 MSXML2(); 1020 return MSXML2; 1021 }, function(){ 1022 MSXML(); 1023 return MSXML; 1024 }); 1025 1026 })(); 1027 1028 Browser.Features.xhr = !!(Browser.Request); 1029 1030 1031 1032 // String scripts 1033 1034 Browser.exec = function(text){ 1035 if (!text) return text; 1036 if (window.execScript){ 1037 window.execScript(text); 1038 } else { 1039 var script = document.createElement('script'); 1040 script.setAttribute('type', 'text/javascript'); 1041 script.text = text; 1042 document.head.appendChild(script); 1043 document.head.removeChild(script); 1044 } 1045 return text; 1046 }; 1047 1048 String.implement('stripScripts', function(exec){ 1049 var scripts = ''; 1050 var text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(all, code){ 1051 scripts += code + '\n'; 1052 return ''; 1053 }); 1054 if (exec === true) Browser.exec(scripts); 1055 else if (typeOf(exec) == 'function') exec(scripts, text); 1056 return text; 1057 }); 1058 1059 // Window, Document 1060 1061 Browser.extend({ 1062 Document: this.Document, 1063 Window: this.Window, 1064 Element: this.Element, 1065 Event: this.Event 1066 }); 1067 1068 this.Window = this.$constructor = new Type('Window', function(){}); 1069 1070 this.$family = Function.from('window').hide(); 1071 1072 Window.mirror(function(name, method){ 1073 window[name] = method; 1074 }); 1075 1076 this.Document = document.$constructor = new Type('Document', function(){}); 1077 1078 document.$family = Function.from('document').hide(); 1079 1080 Document.mirror(function(name, method){ 1081 document[name] = method; 1082 }); 1083 1084 document.html = document.documentElement; 1085 if (!document.head) document.head = document.getElementsByTagName('head')[0]; 1086 1087 if (document.execCommand) try { 1088 document.execCommand("BackgroundImageCache", false, true); 1089 } catch (e){} 1090 1091 /*<ltIE9>*/ 1092 if (this.attachEvent && !this.addEventListener){ 1093 var unloadEvent = function(){ 1094 this.detachEvent('onunload', unloadEvent); 1095 document.head = document.html = document.window = null; 1096 }; 1097 this.attachEvent('onunload', unloadEvent); 1098 } 1099 1100 // IE fails on collections and <select>.options (refers to <select>) 1101 var arrayFrom = Array.from; 1102 try { 1103 arrayFrom(document.html.childNodes); 1104 } catch(e){ 1105 Array.from = function(item){ 1106 if (typeof item != 'string' && Type.isEnumerable(item) && typeOf(item) != 'array'){ 1107 var i = item.length, array = new Array(i); 1108 while (i--) array[i] = item[i]; 1109 return array; 1110 } 1111 return arrayFrom(item); 1112 }; 1113 1114 var prototype = Array.prototype, 1115 slice = prototype.slice; 1116 ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice'].each(function(name){ 1117 var method = prototype[name]; 1118 Array[name] = function(item){ 1119 return method.apply(Array.from(item), slice.call(arguments, 1)); 1120 }; 1121 }); 1122 } 1123 /*</ltIE9>*/ 1124 1125 1126 1127 })(); 1128 1129 1130 /* 1131 --- 1132 1133 name: Event 1134 1135 description: Contains the Event Type, to make the event object cross-browser. 1136 1137 license: MIT-style license. 1138 1139 requires: [Window, Document, Array, Function, String, Object] 1140 1141 provides: Event 1142 1143 ... 1144 */ 1145 1146 (function() { 1147 1148 var _keys = {}; 1149 1150 var DOMEvent = this.DOMEvent = new Type('DOMEvent', function(event, win){ 1151 if (!win) win = window; 1152 event = event || win.event; 1153 if (event.$extended) return event; 1154 this.event = event; 1155 this.$extended = true; 1156 this.shift = event.shiftKey; 1157 this.control = event.ctrlKey; 1158 this.alt = event.altKey; 1159 this.meta = event.metaKey; 1160 var type = this.type = event.type; 1161 var target = event.target || event.srcElement; 1162 while (target && target.nodeType == 3) target = target.parentNode; 1163 this.target = document.id(target); 1164 1165 if (type.indexOf('key') == 0){ 1166 var code = this.code = (event.which || event.keyCode); 1167 this.key = _keys[code]; 1168 if (type == 'keydown' || type == 'keyup'){ 1169 if (code > 111 && code < 124) this.key = 'f' + (code - 111); 1170 else if (code > 95 && code < 106) this.key = code - 96; 1171 } 1172 if (this.key == null) this.key = String.fromCharCode(code).toLowerCase(); 1173 } else if (type == 'click' || type == 'dblclick' || type == 'contextmenu' || type == 'DOMMouseScroll' || type.indexOf('mouse') == 0){ 1174 var doc = win.document; 1175 doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; 1176 this.page = { 1177 x: (event.pageX != null) ? event.pageX : event.clientX + doc.scrollLeft, 1178 y: (event.pageY != null) ? event.pageY : event.clientY + doc.scrollTop 1179 }; 1180 this.client = { 1181 x: (event.pageX != null) ? event.pageX - win.pageXOffset : event.clientX, 1182 y: (event.pageY != null) ? event.pageY - win.pageYOffset : event.clientY 1183 }; 1184 if (type == 'DOMMouseScroll' || type == 'mousewheel') 1185 this.wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3; 1186 1187 this.rightClick = (event.which == 3 || event.button == 2); 1188 if (type == 'mouseover' || type == 'mouseout'){ 1189 var related = event.relatedTarget || event[(type == 'mouseover' ? 'from' : 'to') + 'Element']; 1190 while (related && related.nodeType == 3) related = related.parentNode; 1191 this.relatedTarget = document.id(related); 1192 } 1193 } else if (type.indexOf('touch') == 0 || type.indexOf('gesture') == 0){ 1194 this.rotation = event.rotation; 1195 this.scale = event.scale; 1196 this.targetTouches = event.targetTouches; 1197 this.changedTouches = event.changedTouches; 1198 var touches = this.touches = event.touches; 1199 if (touches && touches[0]){ 1200 var touch = touches[0]; 1201 this.page = {x: touch.pageX, y: touch.pageY}; 1202 this.client = {x: touch.clientX, y: touch.clientY}; 1203 } 1204 } 1205 1206 if (!this.client) this.client = {}; 1207 if (!this.page) this.page = {}; 1208 }); 1209 1210 DOMEvent.implement({ 1211 1212 stop: function(){ 1213 return this.preventDefault().stopPropagation(); 1214 }, 1215 1216 stopPropagation: function(){ 1217 if (this.event.stopPropagation) this.event.stopPropagation(); 1218 else this.event.cancelBubble = true; 1219 return this; 1220 }, 1221 1222 preventDefault: function(){ 1223 if (this.event.preventDefault) this.event.preventDefault(); 1224 else this.event.returnValue = false; 1225 return this; 1226 } 1227 1228 }); 1229 1230 DOMEvent.defineKey = function(code, key){ 1231 _keys[code] = key; 1232 return this; 1233 }; 1234 1235 DOMEvent.defineKeys = DOMEvent.defineKey.overloadSetter(true); 1236 1237 DOMEvent.defineKeys({ 1238 '38': 'up', '40': 'down', '37': 'left', '39': 'right', 1239 '27': 'esc', '32': 'space', '8': 'backspace', '9': 'tab', 1240 '46': 'delete', '13': 'enter' 1241 }); 1242 1243 })(); 1244 1245 1246 1247 1248 1249 1250 /* 1251 --- 1252 1253 name: Class 1254 1255 description: Contains the Class Function for easily creating, extending, and implementing reusable Classes. 1256 1257 license: MIT-style license. 1258 1259 requires: [Array, String, Function, Number] 1260 1261 provides: Class 1262 1263 ... 1264 */ 1265 1266 (function(){ 1267 1268 var Class = this.Class = new Type('Class', function(params){ 1269 if (instanceOf(params, Function)) params = {initialize: params}; 1270 1271 var newClass = function(){ 1272 reset(this); 1273 if (newClass.$prototyping) return this; 1274 this.$caller = null; 1275 var value = (this.initialize) ? this.initialize.apply(this, arguments) : this; 1276 this.$caller = this.caller = null; 1277 return value; 1278 }.extend(this).implement(params); 1279 1280 newClass.$constructor = Class; 1281 newClass.prototype.$constructor = newClass; 1282 newClass.prototype.parent = parent; 1283 1284 return newClass; 1285 }); 1286 1287 var parent = function(){ 1288 if (!this.$caller) throw new Error('The method "parent" cannot be called.'); 1289 var name = this.$caller.$name, 1290 parent = this.$caller.$owner.parent, 1291 previous = (parent) ? parent.prototype[name] : null; 1292 if (!previous) throw new Error('The method "' + name + '" has no parent.'); 1293 return previous.apply(this, arguments); 1294 }; 1295 1296 var reset = function(object){ 1297 for (var key in object){ 1298 var value = object[key]; 1299 switch (typeOf(value)){ 1300 case 'object': 1301 var F = function(){}; 1302 F.prototype = value; 1303 object[key] = reset(new F); 1304 break; 1305 case 'array': object[key] = value.clone(); break; 1306 } 1307 } 1308 return object; 1309 }; 1310 1311 var wrap = function(self, key, method){ 1312 if (method.$origin) method = method.$origin; 1313 var wrapper = function(){ 1314 if (method.$protected && this.$caller == null) throw new Error('The method "' + key + '" cannot be called.'); 1315 var caller = this.caller, current = this.$caller; 1316 this.caller = current; this.$caller = wrapper; 1317 var result = method.apply(this, arguments); 1318 this.$caller = current; this.caller = caller; 1319 return result; 1320 }.extend({$owner: self, $origin: method, $name: key}); 1321 return wrapper; 1322 }; 1323 1324 var implement = function(key, value, retain){ 1325 if (Class.Mutators.hasOwnProperty(key)){ 1326 value = Class.Mutators[key].call(this, value); 1327 if (value == null) return this; 1328 } 1329 1330 if (typeOf(value) == 'function'){ 1331 if (value.$hidden) return this; 1332 this.prototype[key] = (retain) ? value : wrap(this, key, value); 1333 } else { 1334 Object.merge(this.prototype, key, value); 1335 } 1336 1337 return this; 1338 }; 1339 1340 var getInstance = function(klass){ 1341 klass.$prototyping = true; 1342 var proto = new klass; 1343 delete klass.$prototyping; 1344 return proto; 1345 }; 1346 1347 Class.implement('implement', implement.overloadSetter()); 1348 1349 Class.Mutators = { 1350 1351 Extends: function(parent){ 1352 this.parent = parent; 1353 this.prototype = getInstance(parent); 1354 }, 1355 1356 Implements: function(items){ 1357 Array.from(items).each(function(item){ 1358 var instance = new item; 1359 for (var key in instance) implement.call(this, key, instance[key], true); 1360 }, this); 1361 } 1362 }; 1363 1364 })(); 1365 1366 1367 /* 1368 --- 1369 1370 name: Class.Extras 1371 1372 description: Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks. 1373 1374 license: MIT-style license. 1375 1376 requires: Class 1377 1378 provides: [Class.Extras, Chain, Events, Options] 1379 1380 ... 1381 */ 1382 1383 (function(){ 1384 1385 this.Chain = new Class({ 1386 1387 $chain: [], 1388 1389 chain: function(){ 1390 this.$chain.append(Array.flatten(arguments)); 1391 return this; 1392 }, 1393 1394 callChain: function(){ 1395 return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false; 1396 }, 1397 1398 clearChain: function(){ 1399 this.$chain.empty(); 1400 return this; 1401 } 1402 1403 }); 1404 1405 var removeOn = function(string){ 1406 return string.replace(/^on([A-Z])/, function(full, first){ 1407 return first.toLowerCase(); 1408 }); 1409 }; 1410 1411 this.Events = new Class({ 1412 1413 $events: {}, 1414 1415 addEvent: function(type, fn, internal){ 1416 type = removeOn(type); 1417 1418 1419 1420 this.$events[type] = (this.$events[type] || []).include(fn); 1421 if (internal) fn.internal = true; 1422 return this; 1423 }, 1424 1425 addEvents: function(events){ 1426 for (var type in events) this.addEvent(type, events[type]); 1427 return this; 1428 }, 1429 1430 fireEvent: function(type, args, delay){ 1431 type = removeOn(type); 1432 var events = this.$events[type]; 1433 if (!events) return this; 1434 args = Array.from(args); 1435 events.each(function(fn){ 1436 if (delay) fn.delay(delay, this, args); 1437 else fn.apply(this, args); 1438 }, this); 1439 return this; 1440 }, 1441 1442 removeEvent: function(type, fn){ 1443 type = removeOn(type); 1444 var events = this.$events[type]; 1445 if (events && !fn.internal){ 1446 var index = events.indexOf(fn); 1447 if (index != -1) delete events[index]; 1448 } 1449 return this; 1450 }, 1451 1452 removeEvents: function(events){ 1453 var type; 1454 if (typeOf(events) == 'object'){ 1455 for (type in events) this.removeEvent(type, events[type]); 1456 return this; 1457 } 1458 if (events) events = removeOn(events); 1459 for (type in this.$events){ 1460 if (events && events != type) continue; 1461 var fns = this.$events[type]; 1462 for (var i = fns.length; i--;) if (i in fns){ 1463 this.removeEvent(type, fns[i]); 1464 } 1465 } 1466 return this; 1467 } 1468 1469 }); 1470 1471 this.Options = new Class({ 1472 1473 setOptions: function(){ 1474 var options = this.options = Object.merge.apply(null, [{}, this.options].append(arguments)); 1475 if (this.addEvent) for (var option in options){ 1476 if (typeOf(options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue; 1477 this.addEvent(option, options[option]); 1478 delete options[option]; 1479 } 1480 return this; 1481 } 1482 1483 }); 1484 1485 })(); 1486 1487 1488 /* 1489 --- 1490 name: Slick.Parser 1491 description: Standalone CSS3 Selector parser 1492 provides: Slick.Parser 1493 ... 1494 */ 1495 1496 ;(function(){ 1497 1498 var parsed, 1499 separatorIndex, 1500 combinatorIndex, 1501 reversed, 1502 cache = {}, 1503 reverseCache = {}, 1504 reUnescape = /\\/g; 1505 1506 var parse = function(expression, isReversed){ 1507 if (expression == null) return null; 1508 if (expression.Slick === true) return expression; 1509 expression = ('' + expression).replace(/^\s+|\s+$/g, ''); 1510 reversed = !!isReversed; 1511 var currentCache = (reversed) ? reverseCache : cache; 1512 if (currentCache[expression]) return currentCache[expression]; 1513 parsed = { 1514 Slick: true, 1515 expressions: [], 1516 raw: expression, 1517 reverse: function(){ 1518 return parse(this.raw, true); 1519 } 1520 }; 1521 separatorIndex = -1; 1522 while (expression != (expression = expression.replace(regexp, parser))); 1523 parsed.length = parsed.expressions.length; 1524 return currentCache[parsed.raw] = (reversed) ? reverse(parsed) : parsed; 1525 }; 1526 1527 var reverseCombinator = function(combinator){ 1528 if (combinator === '!') return ' '; 1529 else if (combinator === ' ') return '!'; 1530 else if ((/^!/).test(combinator)) return combinator.replace(/^!/, ''); 1531 else return '!' + combinator; 1532 }; 1533 1534 var reverse = function(expression){ 1535 var expressions = expression.expressions; 1536 for (var i = 0; i < expressions.length; i++){ 1537 var exp = expressions[i]; 1538 var last = {parts: [], tag: '*', combinator: reverseCombinator(exp[0].combinator)}; 1539 1540 for (var j = 0; j < exp.length; j++){ 1541 var cexp = exp[j]; 1542 if (!cexp.reverseCombinator) cexp.reverseCombinator = ' '; 1543 cexp.combinator = cexp.reverseCombinator; 1544 delete cexp.reverseCombinator; 1545 } 1546 1547 exp.reverse().push(last); 1548 } 1549 return expression; 1550 }; 1551 1552 var escapeRegExp = function(string){// Credit: XRegExp 0.6.1 (c) 2007-2008 Steven Levithan <http://stevenlevithan.com/regex/xregexp/> MIT License 1553 return string.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, function(match){ 1554 return '\\' + match; 1555 }); 1556 }; 1557 1558 var regexp = new RegExp( 1559 /* 1560 #!/usr/bin/env ruby 1561 puts "\t\t" + DATA.read.gsub(/\(\?x\)|\s+#.*$|\s+|\\$|\\n/,'') 1562 __END__ 1563 "(?x)^(?:\ 1564 \\s* ( , ) \\s* # Separator \n\ 1565 | \\s* ( <combinator>+ ) \\s* # Combinator \n\ 1566 | ( \\s+ ) # CombinatorChildren \n\ 1567 | ( <unicode>+ | \\* ) # Tag \n\ 1568 | \\# ( <unicode>+ ) # ID \n\ 1569 | \\. ( <unicode>+ ) # ClassName \n\ 1570 | # Attribute \n\ 1571 \\[ \ 1572 \\s* (<unicode1>+) (?: \ 1573 \\s* ([*^$!~|]?=) (?: \ 1574 \\s* (?:\ 1575 ([\"']?)(.*?)\\9 \ 1576 )\ 1577 ) \ 1578 )? \\s* \ 1579 \\](?!\\]) \n\ 1580 | :+ ( <unicode>+ )(?:\ 1581 \\( (?:\ 1582 (?:([\"'])([^\\12]*)\\12)|((?:\\([^)]+\\)|[^()]*)+)\ 1583 ) \\)\ 1584 )?\ 1585 )" 1586 */ 1587 "^(?:\\s*(,)\\s*|\\s*(<combinator>+)\\s*|(\\s+)|(<unicode>+|\\*)|\\#(<unicode>+)|\\.(<unicode>+)|\\[\\s*(<unicode1>+)(?:\\s*([*^$!~|]?=)(?:\\s*(?:([\"']?)(.*?)\\9)))?\\s*\\](?!\\])|(:+)(<unicode>+)(?:\\((?:(?:([\"'])([^\\13]*)\\13)|((?:\\([^)]+\\)|[^()]*)+))\\))?)" 1588 .replace(/<combinator>/, '[' + escapeRegExp(">+~`!@$%^&={}\\;</") + ']') 1589 .replace(/<unicode>/g, '(?:[\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])') 1590 .replace(/<unicode1>/g, '(?:[:\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])') 1591 ); 1592 1593 function parser( 1594 rawMatch, 1595 1596 separator, 1597 combinator, 1598 combinatorChildren, 1599 1600 tagName, 1601 id, 1602 className, 1603 1604 attributeKey, 1605 attributeOperator, 1606 attributeQuote, 1607 attributeValue, 1608 1609 pseudoMarker, 1610 pseudoClass, 1611 pseudoQuote, 1612 pseudoClassQuotedValue, 1613 pseudoClassValue 1614 ){ 1615 if (separator || separatorIndex === -1){ 1616 parsed.expressions[++separatorIndex] = []; 1617 combinatorIndex = -1; 1618 if (separator) return ''; 1619 } 1620 1621 if (combinator || combinatorChildren || combinatorIndex === -1){ 1622 combinator = combinator || ' '; 1623 var currentSeparator = parsed.expressions[separatorIndex]; 1624 if (reversed && currentSeparator[combinatorIndex]) 1625 currentSeparator[combinatorIndex].reverseCombinator = reverseCombinator(combinator); 1626 currentSeparator[++combinatorIndex] = {combinator: combinator, tag: '*'}; 1627 } 1628 1629 var currentParsed = parsed.expressions[separatorIndex][combinatorIndex]; 1630 1631 if (tagName){ 1632 currentParsed.tag = tagName.replace(reUnescape, ''); 1633 1634 } else if (id){ 1635 currentParsed.id = id.replace(reUnescape, ''); 1636 1637 } else if (className){ 1638 className = className.replace(reUnescape, ''); 1639 1640 if (!currentParsed.classList) currentParsed.classList = []; 1641 if (!currentParsed.classes) currentParsed.classes = []; 1642 currentParsed.classList.push(className); 1643 currentParsed.classes.push({ 1644 value: className, 1645 regexp: new RegExp('(^|\\s)' + escapeRegExp(className) + '(\\s|$)') 1646 }); 1647 1648 } else if (pseudoClass){ 1649 pseudoClassValue = pseudoClassValue || pseudoClassQuotedValue; 1650 pseudoClassValue = pseudoClassValue ? pseudoClassValue.replace(reUnescape, '') : null; 1651 1652 if (!currentParsed.pseudos) currentParsed.pseudos = []; 1653 currentParsed.pseudos.push({ 1654 key: pseudoClass.replace(reUnescape, ''), 1655 value: pseudoClassValue, 1656 type: pseudoMarker.length == 1 ? 'class' : 'element' 1657 }); 1658 1659 } else if (attributeKey){ 1660 attributeKey = attributeKey.replace(reUnescape, ''); 1661 attributeValue = (attributeValue || '').replace(reUnescape, ''); 1662 1663 var test, regexp; 1664 1665 switch (attributeOperator){ 1666 case '^=' : regexp = new RegExp( '^'+ escapeRegExp(attributeValue) ); break; 1667 case '$=' : regexp = new RegExp( escapeRegExp(attributeValue) +'$' ); break; 1668 case '~=' : regexp = new RegExp( '(^|\\s)'+ escapeRegExp(attributeValue) +'(\\s|$)' ); break; 1669 case '|=' : regexp = new RegExp( '^'+ escapeRegExp(attributeValue) +'(-|$)' ); break; 1670 case '=' : test = function(value){ 1671 return attributeValue == value; 1672 }; break; 1673 case '*=' : test = function(value){ 1674 return value && value.indexOf(attributeValue) > -1; 1675 }; break; 1676 case '!=' : test = function(value){ 1677 return attributeValue != value; 1678 }; break; 1679 default : test = function(value){ 1680 return !!value; 1681 }; 1682 } 1683 1684 if (attributeValue == '' && (/^[*$^]=$/).test(attributeOperator)) test = function(){ 1685 return false; 1686 }; 1687 1688 if (!test) test = function(value){ 1689 return value && regexp.test(value); 1690 }; 1691 1692 if (!currentParsed.attributes) currentParsed.attributes = []; 1693 currentParsed.attributes.push({ 1694 key: attributeKey, 1695 operator: attributeOperator, 1696 value: attributeValue, 1697 test: test 1698 }); 1699 1700 } 1701 1702 return ''; 1703 }; 1704 1705 // Slick NS 1706 1707 var Slick = (this.Slick || {}); 1708 1709 Slick.parse = function(expression){ 1710 return parse(expression); 1711 }; 1712 1713 Slick.escapeRegExp = escapeRegExp; 1714 1715 if (!this.Slick) this.Slick = Slick; 1716 1717 }).apply(/*<CommonJS>*/(typeof exports != 'undefined') ? exports : /*</CommonJS>*/this); 1718 1719 1720 /* 1721 --- 1722 name: Slick.Finder 1723 description: The new, superfast css selector engine. 1724 provides: Slick.Finder 1725 requires: Slick.Parser 1726 ... 1727 */ 1728 1729 ;(function(){ 1730 1731 var local = {}, 1732 featuresCache = {}, 1733 toString = Object.prototype.toString; 1734 1735 // Feature / Bug detection 1736 1737 local.isNativeCode = function(fn){ 1738 return (/\{\s*\[native code\]\s*\}/).test('' + fn); 1739 }; 1740 1741 local.isXML = function(document){ 1742 return (!!document.xmlVersion) || (!!document.xml) || (toString.call(document) == '[object XMLDocument]') || 1743 (document.nodeType == 9 && document.documentElement.nodeName != 'HTML'); 1744 }; 1745 1746 local.setDocument = function(document){ 1747 1748 // convert elements / window arguments to document. if document cannot be extrapolated, the function returns. 1749 var nodeType = document.nodeType; 1750 if (nodeType == 9); // document 1751 else if (nodeType) document = document.ownerDocument; // node 1752 else if (document.navigator) document = document.document; // window 1753 else return; 1754 1755 // check if it's the old document 1756 1757 if (this.document === document) return; 1758 this.document = document; 1759 1760 // check if we have done feature detection on this document before 1761 1762 var root = document.documentElement, 1763 rootUid = this.getUIDXML(root), 1764 features = featuresCache[rootUid], 1765 feature; 1766 1767 if (features){ 1768 for (feature in features){ 1769 this[feature] = features[feature]; 1770 } 1771 return; 1772 } 1773 1774 features = featuresCache[rootUid] = {}; 1775 1776 features.root = root; 1777 features.isXMLDocument = this.isXML(document); 1778 1779 features.brokenStarGEBTN 1780 = features.starSelectsClosedQSA 1781 = features.idGetsName 1782 = features.brokenMixedCaseQSA 1783 = features.brokenGEBCN 1784 = features.brokenCheckedQSA 1785 = features.brokenEmptyAttributeQSA 1786 = features.isHTMLDocument 1787 = features.nativeMatchesSelector 1788 = false; 1789 1790 var starSelectsClosed, starSelectsComments, 1791 brokenSecondClassNameGEBCN, cachedGetElementsByClassName, 1792 brokenFormAttributeGetter; 1793 1794 var selected, id = 'slick_uniqueid'; 1795 var testNode = document.createElement('div'); 1796 1797 var testRoot = document.body || document.getElementsByTagName('body')[0] || root; 1798 testRoot.appendChild(testNode); 1799 1800 // on non-HTML documents innerHTML and getElementsById doesnt work properly 1801 try { 1802 testNode.innerHTML = '<a id="'+id+'"></a>'; 1803 features.isHTMLDocument = !!document.getElementById(id); 1804 } catch(e){}; 1805 1806 if (features.isHTMLDocument){ 1807 1808 testNode.style.display = 'none'; 1809 1810 // IE returns comment nodes for getElementsByTagName('*') for some documents 1811 testNode.appendChild(document.createComment('')); 1812 starSelectsComments = (testNode.getElementsByTagName('*').length > 1); 1813 1814 // IE returns closed nodes (EG:"</foo>") for getElementsByTagName('*') for some documents 1815 try { 1816 testNode.innerHTML = 'foo</foo>'; 1817 selected = testNode.getElementsByTagName('*'); 1818 starSelectsClosed = (selected && !!selected.length && selected[0].nodeName.charAt(0) == '/'); 1819 } catch(e){}; 1820 1821 features.brokenStarGEBTN = starSelectsComments || starSelectsClosed; 1822 1823 // IE returns elements with the name instead of just id for getElementsById for some documents 1824 try { 1825 testNode.innerHTML = '<a name="'+ id +'"></a><b id="'+ id +'"></b>'; 1826 features.idGetsName = document.getElementById(id) === testNode.firstChild; 1827 } catch(e){}; 1828 1829 if (testNode.getElementsByClassName){ 1830 1831 // Safari 3.2 getElementsByClassName caches results 1832 try { 1833 testNode.innerHTML = '<a class="f"></a><a class="b"></a>'; 1834 testNode.getElementsByClassName('b').length; 1835 testNode.firstChild.className = 'b'; 1836 cachedGetElementsByClassName = (testNode.getElementsByClassName('b').length != 2); 1837 } catch(e){}; 1838 1839 // Opera 9.6 getElementsByClassName doesnt detects the class if its not the first one 1840 try { 1841 testNode.innerHTML = '<a class="a"></a><a class="f b a"></a>'; 1842 brokenSecondClassNameGEBCN = (testNode.getElementsByClassName('a').length != 2); 1843 } catch(e){}; 1844 1845 features.brokenGEBCN = cachedGetElementsByClassName || brokenSecondClassNameGEBCN; 1846 } 1847 1848 if (testNode.querySelectorAll){ 1849 // IE 8 returns closed nodes (EG:"</foo>") for querySelectorAll('*') for some documents 1850 try { 1851 testNode.innerHTML = 'foo</foo>'; 1852 selected = testNode.querySelectorAll('*'); 1853 features.starSelectsClosedQSA = (selected && !!selected.length && selected[0].nodeName.charAt(0) == '/'); 1854 } catch(e){}; 1855 1856 // Safari 3.2 querySelectorAll doesnt work with mixedcase on quirksmode 1857 try { 1858 testNode.innerHTML = '<a class="MiX"></a>'; 1859 features.brokenMixedCaseQSA = !testNode.querySelectorAll('.MiX').length; 1860 } catch(e){}; 1861 1862 // Webkit and Opera dont return selected options on querySelectorAll 1863 try { 1864 testNode.innerHTML = '<select><option selected="selected">a</option></select>'; 1865 features.brokenCheckedQSA = (testNode.querySelectorAll(':checked').length == 0); 1866 } catch(e){}; 1867 1868 // IE returns incorrect results for attr[*^$]="" selectors on querySelectorAll 1869 try { 1870 testNode.innerHTML = '<a class=""></a>'; 1871 features.brokenEmptyAttributeQSA = (testNode.querySelectorAll('[class*=""]').length != 0); 1872 } catch(e){}; 1873 1874 } 1875 1876 // IE6-7, if a form has an input of id x, form.getAttribute(x) returns a reference to the input 1877 try { 1878 testNode.innerHTML = '<form action="s"><input id="action"/></form>'; 1879 brokenFormAttributeGetter = (testNode.firstChild.getAttribute('action') != 's'); 1880 } catch(e){}; 1881 1882 // native matchesSelector function 1883 1884 features.nativeMatchesSelector = root.matches || /*root.msMatchesSelector ||*/ root.mozMatchesSelector || root.webkitMatchesSelector; 1885 if (features.nativeMatchesSelector) try { 1886 // if matchesSelector trows errors on incorrect sintaxes we can use it 1887 features.nativeMatchesSelector.call(root, ':slick'); 1888 features.nativeMatchesSelector = null; 1889 } catch(e){}; 1890 1891 } 1892 1893 try { 1894 root.slick_expando = 1; 1895 delete root.slick_expando; 1896 features.getUID = this.getUIDHTML; 1897 } catch(e) { 1898 features.getUID = this.getUIDXML; 1899 } 1900 1901 testRoot.removeChild(testNode); 1902 testNode = selected = testRoot = null; 1903 1904 // getAttribute 1905 1906 features.getAttribute = (features.isHTMLDocument && brokenFormAttributeGetter) ? function(node, name){ 1907 var method = this.attributeGetters[name]; 1908 if (method) return method.call(node); 1909 var attributeNode = node.getAttributeNode(name); 1910 return (attributeNode) ? attributeNode.nodeValue : null; 1911 } : function(node, name){ 1912 var method = this.attributeGetters[name]; 1913 return (method) ? method.call(node) : node.getAttribute(name); 1914 }; 1915 1916 // hasAttribute 1917 1918 features.hasAttribute = (root && this.isNativeCode(root.hasAttribute)) ? function(node, attribute) { 1919 return node.hasAttribute(attribute); 1920 } : function(node, attribute) { 1921 node = node.getAttributeNode(attribute); 1922 return !!(node && (node.specified || node.nodeValue)); 1923 }; 1924 1925 // contains 1926 // FIXME: Add specs: local.contains should be different for xml and html documents? 1927 var nativeRootContains = root && this.isNativeCode(root.contains), 1928 nativeDocumentContains = document && this.isNativeCode(document.contains); 1929 1930 features.contains = (nativeRootContains && nativeDocumentContains) ? function(context, node){ 1931 return context.contains(node); 1932 } : (nativeRootContains && !nativeDocumentContains) ? function(context, node){ 1933 // IE8 does not have .contains on document. 1934 return context === node || ((context === document) ? document.documentElement : context).contains(node); 1935 } : (root && root.compareDocumentPosition) ? function(context, node){ 1936 return context === node || !!(context.compareDocumentPosition(node) & 16); 1937 } : function(context, node){ 1938 if (node) do { 1939 if (node === context) return true; 1940 } while ((node = node.parentNode)); 1941 return false; 1942 }; 1943 1944 // document order sorting 1945 // credits to Sizzle (http://sizzlejs.com/) 1946 1947 features.documentSorter = (root.compareDocumentPosition) ? function(a, b){ 1948 if (!a.compareDocumentPosition || !b.compareDocumentPosition) return 0; 1949 return a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; 1950 } : ('sourceIndex' in root) ? function(a, b){ 1951 if (!a.sourceIndex || !b.sourceIndex) return 0; 1952 return a.sourceIndex - b.sourceIndex; 1953 } : (document.createRange) ? function(a, b){ 1954 if (!a.ownerDocument || !b.ownerDocument) return 0; 1955 var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); 1956 aRange.setStart(a, 0); 1957 aRange.setEnd(a, 0); 1958 bRange.setStart(b, 0); 1959 bRange.setEnd(b, 0); 1960 return aRange.compareBoundaryPoints(Range.START_TO_END, bRange); 1961 } : null ; 1962 1963 root = null; 1964 1965 for (feature in features){ 1966 this[feature] = features[feature]; 1967 } 1968 }; 1969 1970 // Main Method 1971 1972 var reSimpleSelector = /^([#.]?)((?:[\w-]+|\*))$/, 1973 reEmptyAttribute = /\[.+[*$^]=(?:""|'')?\]/, 1974 qsaFailExpCache = {}; 1975 1976 local.search = function(context, expression, append, first){ 1977 1978 var found = this.found = (first) ? null : (append || []); 1979 1980 if (!context) return found; 1981 else if (context.navigator) context = context.document; // Convert the node from a window to a document 1982 else if (!context.nodeType) return found; 1983 1984 // setup 1985 1986 var parsed, i, 1987 uniques = this.uniques = {}, 1988 hasOthers = !!(append && append.length), 1989 contextIsDocument = (context.nodeType == 9); 1990 1991 if (this.document !== (contextIsDocument ? context : context.ownerDocument)) this.setDocument(context); 1992 1993 // avoid duplicating items already in the append array 1994 if (hasOthers) for (i = found.length; i--;) uniques[this.getUID(found[i])] = true; 1995 1996 // expression checks 1997 1998 if (typeof expression == 'string'){ // expression is a string 1999 2000 /*<simple-selectors-override>*/ 2001 var simpleSelector = expression.match(reSimpleSelector); 2002 simpleSelectors: if (simpleSelector) { 2003 2004 var symbol = simpleSelector[1], 2005 name = simpleSelector[2], 2006 node, nodes; 2007 2008 if (!symbol){ 2009 2010 if (name == '*' && this.brokenStarGEBTN) break simpleSelectors; 2011 nodes = context.getElementsByTagName(name); 2012 if (first) return nodes[0] || null; 2013 for (i = 0; node = nodes[i++];){ 2014 if (!(hasOthers && uniques[this.getUID(node)])) found.push(node); 2015 } 2016 2017 } else if (symbol == '#'){ 2018 2019 if (!this.isHTMLDocument || !contextIsDocument) break simpleSelectors; 2020 node = context.getElementById(name); 2021 if (!node) return found; 2022 if (this.idGetsName && node.getAttributeNode('id').nodeValue != name) break simpleSelectors; 2023 if (first) return node || null; 2024 if (!(hasOthers && uniques[this.getUID(node)])) found.push(node); 2025 2026 } else if (symbol == '.'){ 2027 2028 if (!this.isHTMLDocument || ((!context.getElementsByClassName || this.brokenGEBCN) && context.querySelectorAll)) break simpleSelectors; 2029 if (context.getElementsByClassName && !this.brokenGEBCN){ 2030 nodes = context.getElementsByClassName(name); 2031 if (first) return nodes[0] || null; 2032 for (i = 0; node = nodes[i++];){ 2033 if (!(hasOthers && uniques[this.getUID(node)])) found.push(node); 2034 } 2035 } else { 2036 var matchClass = new RegExp('(^|\\s)'+ Slick.escapeRegExp(name) +'(\\s|$)'); 2037 nodes = context.getElementsByTagName('*'); 2038 for (i = 0; node = nodes[i++];){ 2039 className = node.className; 2040 if (!(className && matchClass.test(className))) continue; 2041 if (first) return node; 2042 if (!(hasOthers && uniques[this.getUID(node)])) found.push(node); 2043 } 2044 } 2045 2046 } 2047 2048 if (hasOthers) this.sort(found); 2049 return (first) ? null : found; 2050 2051 } 2052 /*</simple-selectors-override>*/ 2053 2054 /*<query-selector-override>*/ 2055 querySelector: if (context.querySelectorAll) { 2056 2057 if (!this.isHTMLDocument 2058 || qsaFailExpCache[expression] 2059 //TODO: only skip when expression is actually mixed case 2060 || this.brokenMixedCaseQSA 2061 || (this.brokenCheckedQSA && expression.indexOf(':checked') > -1) 2062 || (this.brokenEmptyAttributeQSA && reEmptyAttribute.test(expression)) 2063 || (!contextIsDocument //Abort when !contextIsDocument and... 2064 // there are multiple expressions in the selector 2065 // since we currently only fix non-document rooted QSA for single expression selectors 2066 && expression.indexOf(',') > -1 2067 ) 2068 || Slick.disableQSA 2069 ) break querySelector; 2070 2071 var _expression = expression, _context = context; 2072 if (!contextIsDocument){ 2073 // non-document rooted QSA 2074 // credits to Andrew Dupont 2075 var currentId = _context.getAttribute('id'), slickid = 'slickid__'; 2076 _context.setAttribute('id', slickid); 2077 _expression = '#' + slickid + ' ' + _expression; 2078 context = _context.parentNode; 2079 } 2080 2081 try { 2082 if (first) return context.querySelector(_expression) || null; 2083 else nodes = context.querySelectorAll(_expression); 2084 } catch(e) { 2085 qsaFailExpCache[expression] = 1; 2086 break querySelector; 2087 } finally { 2088 if (!contextIsDocument){ 2089 if (currentId) _context.setAttribute('id', currentId); 2090 else _context.removeAttribute('id'); 2091 context = _context; 2092 } 2093 } 2094 2095 if (this.starSelectsClosedQSA) for (i = 0; node = nodes[i++];){ 2096 if (node.nodeName > '@' && !(hasOthers && uniques[this.getUID(node)])) found.push(node); 2097 } else for (i = 0; node = nodes[i++];){ 2098 if (!(hasOthers && uniques[this.getUID(node)])) found.push(node); 2099 } 2100 2101 if (hasOthers) this.sort(found); 2102 return found; 2103 2104 } 2105 /*</query-selector-override>*/ 2106 2107 parsed = this.Slick.parse(expression); 2108 if (!parsed.length) return found; 2109 } else if (expression == null){ // there is no expression 2110 return found; 2111 } else if (expression.Slick){ // expression is a parsed Slick object 2112 parsed = expression; 2113 } else if (this.contains(context.documentElement || context, expression)){ // expression is a node 2114 (found) ? found.push(expression) : found = expression; 2115 return found; 2116 } else { // other junk 2117 return found; 2118 } 2119 2120 /*<pseudo-selectors>*//*<nth-pseudo-selectors>*/ 2121 2122 // cache elements for the nth selectors 2123 2124 this.posNTH = {}; 2125 this.posNTHLast = {}; 2126 this.posNTHType = {}; 2127 this.posNTHTypeLast = {}; 2128 2129 /*</nth-pseudo-selectors>*//*</pseudo-selectors>*/ 2130 2131 // if append is null and there is only a single selector with one expression use pushArray, else use pushUID 2132 this.push = (!hasOthers && (first || (parsed.length == 1 && parsed.expressions[0].length == 1))) ? this.pushArray : this.pushUID; 2133 2134 if (found == null) found = []; 2135 2136 // default engine 2137 2138 var j, m, n; 2139 var combinator, tag, id, classList, classes, attributes, pseudos; 2140 var currentItems, currentExpression, currentBit, lastBit, expressions = parsed.expressions; 2141 2142 search: for (i = 0; (currentExpression = expressions[i]); i++) for (j = 0; (currentBit = currentExpression[j]); j++){ 2143 2144 combinator = 'combinator:' + currentBit.combinator; 2145 if (!this[combinator]) continue search; 2146 2147 tag = (this.isXMLDocument) ? currentBit.tag : currentBit.tag.toUpperCase(); 2148 id = currentBit.id; 2149 classList = currentBit.classList; 2150 classes = currentBit.classes; 2151 attributes = currentBit.attributes; 2152 pseudos = currentBit.pseudos; 2153 lastBit = (j === (currentExpression.length - 1)); 2154 2155 this.bitUniques = {}; 2156 2157 if (lastBit){ 2158 this.uniques = uniques; 2159 this.found = found; 2160 } else { 2161 this.uniques = {}; 2162 this.found = []; 2163 } 2164 2165 if (j === 0){ 2166 this[combinator](context, tag, id, classes, attributes, pseudos, classList); 2167 if (first && lastBit && found.length) break search; 2168 } else { 2169 if (first && lastBit) for (m = 0, n = currentItems.length; m < n; m++){ 2170 this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList); 2171 if (found.length) break search; 2172 } else for (m = 0, n = currentItems.length; m < n; m++) this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList); 2173 } 2174 2175 currentItems = this.found; 2176 } 2177 2178 // should sort if there are nodes in append and if you pass multiple expressions. 2179 if (hasOthers || (parsed.expressions.length > 1)) this.sort(found); 2180 2181 return (first) ? (found[0] || null) : found; 2182 }; 2183 2184 // Utils 2185 2186 local.uidx = 1; 2187 local.uidk = 'slick-uniqueid'; 2188 2189 local.getUIDXML = function(node){ 2190 var uid = node.getAttribute(this.uidk); 2191 if (!uid){ 2192 uid = this.uidx++; 2193 node.setAttribute(this.uidk, uid); 2194 } 2195 return uid; 2196 }; 2197 2198 local.getUIDHTML = function(node){ 2199 return node.uniqueNumber || (node.uniqueNumber = this.uidx++); 2200 }; 2201 2202 // sort based on the setDocument documentSorter method. 2203 2204 local.sort = function(results){ 2205 if (!this.documentSorter) return results; 2206 results.sort(this.documentSorter); 2207 return results; 2208 }; 2209 2210 /*<pseudo-selectors>*//*<nth-pseudo-selectors>*/ 2211 2212 local.cacheNTH = {}; 2213 2214 local.matchNTH = /^([+-]?\d*)?([a-z]+)?([+-]\d+)?$/; 2215 2216 local.parseNTHArgument = function(argument){ 2217 var parsed = argument.match(this.matchNTH); 2218 if (!parsed) return false; 2219 var special = parsed[2] || false; 2220 var a = parsed[1] || 1; 2221 if (a == '-') a = -1; 2222 var b = +parsed[3] || 0; 2223 parsed = 2224 (special == 'n') ? {a: a, b: b} : 2225 (special == 'odd') ? {a: 2, b: 1} : 2226 (special == 'even') ? {a: 2, b: 0} : {a: 0, b: a}; 2227 2228 return (this.cacheNTH[argument] = parsed); 2229 }; 2230 2231 local.createNTHPseudo = function(child, sibling, positions, ofType){ 2232 return function(node, argument){ 2233 var uid = this.getUID(node); 2234 if (!this[positions][uid]){ 2235 var parent = node.parentNode; 2236 if (!parent) return false; 2237 var el = parent[child], count = 1; 2238 if (ofType){ 2239 var nodeName = node.nodeName; 2240 do { 2241 if (el.nodeName != nodeName) continue; 2242 this[positions][this.getUID(el)] = count++; 2243 } while ((el = el[sibling])); 2244 } else { 2245 do { 2246 if (el.nodeType != 1) continue; 2247 this[positions][this.getUID(el)] = count++; 2248 } while ((el = el[sibling])); 2249 } 2250 } 2251 argument = argument || 'n'; 2252 var parsed = this.cacheNTH[argument] || this.parseNTHArgument(argument); 2253 if (!parsed) return false; 2254 var a = parsed.a, b = parsed.b, pos = this[positions][uid]; 2255 if (a == 0) return b == pos; 2256 if (a > 0){ 2257 if (pos < b) return false; 2258 } else { 2259 if (b < pos) return false; 2260 } 2261 return ((pos - b) % a) == 0; 2262 }; 2263 }; 2264 2265 /*</nth-pseudo-selectors>*//*</pseudo-selectors>*/ 2266 2267 local.pushArray = function(node, tag, id, classes, attributes, pseudos){ 2268 if (this.matchSelector(node, tag, id, classes, attributes, pseudos)) this.found.push(node); 2269 }; 2270 2271 local.pushUID = function(node, tag, id, classes, attributes, pseudos){ 2272 var uid = this.getUID(node); 2273 if (!this.uniques[uid] && this.matchSelector(node, tag, id, classes, attributes, pseudos)){ 2274 this.uniques[uid] = true; 2275 this.found.push(node); 2276 } 2277 }; 2278 2279 local.matchNode = function(node, selector){ 2280 if (this.isHTMLDocument && this.nativeMatchesSelector){ 2281 try { 2282 return this.nativeMatchesSelector.call(node, selector.replace(/\[([^=]+)=\s*([^'"\]]+?)\s*\]/g, '[$1="$2"]')); 2283 } catch(matchError) {} 2284 } 2285 2286 var parsed = this.Slick.parse(selector); 2287 if (!parsed) return true; 2288 2289 // simple (single) selectors 2290 var expressions = parsed.expressions, simpleExpCounter = 0, i; 2291 for (i = 0; (currentExpression = expressions[i]); i++){ 2292 if (currentExpression.length == 1){ 2293 var exp = currentExpression[0]; 2294 if (this.matchSelector(node, (this.isXMLDocument) ? exp.tag : exp.tag.toUpperCase(), exp.id, exp.classes, exp.attributes, exp.pseudos)) return true; 2295 simpleExpCounter++; 2296 } 2297 } 2298 2299 if (simpleExpCounter == parsed.length) return false; 2300 2301 var nodes = this.search(this.document, parsed), item; 2302 for (i = 0; item = nodes[i++];){ 2303 if (item === node) return true; 2304 } 2305 return false; 2306 }; 2307 2308 local.matchPseudo = function(node, name, argument){ 2309 var pseudoName = 'pseudo:' + name; 2310 if (this[pseudoName]) return this[pseudoName](node, argument); 2311 var attribute = this.getAttribute(node, name); 2312 return (argument) ? argument == attribute : !!attribute; 2313 }; 2314 2315 local.matchSelector = function(node, tag, id, classes, attributes, pseudos){ 2316 if (tag){ 2317 var nodeName = (this.isXMLDocument) ? node.nodeName : node.nodeName.toUpperCase(); 2318 if (tag == '*'){ 2319 if (nodeName < '@') return false; // Fix for comment nodes and closed nodes 2320 } else { 2321 if (nodeName != tag) return false; 2322 } 2323 } 2324 2325 if (id && node.getAttribute('id') != id) return false; 2326 2327 var i, part, cls; 2328 if (classes) for (i = classes.length; i--;){ 2329 cls = this.getAttribute(node, 'class'); 2330 if (!(cls && classes[i].regexp.test(cls))) return false; 2331 } 2332 if (attributes) for (i = attributes.length; i--;){ 2333 part = attributes[i]; 2334 if (part.operator ? !part.test(this.getAttribute(node, part.key)) : !this.hasAttribute(node, part.key)) return false; 2335 } 2336 if (pseudos) for (i = pseudos.length; i--;){ 2337 part = pseudos[i]; 2338 if (!this.matchPseudo(node, part.key, part.value)) return false; 2339 } 2340 return true; 2341 }; 2342 2343 var combinators = { 2344 2345 ' ': function(node, tag, id, classes, attributes, pseudos, classList){ // all child nodes, any level 2346 2347 var i, item, children; 2348 2349 if (this.isHTMLDocument){ 2350 getById: if (id){ 2351 item = this.document.getElementById(id); 2352 if ((!item && node.all) || (this.idGetsName && item && item.getAttributeNode('id').nodeValue != id)){ 2353 // all[id] returns all the elements with that name or id inside node 2354 // if theres just one it will return the element, else it will be a collection 2355 children = node.all[id]; 2356 if (!children) return; 2357 if (!children[0]) children = [children]; 2358 for (i = 0; item = children[i++];){ 2359 var idNode = item.getAttributeNode('id'); 2360 if (idNode && idNode.nodeValue == id){ 2361 this.push(item, tag, null, classes, attributes, pseudos); 2362 break; 2363 } 2364 } 2365 return; 2366 } 2367 if (!item){ 2368 // if the context is in the dom we return, else we will try GEBTN, breaking the getById label 2369 if (this.contains(this.root, node)) return; 2370 else break getById; 2371 } else if (this.document !== node && !this.contains(node, item)) return; 2372 this.push(item, tag, null, classes, attributes, pseudos); 2373 return; 2374 } 2375 getByClass: if (classes && node.getElementsByClassName && !this.brokenGEBCN){ 2376 children = node.getElementsByClassName(classList.join(' ')); 2377 if (!(children && children.length)) break getByClass; 2378 for (i = 0; item = children[i++];) this.push(item, tag, id, null, attributes, pseudos); 2379 return; 2380 } 2381 } 2382 getByTag: { 2383 children = node.getElementsByTagName(tag); 2384 if (!(children && children.length)) break getByTag; 2385 if (!this.brokenStarGEBTN) tag = null; 2386 for (i = 0; item = children[i++];) this.push(item, tag, id, classes, attributes, pseudos); 2387 } 2388 }, 2389 2390 '>': function(node, tag, id, classes, attributes, pseudos){ // direct children 2391 if ((node = node.firstChild)) do { 2392 if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos); 2393 } while ((node = node.nextSibling)); 2394 }, 2395 2396 '+': function(node, tag, id, classes, attributes, pseudos){ // next sibling 2397 while ((node = node.nextSibling)) if (node.nodeType == 1){ 2398 this.push(node, tag, id, classes, attributes, pseudos); 2399 break; 2400 } 2401 }, 2402 2403 '^': function(node, tag, id, classes, attributes, pseudos){ // first child 2404 node = node.firstChild; 2405 if (node){ 2406 if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos); 2407 else this['combinator:+'](node, tag, id, classes, attributes, pseudos); 2408 } 2409 }, 2410 2411 '~': function(node, tag, id, classes, attributes, pseudos){ // next siblings 2412 while ((node = node.nextSibling)){ 2413 if (node.nodeType != 1) continue; 2414 var uid = this.getUID(node); 2415 if (this.bitUniques[uid]) break; 2416 this.bitUniques[uid] = true; 2417 this.push(node, tag, id, classes, attributes, pseudos); 2418 } 2419 }, 2420 2421 '++': function(node, tag, id, classes, attributes, pseudos){ // next sibling and previous sibling 2422 this['combinator:+'](node, tag, id, classes, attributes, pseudos); 2423 this['combinator:!+'](node, tag, id, classes, attributes, pseudos); 2424 }, 2425 2426 '~~': function(node, tag, id, classes, attributes, pseudos){ // next siblings and previous siblings 2427 this['combinator:~'](node, tag, id, classes, attributes, pseudos); 2428 this['combinator:!~'](node, tag, id, classes, attributes, pseudos); 2429 }, 2430 2431 '!': function(node, tag, id, classes, attributes, pseudos){ // all parent nodes up to document 2432 while ((node = node.parentNode)) if (node !== this.document) this.push(node, tag, id, classes, attributes, pseudos); 2433 }, 2434 2435 '!>': function(node, tag, id, classes, attributes, pseudos){ // direct parent (one level) 2436 node = node.parentNode; 2437 if (node !== this.document) this.push(node, tag, id, classes, attributes, pseudos); 2438 }, 2439 2440 '!+': function(node, tag, id, classes, attributes, pseudos){ // previous sibling 2441 while ((node = node.previousSibling)) if (node.nodeType == 1){ 2442 this.push(node, tag, id, classes, attributes, pseudos); 2443 break; 2444 } 2445 }, 2446 2447 '!^': function(node, tag, id, classes, attributes, pseudos){ // last child 2448 node = node.lastChild; 2449 if (node){ 2450 if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos); 2451 else this['combinator:!+'](node, tag, id, classes, attributes, pseudos); 2452 } 2453 }, 2454 2455 '!~': function(node, tag, id, classes, attributes, pseudos){ // previous siblings 2456 while ((node = node.previousSibling)){ 2457 if (node.nodeType != 1) continue; 2458 var uid = this.getUID(node); 2459 if (this.bitUniques[uid]) break; 2460 this.bitUniques[uid] = true; 2461 this.push(node, tag, id, classes, attributes, pseudos); 2462 } 2463 } 2464 2465 }; 2466 2467 for (var c in combinators) local['combinator:' + c] = combinators[c]; 2468 2469 var pseudos = { 2470 2471 /*<pseudo-selectors>*/ 2472 2473 'empty': function(node){ 2474 var child = node.firstChild; 2475 return !(child && child.nodeType == 1) && !(node.innerText || node.textContent || '').length; 2476 }, 2477 2478 'not': function(node, expression){ 2479 return !this.matchNode(node, expression); 2480 }, 2481 2482 'contains': function(node, text){ 2483 return (node.innerText || node.textContent || '').indexOf(text) > -1; 2484 }, 2485 2486 'first-child': function(node){ 2487 while ((node = node.previousSibling)) if (node.nodeType == 1) return false; 2488 return true; 2489 }, 2490 2491 'last-child': function(node){ 2492 while ((node = node.nextSibling)) if (node.nodeType == 1) return false; 2493 return true; 2494 }, 2495 2496 'only-child': function(node){ 2497 var prev = node; 2498 while ((prev = prev.previousSibling)) if (prev.nodeType == 1) return false; 2499 var next = node; 2500 while ((next = next.nextSibling)) if (next.nodeType == 1) return false; 2501 return true; 2502 }, 2503 2504 /*<nth-pseudo-selectors>*/ 2505 2506 'nth-child': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTH'), 2507 2508 'nth-last-child': local.createNTHPseudo('lastChild', 'previousSibling', 'posNTHLast'), 2509 2510 'nth-of-type': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTHType', true), 2511 2512 'nth-last-of-type': local.createNTHPseudo('lastChild', 'previousSibling', 'posNTHTypeLast', true), 2513 2514 'index': function(node, index){ 2515 return this['pseudo:nth-child'](node, '' + (index + 1)); 2516 }, 2517 2518 'even': function(node){ 2519 return this['pseudo:nth-child'](node, '2n'); 2520 }, 2521 2522 'odd': function(node){ 2523 return this['pseudo:nth-child'](node, '2n+1'); 2524 }, 2525 2526 /*</nth-pseudo-selectors>*/ 2527 2528 /*<of-type-pseudo-selectors>*/ 2529 2530 'first-of-type': function(node){ 2531 var nodeName = node.nodeName; 2532 while ((node = node.previousSibling)) if (node.nodeName == nodeName) return false; 2533 return true; 2534 }, 2535 2536 'last-of-type': function(node){ 2537 var nodeName = node.nodeName; 2538 while ((node = node.nextSibling)) if (node.nodeName == nodeName) return false; 2539 return true; 2540 }, 2541 2542 'only-of-type': function(node){ 2543 var prev = node, nodeName = node.nodeName; 2544 while ((prev = prev.previousSibling)) if (prev.nodeName == nodeName) return false; 2545 var next = node; 2546 while ((next = next.nextSibling)) if (next.nodeName == nodeName) return false; 2547 return true; 2548 }, 2549 2550 /*</of-type-pseudo-selectors>*/ 2551 2552 // custom pseudos 2553 2554 'enabled': function(node){ 2555 return !node.disabled; 2556 }, 2557 2558 'disabled': function(node){ 2559 return node.disabled; 2560 }, 2561 2562 'checked': function(node){ 2563 return node.checked || node.selected; 2564 }, 2565 2566 'focus': function(node){ 2567 return this.isHTMLDocument && this.document.activeElement === node && (node.href || node.type || this.hasAttribute(node, 'tabindex')); 2568 }, 2569 2570 'root': function(node){ 2571 return (node === this.root); 2572 }, 2573 2574 'selected': function(node){ 2575 return node.selected; 2576 } 2577 2578 /*</pseudo-selectors>*/ 2579 }; 2580 2581 for (var p in pseudos) local['pseudo:' + p] = pseudos[p]; 2582 2583 // attributes methods 2584 2585 var attributeGetters = local.attributeGetters = { 2586 2587 'for': function(){ 2588 return ('htmlFor' in this) ? this.htmlFor : this.getAttribute('for'); 2589 }, 2590 2591 'href': function(){ 2592 return ('href' in this) ? this.getAttribute('href', 2) : this.getAttribute('href'); 2593 }, 2594 2595 'style': function(){ 2596 return (this.style) ? this.style.cssText : this.getAttribute('style'); 2597 }, 2598 2599 'tabindex': function(){ 2600 var attributeNode = this.getAttributeNode('tabindex'); 2601 return (attributeNode && attributeNode.specified) ? attributeNode.nodeValue : null; 2602 }, 2603 2604 'type': function(){ 2605 return this.getAttribute('type'); 2606 }, 2607 2608 'maxlength': function(){ 2609 var attributeNode = this.getAttributeNode('maxLength'); 2610 return (attributeNode && attributeNode.specified) ? attributeNode.nodeValue : null; 2611 } 2612 2613 }; 2614 2615 attributeGetters.MAXLENGTH = attributeGetters.maxLength = attributeGetters.maxlength; 2616 2617 // Slick 2618 2619 var Slick = local.Slick = (this.Slick || {}); 2620 2621 Slick.version = '1.1.7'; 2622 2623 // Slick finder 2624 2625 Slick.search = function(context, expression, append){ 2626 return local.search(context, expression, append); 2627 }; 2628 2629 Slick.find = function(context, expression){ 2630 return local.search(context, expression, null, true); 2631 }; 2632 2633 // Slick containment checker 2634 2635 Slick.contains = function(container, node){ 2636 local.setDocument(container); 2637 return local.contains(container, node); 2638 }; 2639 2640 // Slick attribute getter 2641 2642 Slick.getAttribute = function(node, name){ 2643 local.setDocument(node); 2644 return local.getAttribute(node, name); 2645 }; 2646 2647 Slick.hasAttribute = function(node, name){ 2648 local.setDocument(node); 2649 return local.hasAttribute(node, name); 2650 }; 2651 2652 // Slick matcher 2653 2654 Slick.match = function(node, selector){ 2655 if (!(node && selector)) return false; 2656 if (!selector || selector === node) return true; 2657 local.setDocument(node); 2658 return local.matchNode(node, selector); 2659 }; 2660 2661 // Slick attribute accessor 2662 2663 Slick.defineAttributeGetter = function(name, fn){ 2664 local.attributeGetters[name] = fn; 2665 return this; 2666 }; 2667 2668 Slick.lookupAttributeGetter = function(name){ 2669 return local.attributeGetters[name]; 2670 }; 2671 2672 // Slick pseudo accessor 2673 2674 Slick.definePseudo = function(name, fn){ 2675 local['pseudo:' + name] = function(node, argument){ 2676 return fn.call(node, argument); 2677 }; 2678 return this; 2679 }; 2680 2681 Slick.lookupPseudo = function(name){ 2682 var pseudo = local['pseudo:' + name]; 2683 if (pseudo) return function(argument){ 2684 return pseudo.call(this, argument); 2685 }; 2686 return null; 2687 }; 2688 2689 // Slick overrides accessor 2690 2691 Slick.override = function(regexp, fn){ 2692 local.override(regexp, fn); 2693 return this; 2694 }; 2695 2696 Slick.isXML = local.isXML; 2697 2698 Slick.uidOf = function(node){ 2699 return local.getUIDHTML(node); 2700 }; 2701 2702 if (!this.Slick) this.Slick = Slick; 2703 2704 }).apply(/*<CommonJS>*/(typeof exports != 'undefined') ? exports : /*</CommonJS>*/this); 2705 2706 2707 /* 2708 --- 2709 2710 name: Element 2711 2712 description: One of the most important items in MooTools. Contains the dollar function, the dollars function, and an handful of cross-browser, time-saver methods to let you easily work with HTML Elements. 2713 2714 license: MIT-style license. 2715 2716 requires: [Window, Document, Array, String, Function, Object, Number, Slick.Parser, Slick.Finder] 2717 2718 provides: [Element, Elements, $, $$, IFrame, Selectors] 2719 2720 ... 2721 */ 2722 2723 var Element = this.Element = function(tag, props){ 2724 var konstructor = Element.Constructors[tag]; 2725 if (konstructor) return konstructor(props); 2726 if (typeof tag != 'string') return document.id(tag).set(props); 2727 2728 if (!props) props = {}; 2729 2730 if (!(/^[\w-]+$/).test(tag)){ 2731 var parsed = Slick.parse(tag).expressions[0][0]; 2732 tag = (parsed.tag == '*') ? 'div' : parsed.tag; 2733 if (parsed.id && props.id == null) props.id = parsed.id; 2734 2735 var attributes = parsed.attributes; 2736 if (attributes) for (var attr, i = 0, l = attributes.length; i < l; i++){ 2737 attr = attributes[i]; 2738 if (props[attr.key] != null) continue; 2739 2740 if (attr.value != null && attr.operator == '=') props[attr.key] = attr.value; 2741 else if (!attr.value && !attr.operator) props[attr.key] = true; 2742 } 2743 2744 if (parsed.classList && props['class'] == null) props['class'] = parsed.classList.join(' '); 2745 } 2746 2747 return document.newElement(tag, props); 2748 }; 2749 2750 2751 if (Browser.Element){ 2752 Element.prototype = Browser.Element.prototype; 2753 // IE8 and IE9 require the wrapping. 2754 Element.prototype._fireEvent = (function(fireEvent){ 2755 return function(type, event){ 2756 return fireEvent.call(this, type, event); 2757 }; 2758 })(Element.prototype.fireEvent); 2759 } 2760 2761 new Type('Element', Element).mirror(function(name){ 2762 if (Array.prototype[name]) return; 2763 2764 var obj = {}; 2765 obj[name] = function(){ 2766 var results = [], args = arguments, elements = true; 2767 for (var i = 0, l = this.length; i < l; i++){ 2768 var element = this[i], result = results[i] = element[name].apply(element, args); 2769 elements = (elements && typeOf(result) == 'element'); 2770 } 2771 return (elements) ? new Elements(results) : results; 2772 }; 2773 2774 Elements.implement(obj); 2775 }); 2776 2777 if (!Browser.Element){ 2778 Element.parent = Object; 2779 2780 Element.Prototype = { 2781 '$constructor': Element, 2782 '$family': Function.from('element').hide() 2783 }; 2784 2785 Element.mirror(function(name, method){ 2786 Element.Prototype[name] = method; 2787 }); 2788 } 2789 2790 Element.Constructors = {}; 2791 2792 2793 2794 var IFrame = new Type('IFrame', function(){ 2795 var params = Array.link(arguments, { 2796 properties: Type.isObject, 2797 iframe: function(obj){ 2798 return (obj != null); 2799 } 2800 }); 2801 2802 var props = params.properties || {}, iframe; 2803 if (params.iframe) iframe = document.id(params.iframe); 2804 var onload = props.onload || function(){}; 2805 delete props.onload; 2806 props.id = props.name = [props.id, props.name, iframe ? (iframe.id || iframe.name) : 'IFrame_' + String.uniqueID()].pick(); 2807 iframe = new Element(iframe || 'iframe', props); 2808 2809 var onLoad = function(){ 2810 onload.call(iframe.contentWindow); 2811 }; 2812 2813 if (window.frames[props.id]) onLoad(); 2814 else iframe.addListener('load', onLoad); 2815 return iframe; 2816 }); 2817 2818 var Elements = this.Elements = function(nodes){ 2819 if (nodes && nodes.length){ 2820 var uniques = {}, node; 2821 for (var i = 0; node = nodes[i++];){ 2822 var uid = Slick.uidOf(node); 2823 if (!uniques[uid]){ 2824 uniques[uid] = true; 2825 this.push(node); 2826 } 2827 } 2828 } 2829 }; 2830 2831 Elements.prototype = {length: 0}; 2832 Elements.parent = Array; 2833 2834 new Type('Elements', Elements).implement({ 2835 2836 filter: function(filter, bind){ 2837 if (!filter) return this; 2838 return new Elements(Array.filter(this, (typeOf(filter) == 'string') ? function(item){ 2839 return item.match(filter); 2840 } : filter, bind)); 2841 }.protect(), 2842 2843 push: function(){ 2844 var length = this.length; 2845 for (var i = 0, l = arguments.length; i < l; i++){ 2846 var item = document.id(arguments[i]); 2847 if (item) this[length++] = item; 2848 } 2849 return (this.length = length); 2850 }.protect(), 2851 2852 unshift: function(){ 2853 var items = []; 2854 for (var i = 0, l = arguments.length; i < l; i++){ 2855 var item = document.id(arguments[i]); 2856 if (item) items.push(item); 2857 } 2858 return Array.prototype.unshift.apply(this, items); 2859 }.protect(), 2860 2861 concat: function(){ 2862 var newElements = new Elements(this); 2863 for (var i = 0, l = arguments.length; i < l; i++){ 2864 var item = arguments[i]; 2865 if (Type.isEnumerable(item)) newElements.append(item); 2866 else newElements.push(item); 2867 } 2868 return newElements; 2869 }.protect(), 2870 2871 append: function(collection){ 2872 for (var i = 0, l = collection.length; i < l; i++) this.push(collection[i]); 2873 return this; 2874 }.protect(), 2875 2876 empty: function(){ 2877 while (this.length) delete this[--this.length]; 2878 return this; 2879 }.protect() 2880 2881 }); 2882 2883 2884 2885 (function(){ 2886 2887 // FF, IE 2888 var splice = Array.prototype.splice, object = {'0': 0, '1': 1, length: 2}; 2889 2890 splice.call(object, 1, 1); 2891 if (object[1] == 1) Elements.implement('splice', function(){ 2892 var length = this.length; 2893 var result = splice.apply(this, arguments); 2894 while (length >= this.length) delete this[length--]; 2895 return result; 2896 }.protect()); 2897 2898 Array.forEachMethod(function(method, name){ 2899 Elements.implement(name, method); 2900 }); 2901 2902 Array.mirror(Elements); 2903 2904 /*<ltIE8>*/ 2905 var createElementAcceptsHTML; 2906 try { 2907 createElementAcceptsHTML = (document.createElement('<input name=x>').name == 'x'); 2908 } catch (e){} 2909 2910 var escapeQuotes = function(html){ 2911 return ('' + html).replace(/&/g, '&').replace(/"/g, '"'); 2912 }; 2913 /*</ltIE8>*/ 2914 2915 Document.implement({ 2916 2917 newElement: function(tag, props){ 2918 if (props && props.checked != null) props.defaultChecked = props.checked; 2919 /*<ltIE8>*/// Fix for readonly name and type properties in IE < 8 2920 if (createElementAcceptsHTML && props){ 2921 tag = '<' + tag; 2922 if (props.name) tag += ' name="' + escapeQuotes(props.name) + '"'; 2923 if (props.type) tag += ' type="' + escapeQuotes(props.type) + '"'; 2924 tag += '>'; 2925 delete props.name; 2926 delete props.type; 2927 } 2928 /*</ltIE8>*/ 2929 return this.id(this.createElement(tag)).set(props); 2930 } 2931 2932 }); 2933 2934 })(); 2935 2936 (function(){ 2937 2938 Slick.uidOf(window); 2939 Slick.uidOf(document); 2940 2941 Document.implement({ 2942 2943 newTextNode: function(text){ 2944 return this.createTextNode(text); 2945 }, 2946 2947 getDocument: function(){ 2948 return this; 2949 }, 2950 2951 getWindow: function(){ 2952 return this.window; 2953 }, 2954 2955 id: (function(){ 2956 2957 var types = { 2958 2959 string: function(id, nocash, doc){ 2960 id = Slick.find(doc, '#' + id.replace(/(\W)/g, '\\$1')); 2961 return (id) ? types.element(id, nocash) : null; 2962 }, 2963 2964 element: function(el, nocash){ 2965 Slick.uidOf(el); 2966 if (!nocash && !el.$family && !(/^(?:object|embed)$/i).test(el.tagName)){ 2967 var fireEvent = el.fireEvent; 2968 // wrapping needed in IE7, or else crash 2969 el._fireEvent = function(type, event){ 2970 return fireEvent(type, event); 2971 }; 2972 Object.append(el, Element.Prototype); 2973 } 2974 return el; 2975 }, 2976 2977 object: function(obj, nocash, doc){ 2978 if (obj.toElement) return types.element(obj.toElement(doc), nocash); 2979 return null; 2980 } 2981 2982 }; 2983 2984 types.textnode = types.whitespace = types.window = types.document = function(zero){ 2985 return zero; 2986 }; 2987 2988 return function(el, nocash, doc){ 2989 if (el && el.$family && el.uniqueNumber) return el; 2990 var type = typeOf(el); 2991 return (types[type]) ? types[type](el, nocash, doc || document) : null; 2992 }; 2993 2994 })() 2995 2996 }); 2997 2998 if (window.$ == null) Window.implement('$', function(el, nc){ 2999 return document.id(el, nc, this.document); 3000 }); 3001 3002 Window.implement({ 3003 3004 getDocument: function(){ 3005 return this.document; 3006 }, 3007 3008 getWindow: function(){ 3009 return this; 3010 } 3011 3012 }); 3013 3014 [Document, Element].invoke('implement', { 3015 3016 getElements: function(expression){ 3017 return Slick.search(this, expression, new Elements); 3018 }, 3019 3020 getElement: function(expression){ 3021 return document.id(Slick.find(this, expression)); 3022 } 3023 3024 }); 3025 3026 var contains = {contains: function(element){ 3027 return Slick.contains(this, element); 3028 }}; 3029 3030 if (!document.contains) Document.implement(contains); 3031 if (!document.createElement('div').contains) Element.implement(contains); 3032 3033 3034 3035 // tree walking 3036 3037 var injectCombinator = function(expression, combinator){ 3038 if (!expression) return combinator; 3039 3040 expression = Object.clone(Slick.parse(expression)); 3041 3042 var expressions = expression.expressions; 3043 for (var i = expressions.length; i--;) 3044 expressions[i][0].combinator = combinator; 3045 3046 return expression; 3047 }; 3048 3049 Object.forEach({ 3050 getNext: '~', 3051 getPrevious: '!~', 3052 getParent: '!' 3053 }, function(combinator, method){ 3054 Element.implement(method, function(expression){ 3055 return this.getElement(injectCombinator(expression, combinator)); 3056 }); 3057 }); 3058 3059 Object.forEach({ 3060 getAllNext: '~', 3061 getAllPrevious: '!~', 3062 getSiblings: '~~', 3063 getChildren: '>', 3064 getParents: '!' 3065 }, function(combinator, method){ 3066 Element.implement(method, function(expression){ 3067 return this.getElements(injectCombinator(expression, combinator)); 3068 }); 3069 }); 3070 3071 Element.implement({ 3072 3073 getFirst: function(expression){ 3074 return document.id(Slick.search(this, injectCombinator(expression, '>'))[0]); 3075 }, 3076 3077 getLast: function(expression){ 3078 return document.id(Slick.search(this, injectCombinator(expression, '>')).getLast()); 3079 }, 3080 3081 getWindow: function(){ 3082 return this.ownerDocument.window; 3083 }, 3084 3085 getDocument: function(){ 3086 return this.ownerDocument; 3087 }, 3088 3089 getElementById: function(id){ 3090 return document.id(Slick.find(this, '#' + ('' + id).replace(/(\W)/g, '\\$1'))); 3091 }, 3092 3093 match: function(expression){ 3094 return !expression || Slick.match(this, expression); 3095 } 3096 3097 }); 3098 3099 3100 3101 if (window.$$ == null) Window.implement('$$', function(selector){ 3102 if (arguments.length == 1){ 3103 if (typeof selector == 'string') return Slick.search(this.document, selector, new Elements); 3104 else if (Type.isEnumerable(selector)) return new Elements(selector); 3105 } 3106 return new Elements(arguments); 3107 }); 3108 3109 // Inserters 3110 3111 var inserters = { 3112 3113 before: function(context, element){ 3114 var parent = element.parentNode; 3115 if (parent) parent.insertBefore(context, element); 3116 }, 3117 3118 after: function(context, element){ 3119 var parent = element.parentNode; 3120 if (parent) parent.insertBefore(context, element.nextSibling); 3121 }, 3122 3123 bottom: function(context, element){ 3124 element.appendChild(context); 3125 }, 3126 3127 top: function(context, element){ 3128 element.insertBefore(context, element.firstChild); 3129 } 3130 3131 }; 3132 3133 inserters.inside = inserters.bottom; 3134 3135 3136 3137 // getProperty / setProperty 3138 3139 var propertyGetters = {}, propertySetters = {}; 3140 3141 // properties 3142 3143 var properties = {}; 3144 Array.forEach([ 3145 'type', 'value', 'defaultValue', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan', 3146 'frameBorder', 'rowSpan', 'tabIndex', 'useMap' 3147 ], function(property){ 3148 properties[property.toLowerCase()] = property; 3149 }); 3150 3151 properties.html = 'innerHTML'; 3152 properties.text = (document.createElement('div').textContent == null) ? 'innerText': 'textContent'; 3153 3154 Object.forEach(properties, function(real, key){ 3155 propertySetters[key] = function(node, value){ 3156 node[real] = value; 3157 }; 3158 propertyGetters[key] = function(node){ 3159 return node[real]; 3160 }; 3161 }); 3162 3163 // Booleans 3164 3165 var bools = [ 3166 'compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', 3167 'disabled', 'readOnly', 'multiple', 'selected', 'noresize', 3168 'defer', 'defaultChecked', 'autofocus', 'controls', 'autoplay', 3169 'loop' 3170 ]; 3171 3172 var booleans = {}; 3173 Array.forEach(bools, function(bool){ 3174 var lower = bool.toLowerCase(); 3175 booleans[lower] = bool; 3176 propertySetters[lower] = function(node, value){ 3177 node[bool] = !!value; 3178 }; 3179 propertyGetters[lower] = function(node){ 3180 return !!node[bool]; 3181 }; 3182 }); 3183 3184 // Special cases 3185 3186 Object.append(propertySetters, { 3187 3188 'class': function(node, value){ 3189 ('className' in node) ? node.className = (value || '') : node.setAttribute('class', value); 3190 }, 3191 3192 'for': function(node, value){ 3193 ('htmlFor' in node) ? node.htmlFor = value : node.setAttribute('for', value); 3194 }, 3195 3196 'style': function(node, value){ 3197 (node.style) ? node.style.cssText = value : node.setAttribute('style', value); 3198 }, 3199 3200 'value': function(node, value){ 3201 node.value = (value != null) ? value : ''; 3202 } 3203 3204 }); 3205 3206 propertyGetters['class'] = function(node){ 3207 return ('className' in node) ? node.className || null : node.getAttribute('class'); 3208 }; 3209 3210 /* <webkit> */ 3211 var el = document.createElement('button'); 3212 // IE sets type as readonly and throws 3213 try { el.type = 'button'; } catch(e){} 3214 if (el.type != 'button') propertySetters.type = function(node, value){ 3215 node.setAttribute('type', value); 3216 }; 3217 el = null; 3218 /* </webkit> */ 3219 3220 /*<IE>*/ 3221 var input = document.createElement('input'); 3222 input.value = 't'; 3223 input.type = 'submit'; 3224 if (input.value != 't') propertySetters.type = function(node, type){ 3225 var value = node.value; 3226 node.type = type; 3227 node.value = value; 3228 }; 3229 input = null; 3230 /*</IE>*/ 3231 3232 /* getProperty, setProperty */ 3233 3234 /* <ltIE9> */ 3235 var pollutesGetAttribute = (function(div){ 3236 div.random = 'attribute'; 3237 return (div.getAttribute('random') == 'attribute'); 3238 })(document.createElement('div')); 3239 3240 var hasCloneBug = (function(test){ 3241 test.innerHTML = '<object><param name="should_fix" value="the unknown"></object>'; 3242 return test.cloneNode(true).firstChild.childNodes.length != 1; 3243 })(document.createElement('div')); 3244 /* </ltIE9> */ 3245 3246 var hasClassList = !!document.createElement('div').classList; 3247 3248 var classes = function(className){ 3249 var classNames = (className || '').clean().split(" "), uniques = {}; 3250 return classNames.filter(function(className){ 3251 if (className !== "" && !uniques[className]) return uniques[className] = className; 3252 }); 3253 }; 3254 3255 var addToClassList = function(name){ 3256 this.classList.add(name); 3257 }; 3258 3259 var removeFromClassList = function(name){ 3260 this.classList.remove(name); 3261 }; 3262 3263 Element.implement({ 3264 3265 setProperty: function(name, value){ 3266 var setter = propertySetters[name.toLowerCase()]; 3267 if (setter){ 3268 setter(this, value); 3269 } else { 3270 /* <ltIE9> */ 3271 var attributeWhiteList; 3272 if (pollutesGetAttribute) attributeWhiteList = this.retrieve('$attributeWhiteList', {}); 3273 /* </ltIE9> */ 3274 3275 if (value == null){ 3276 this.removeAttribute(name); 3277 /* <ltIE9> */ 3278 if (pollutesGetAttribute) delete attributeWhiteList[name]; 3279 /* </ltIE9> */ 3280 } else { 3281 this.setAttribute(name, '' + value); 3282 /* <ltIE9> */ 3283 if (pollutesGetAttribute) attributeWhiteList[name] = true; 3284 /* </ltIE9> */ 3285 } 3286 } 3287 return this; 3288 }, 3289 3290 setProperties: function(attributes){ 3291 for (var attribute in attributes) this.setProperty(attribute, attributes[attribute]); 3292 return this; 3293 }, 3294 3295 getProperty: function(name){ 3296 var getter = propertyGetters[name.toLowerCase()]; 3297 if (getter) return getter(this); 3298 /* <ltIE9> */ 3299 if (pollutesGetAttribute){ 3300 var attr = this.getAttributeNode(name), attributeWhiteList = this.retrieve('$attributeWhiteList', {}); 3301 if (!attr) return null; 3302 if (attr.expando && !attributeWhiteList[name]){ 3303 var outer = this.outerHTML; 3304 // segment by the opening tag and find mention of attribute name 3305 if (outer.substr(0, outer.search(/\/?['"]?>(?![^<]*<['"])/)).indexOf(name) < 0) return null; 3306 attributeWhiteList[name] = true; 3307 } 3308 } 3309 /* </ltIE9> */ 3310 var result = Slick.getAttribute(this, name); 3311 return (!result && !Slick.hasAttribute(this, name)) ? null : result; 3312 }, 3313 3314 getProperties: function(){ 3315 var args = Array.from(arguments); 3316 return args.map(this.getProperty, this).associate(args); 3317 }, 3318 3319 removeProperty: function(name){ 3320 return this.setProperty(name, null); 3321 }, 3322 3323 removeProperties: function(){ 3324 Array.each(arguments, this.removeProperty, this); 3325 return this; 3326 }, 3327 3328 set: function(prop, value){ 3329 var property = Element.Properties[prop]; 3330 (property && property.set) ? property.set.call(this, value) : this.setProperty(prop, value); 3331 }.overloadSetter(), 3332 3333 get: function(prop){ 3334 var property = Element.Properties[prop]; 3335 return (property && property.get) ? property.get.apply(this) : this.getProperty(prop); 3336 }.overloadGetter(), 3337 3338 erase: function(prop){ 3339 var property = Element.Properties[prop]; 3340 (property && property.erase) ? property.erase.apply(this) : this.removeProperty(prop); 3341 return this; 3342 }, 3343 3344 hasClass: hasClassList ? function(className){ 3345 return this.classList.contains(className); 3346 } : function(className){ 3347 return this.className.clean().contains(className, ' '); 3348 }, 3349 3350 addClass: hasClassList ? function(className){ 3351 classes(className).forEach(addToClassList, this); 3352 return this; 3353 } : function(className){ 3354 this.className = classes(className + ' ' + this.className).join(' '); 3355 return this; 3356 }, 3357 3358 removeClass: hasClassList ? function(className){ 3359 classes(className).forEach(removeFromClassList, this); 3360 return this; 3361 } : function(className){ 3362 var classNames = classes(this.className); 3363 classes(className).forEach(classNames.erase, classNames); 3364 this.className = classNames.join(' '); 3365 return this; 3366 }, 3367 3368 toggleClass: function(className, force){ 3369 if (force == null) force = !this.hasClass(className); 3370 return (force) ? this.addClass(className) : this.removeClass(className); 3371 }, 3372 3373 adopt: function(){ 3374 var parent = this, fragment, elements = Array.flatten(arguments), length = elements.length; 3375 if (length > 1) parent = fragment = document.createDocumentFragment(); 3376 3377 for (var i = 0; i < length; i++){ 3378 var element = document.id(elements[i], true); 3379 if (element) parent.appendChild(element); 3380 } 3381 3382 if (fragment) this.appendChild(fragment); 3383 3384 return this; 3385 }, 3386 3387 appendText: function(text, where){ 3388 return this.grab(this.getDocument().newTextNode(text), where); 3389 }, 3390 3391 grab: function(el, where){ 3392 inserters[where || 'bottom'](document.id(el, true), this); 3393 return this; 3394 }, 3395 3396 inject: function(el, where){ 3397 inserters[where || 'bottom'](this, document.id(el, true)); 3398 return this; 3399 }, 3400 3401 replaces: function(el){ 3402 el = document.id(el, true); 3403 el.parentNode.replaceChild(this, el); 3404 return this; 3405 }, 3406 3407 wraps: function(el, where){ 3408 el = document.id(el, true); 3409 return this.replaces(el).grab(el, where); 3410 }, 3411 3412 getSelected: function(){ 3413 this.selectedIndex; // Safari 3.2.1 3414 return new Elements(Array.from(this.options).filter(function(option){ 3415 return option.selected; 3416 })); 3417 }, 3418 3419 toQueryString: function(){ 3420 var queryString = []; 3421 this.getElements('input, select, textarea').each(function(el){ 3422 var type = el.type; 3423 if (!el.name || el.disabled || type == 'submit' || type == 'reset' || type == 'file' || type == 'image') return; 3424 3425 var value = (el.get('tag') == 'select') ? el.getSelected().map(function(opt){ 3426 // IE 3427 return document.id(opt).get('value'); 3428 }) : ((type == 'radio' || type == 'checkbox') && !el.checked) ? null : el.get('value'); 3429 3430 Array.from(value).each(function(val){ 3431 if (typeof val != 'undefined') queryString.push(encodeURIComponent(el.name) + '=' + encodeURIComponent(val)); 3432 }); 3433 }); 3434 return queryString.join('&'); 3435 } 3436 3437 }); 3438 3439 3440 // appendHTML 3441 3442 var appendInserters = { 3443 before: 'beforeBegin', 3444 after: 'afterEnd', 3445 bottom: 'beforeEnd', 3446 top: 'afterBegin', 3447 inside: 'beforeEnd' 3448 }; 3449 3450 Element.implement('appendHTML', ('insertAdjacentHTML' in document.createElement('div')) ? function(html, where){ 3451 this.insertAdjacentHTML(appendInserters[where || 'bottom'], html); 3452 return this; 3453 } : function(html, where){ 3454 var temp = new Element('div', {html: html}), 3455 children = temp.childNodes, 3456 fragment = temp.firstChild; 3457 3458 if (!fragment) return this; 3459 if (children.length > 1){ 3460 fragment = document.createDocumentFragment(); 3461 for (var i = 0, l = children.length; i < l; i++){ 3462 fragment.appendChild(children[i]); 3463 } 3464 } 3465 3466 inserters[where || 'bottom'](fragment, this); 3467 return this; 3468 }); 3469 3470 var collected = {}, storage = {}; 3471 3472 var get = function(uid){ 3473 return (storage[uid] || (storage[uid] = {})); 3474 }; 3475 3476 var clean = function(item){ 3477 var uid = item.uniqueNumber; 3478 if (item.removeEvents) item.removeEvents(); 3479 if (item.clearAttributes) item.clearAttributes(); 3480 if (uid != null){ 3481 delete collected[uid]; 3482 delete storage[uid]; 3483 } 3484 return item; 3485 }; 3486 3487 var formProps = {input: 'checked', option: 'selected', textarea: 'value'}; 3488 3489 Element.implement({ 3490 3491 destroy: function(){ 3492 var children = clean(this).getElementsByTagName('*'); 3493 Array.each(children, clean); 3494 Element.dispose(this); 3495 return null; 3496 }, 3497 3498 empty: function(){ 3499 Array.from(this.childNodes).each(Element.dispose); 3500 return this; 3501 }, 3502 3503 dispose: function(){ 3504 return (this.parentNode) ? this.parentNode.removeChild(this) : this; 3505 }, 3506 3507 clone: function(contents, keepid){ 3508 contents = contents !== false; 3509 var clone = this.cloneNode(contents), ce = [clone], te = [this], i; 3510 3511 if (contents){ 3512 ce.append(Array.from(clone.getElementsByTagName('*'))); 3513 te.append(Array.from(this.getElementsByTagName('*'))); 3514 } 3515 3516 for (i = ce.length; i--;){ 3517 var node = ce[i], element = te[i]; 3518 if (!keepid) node.removeAttribute('id'); 3519 /*<ltIE9>*/ 3520 if (node.clearAttributes){ 3521 node.clearAttributes(); 3522 node.mergeAttributes(element); 3523 node.removeAttribute('uniqueNumber'); 3524 if (node.options){ 3525 var no = node.options, eo = element.options; 3526 for (var j = no.length; j--;) no[j].selected = eo[j].selected; 3527 } 3528 } 3529 /*</ltIE9>*/ 3530 var prop = formProps[element.tagName.toLowerCase()]; 3531 if (prop && element[prop]) node[prop] = element[prop]; 3532 } 3533 3534 /*<ltIE9>*/ 3535 if (hasCloneBug){ 3536 var co = clone.getElementsByTagName('object'), to = this.getElementsByTagName('object'); 3537 for (i = co.length; i--;) co[i].outerHTML = to[i].outerHTML; 3538 } 3539 /*</ltIE9>*/ 3540 return document.id(clone); 3541 } 3542 3543 }); 3544 3545 [Element, Window, Document].invoke('implement', { 3546 3547 addListener: function(type, fn){ 3548 if (window.attachEvent && !window.addEventListener){ 3549 collected[Slick.uidOf(this)] = this; 3550 } 3551 if (this.addEventListener) this.addEventListener(type, fn, !!arguments[2]); 3552 else this.attachEvent('on' + type, fn); 3553 return this; 3554 }, 3555 3556 removeListener: function(type, fn){ 3557 if (this.removeEventListener) this.removeEventListener(type, fn, !!arguments[2]); 3558 else this.detachEvent('on' + type, fn); 3559 return this; 3560 }, 3561 3562 retrieve: function(property, dflt){ 3563 var storage = get(Slick.uidOf(this)), prop = storage[property]; 3564 if (dflt != null && prop == null) prop = storage[property] = dflt; 3565 return prop != null ? prop : null; 3566 }, 3567 3568 store: function(property, value){ 3569 var storage = get(Slick.uidOf(this)); 3570 storage[property] = value; 3571 return this; 3572 }, 3573 3574 eliminate: function(property){ 3575 var storage = get(Slick.uidOf(this)); 3576 delete storage[property]; 3577 return this; 3578 } 3579 3580 }); 3581 3582 /*<ltIE9>*/ 3583 if (window.attachEvent && !window.addEventListener){ 3584 var gc = function(){ 3585 Object.each(collected, clean); 3586 if (window.CollectGarbage) CollectGarbage(); 3587 window.removeListener('unload', gc); 3588 } 3589 window.addListener('unload', gc); 3590 } 3591 /*</ltIE9>*/ 3592 3593 Element.Properties = {}; 3594 3595 3596 3597 Element.Properties.style = { 3598 3599 set: function(style){ 3600 this.style.cssText = style; 3601 }, 3602 3603 get: function(){ 3604 return this.style.cssText; 3605 }, 3606 3607 erase: function(){ 3608 this.style.cssText = ''; 3609 } 3610 3611 }; 3612 3613 Element.Properties.tag = { 3614 3615 get: function(){ 3616 return this.tagName.toLowerCase(); 3617 } 3618 3619 }; 3620 3621 Element.Properties.html = { 3622 3623 set: function(html){ 3624 if (html == null) html = ''; 3625 else if (typeOf(html) == 'array') html = html.join(''); 3626 this.innerHTML = html; 3627 }, 3628 3629 erase: function(){ 3630 this.innerHTML = ''; 3631 } 3632 3633 }; 3634 3635 var supportsHTML5Elements = true, supportsTableInnerHTML = true, supportsTRInnerHTML = true; 3636 3637 /*<ltIE9>*/ 3638 // technique by jdbarlett - http://jdbartlett.com/innershiv/ 3639 var div = document.createElement('div'); 3640 div.innerHTML = '<nav></nav>'; 3641 supportsHTML5Elements = (div.childNodes.length == 1); 3642 if (!supportsHTML5Elements){ 3643 var tags = 'abbr article aside audio canvas datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video'.split(' '), 3644 fragment = document.createDocumentFragment(), l = tags.length; 3645 while (l--) fragment.createElement(tags[l]); 3646 } 3647 div = null; 3648 /*</ltIE9>*/ 3649 3650 /*<IE>*/ 3651 supportsTableInnerHTML = Function.attempt(function(){ 3652 var table = document.createElement('table'); 3653 table.innerHTML = '<tr><td></td></tr>'; 3654 return true; 3655 }); 3656 3657 /*<ltFF4>*/ 3658 var tr = document.createElement('tr'), html = '<td></td>'; 3659 tr.innerHTML = html; 3660 supportsTRInnerHTML = (tr.innerHTML == html); 3661 tr = null; 3662 /*</ltFF4>*/ 3663 3664 if (!supportsTableInnerHTML || !supportsTRInnerHTML || !supportsHTML5Elements){ 3665 3666 Element.Properties.html.set = (function(set){ 3667 3668 var translations = { 3669 table: [1, '<table>', '</table>'], 3670 select: [1, '<select>', '</select>'], 3671 tbody: [2, '<table><tbody>', '</tbody></table>'], 3672 tr: [3, '<table><tbody><tr>', '</tr></tbody></table>'] 3673 }; 3674 3675 translations.thead = translations.tfoot = translations.tbody; 3676 3677 return function(html){ 3678 var wrap = translations[this.get('tag')]; 3679 if (!wrap && !supportsHTML5Elements) wrap = [0, '', '']; 3680 if (!wrap) return set.call(this, html); 3681 3682 var level = wrap[0], wrapper = document.createElement('div'), target = wrapper; 3683 if (!supportsHTML5Elements) fragment.appendChild(wrapper); 3684 wrapper.innerHTML = [wrap[1], html, wrap[2]].flatten().join(''); 3685 while (level--) target = target.firstChild; 3686 this.empty().adopt(target.childNodes); 3687 if (!supportsHTML5Elements) fragment.removeChild(wrapper); 3688 wrapper = null; 3689 }; 3690 3691 })(Element.Properties.html.set); 3692 } 3693 /*</IE>*/ 3694 3695 /*<ltIE9>*/ 3696 var testForm = document.createElement('form'); 3697 testForm.innerHTML = '<select><option>s</option></select>'; 3698 3699 if (testForm.firstChild.value != 's') Element.Properties.value = { 3700 3701 set: function(value){ 3702 var tag = this.get('tag'); 3703 if (tag != 'select') return this.setProperty('value', value); 3704 var options = this.getElements('option'); 3705 value = String(value); 3706 for (var i = 0; i < options.length; i++){ 3707 var option = options[i], 3708 attr = option.getAttributeNode('value'), 3709 optionValue = (attr && attr.specified) ? option.value : option.get('text'); 3710 if (optionValue === value) return option.selected = true; 3711 } 3712 }, 3713 3714 get: function(){ 3715 var option = this, tag = option.get('tag'); 3716 3717 if (tag != 'select' && tag != 'option') return this.getProperty('value'); 3718 3719 if (tag == 'select' && !(option = option.getSelected()[0])) return ''; 3720 3721 var attr = option.getAttributeNode('value'); 3722 return (attr && attr.specified) ? option.value : option.get('text'); 3723 } 3724 3725 }; 3726 testForm = null; 3727 /*</ltIE9>*/ 3728 3729 /*<IE>*/ 3730 if (document.createElement('div').getAttributeNode('id')) Element.Properties.id = { 3731 set: function(id){ 3732 this.id = this.getAttributeNode('id').value = id; 3733 }, 3734 get: function(){ 3735 return this.id || null; 3736 }, 3737 erase: function(){ 3738 this.id = this.getAttributeNode('id').value = ''; 3739 } 3740 }; 3741 /*</IE>*/ 3742 3743 })(); 3744 3745 3746 /* 3747 --- 3748 3749 name: Element.Style 3750 3751 description: Contains methods for interacting with the styles of Elements in a fashionable way. 3752 3753 license: MIT-style license. 3754 3755 requires: Element 3756 3757 provides: Element.Style 3758 3759 ... 3760 */ 3761 3762 (function(){ 3763 3764 var html = document.html, el; 3765 3766 //<ltIE9> 3767 // Check for oldIE, which does not remove styles when they're set to null 3768 el = document.createElement('div'); 3769 el.style.color = 'red'; 3770 el.style.color = null; 3771 var doesNotRemoveStyles = el.style.color == 'red'; 3772 3773 // check for oldIE, which returns border* shorthand styles in the wrong order (color-width-style instead of width-style-color) 3774 var border = '1px solid #123abc'; 3775 el.style.border = border; 3776 var returnsBordersInWrongOrder = el.style.border != border; 3777 el = null; 3778 //</ltIE9> 3779 3780 var hasGetComputedStyle = !!window.getComputedStyle; 3781 3782 Element.Properties.styles = {set: function(styles){ 3783 this.setStyles(styles); 3784 }}; 3785 3786 var hasOpacity = (html.style.opacity != null), 3787 hasFilter = (html.style.filter != null), 3788 reAlpha = /alpha\(opacity=([\d.]+)\)/i; 3789 3790 var setVisibility = function(element, opacity){ 3791 element.store('$opacity', opacity); 3792 element.style.visibility = opacity > 0 || opacity == null ? 'visible' : 'hidden'; 3793 }; 3794 3795 //<ltIE9> 3796 var setFilter = function(element, regexp, value){ 3797 var style = element.style, 3798 filter = style.filter || element.getComputedStyle('filter') || ''; 3799 style.filter = (regexp.test(filter) ? filter.replace(regexp, value) : filter + ' ' + value).trim(); 3800 if (!style.filter) style.removeAttribute('filter'); 3801 }; 3802 //</ltIE9> 3803 3804 var setOpacity = (hasOpacity ? function(element, opacity){ 3805 element.style.opacity = opacity; 3806 } : (hasFilter ? function(element, opacity){ 3807 if (!element.currentStyle || !element.currentStyle.hasLayout) element.style.zoom = 1; 3808 if (opacity == null || opacity == 1){ 3809 setFilter(element, reAlpha, ''); 3810 if (opacity == 1 && getOpacity(element) != 1) setFilter(element, reAlpha, 'alpha(opacity=100)'); 3811 } else { 3812 setFilter(element, reAlpha, 'alpha(opacity=' + (opacity * 100).limit(0, 100).round() + ')'); 3813 } 3814 } : setVisibility)); 3815 3816 var getOpacity = (hasOpacity ? function(element){ 3817 var opacity = element.style.opacity || element.getComputedStyle('opacity'); 3818 return (opacity == '') ? 1 : opacity.toFloat(); 3819 } : (hasFilter ? function(element){ 3820 var filter = (element.style.filter || element.getComputedStyle('filter')), 3821 opacity; 3822 if (filter) opacity = filter.match(reAlpha); 3823 return (opacity == null || filter == null) ? 1 : (opacity[1] / 100); 3824 } : function(element){ 3825 var opacity = element.retrieve('$opacity'); 3826 if (opacity == null) opacity = (element.style.visibility == 'hidden' ? 0 : 1); 3827 return opacity; 3828 })); 3829 3830 var floatName = (html.style.cssFloat == null) ? 'styleFloat' : 'cssFloat', 3831 namedPositions = {left: '0%', top: '0%', center: '50%', right: '100%', bottom: '100%'}, 3832 hasBackgroundPositionXY = (html.style.backgroundPositionX != null); 3833 3834 //<ltIE9> 3835 var removeStyle = function(style, property){ 3836 if (property == 'backgroundPosition'){ 3837 style.removeAttribute(property + 'X'); 3838 property += 'Y'; 3839 } 3840 style.removeAttribute(property); 3841 }; 3842 //</ltIE9> 3843 3844 Element.implement({ 3845 3846 getComputedStyle: function(property){ 3847 if (!hasGetComputedStyle && this.currentStyle) return this.currentStyle[property.camelCase()]; 3848 var defaultView = Element.getDocument(this).defaultView, 3849 computed = defaultView ? defaultView.getComputedStyle(this, null) : null; 3850 return (computed) ? computed.getPropertyValue((property == floatName) ? 'float' : property.hyphenate()) : ''; 3851 }, 3852 3853 setStyle: function(property, value){ 3854 if (property == 'opacity'){ 3855 if (value != null) value = parseFloat(value); 3856 setOpacity(this, value); 3857 return this; 3858 } 3859 property = (property == 'float' ? floatName : property).camelCase(); 3860 if (typeOf(value) != 'string'){ 3861 var map = (Element.Styles[property] || '@').split(' '); 3862 value = Array.from(value).map(function(val, i){ 3863 if (!map[i]) return ''; 3864 return (typeOf(val) == 'number') ? map[i].replace('@', Math.round(val)) : val; 3865 }).join(' '); 3866 } else if (value == String(Number(value))){ 3867 value = Math.round(value); 3868 } 3869 this.style[property] = value; 3870 //<ltIE9> 3871 if ((value == '' || value == null) && doesNotRemoveStyles && this.style.removeAttribute){ 3872 removeStyle(this.style, property); 3873 } 3874 //</ltIE9> 3875 return this; 3876 }, 3877 3878 getStyle: function(property){ 3879 if (property == 'opacity') return getOpacity(this); 3880 property = (property == 'float' ? floatName : property).camelCase(); 3881 var result = this.style[property]; 3882 if (!result || property == 'zIndex'){ 3883 if (Element.ShortStyles.hasOwnProperty(property)){ 3884 result = []; 3885 for (var s in Element.ShortStyles[property]) result.push(this.getStyle(s)); 3886 return result.join(' '); 3887 } 3888 result = this.getComputedStyle(property); 3889 } 3890 if (hasBackgroundPositionXY && /^backgroundPosition[XY]?$/.test(property)){ 3891 return result.replace(/(top|right|bottom|left)/g, function(position){ 3892 return namedPositions[position]; 3893 }) || '0px'; 3894 } 3895 if (!result && property == 'backgroundPosition') return '0px 0px'; 3896 if (result){ 3897 result = String(result); 3898 var color = result.match(/rgba?\([\d\s,]+\)/); 3899 if (color) result = result.replace(color[0], color[0].rgbToHex()); 3900 } 3901 if (!hasGetComputedStyle && !this.style[property]){ 3902 if ((/^(height|width)$/).test(property) && !(/px$/.test(result))){ 3903 var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0; 3904 values.each(function(value){ 3905 size += this.getStyle('border-' + value + '-width').toInt() + this.getStyle('padding-' + value).toInt(); 3906 }, this); 3907 return this['offset' + property.capitalize()] - size + 'px'; 3908 } 3909 if ((/^border(.+)Width|margin|padding/).test(property) && isNaN(parseFloat(result))){ 3910 return '0px'; 3911 } 3912 } 3913 //<ltIE9> 3914 if (returnsBordersInWrongOrder && /^border(Top|Right|Bottom|Left)?$/.test(property) && /^#/.test(result)){ 3915 return result.replace(/^(.+)\s(.+)\s(.+)$/, '$2 $3 $1'); 3916 } 3917 //</ltIE9> 3918 return result; 3919 }, 3920 3921 setStyles: function(styles){ 3922 for (var style in styles) this.setStyle(style, styles[style]); 3923 return this; 3924 }, 3925 3926 getStyles: function(){ 3927 var result = {}; 3928 Array.flatten(arguments).each(function(key){ 3929 result[key] = this.getStyle(key); 3930 }, this); 3931 return result; 3932 } 3933 3934 }); 3935 3936 Element.Styles = { 3937 left: '@px', top: '@px', bottom: '@px', right: '@px', 3938 width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px', 3939 backgroundColor: 'rgb(@, @, @)', backgroundSize: '@px', backgroundPosition: '@px @px', color: 'rgb(@, @, @)', 3940 fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)', 3941 margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)', 3942 borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)', 3943 zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@' 3944 }; 3945 3946 3947 3948 3949 3950 Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}}; 3951 3952 ['Top', 'Right', 'Bottom', 'Left'].each(function(direction){ 3953 var Short = Element.ShortStyles; 3954 var All = Element.Styles; 3955 ['margin', 'padding'].each(function(style){ 3956 var sd = style + direction; 3957 Short[style][sd] = All[sd] = '@px'; 3958 }); 3959 var bd = 'border' + direction; 3960 Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)'; 3961 var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color'; 3962 Short[bd] = {}; 3963 Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px'; 3964 Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@'; 3965 Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)'; 3966 }); 3967 3968 if (hasBackgroundPositionXY) Element.ShortStyles.backgroundPosition = {backgroundPositionX: '@', backgroundPositionY: '@'}; 3969 })(); 3970 3971 3972 /* 3973 --- 3974 3975 name: Element.Event 3976 3977 description: Contains Element methods for dealing with events. This file also includes mouseenter and mouseleave custom Element Events, if necessary. 3978 3979 license: MIT-style license. 3980 3981 requires: [Element, Event] 3982 3983 provides: Element.Event 3984 3985 ... 3986 */ 3987 3988 (function(){ 3989 3990 Element.Properties.events = {set: function(events){ 3991 this.addEvents(events); 3992 }}; 3993 3994 [Element, Window, Document].invoke('implement', { 3995 3996 addEvent: function(type, fn){ 3997 var events = this.retrieve('events', {}); 3998 if (!events[type]) events[type] = {keys: [], values: []}; 3999 if (events[type].keys.contains(fn)) return this; 4000 events[type].keys.push(fn); 4001 var realType = type, 4002 custom = Element.Events[type], 4003 condition = fn, 4004 self = this; 4005 if (custom){ 4006 if (custom.onAdd) custom.onAdd.call(this, fn, type); 4007 if (custom.condition){ 4008 condition = function(event){ 4009 if (custom.condition.call(this, event, type)) return fn.call(this, event); 4010 return true; 4011 }; 4012 } 4013 if (custom.base) realType = Function.from(custom.base).call(this, type); 4014 } 4015 var defn = function(){ 4016 return fn.call(self); 4017 }; 4018 var nativeEvent = Element.NativeEvents[realType]; 4019 if (nativeEvent){ 4020 if (nativeEvent == 2){ 4021 defn = function(event){ 4022 event = new DOMEvent(event, self.getWindow()); 4023 if (condition.call(self, event) === false) event.stop(); 4024 }; 4025 } 4026 this.addListener(realType, defn, arguments[2]); 4027 } 4028 events[type].values.push(defn); 4029 return this; 4030 }, 4031 4032 removeEvent: function(type, fn){ 4033 var events = this.retrieve('events'); 4034 if (!events || !events[type]) return this; 4035 var list = events[type]; 4036 var index = list.keys.indexOf(fn); 4037 if (index == -1) return this; 4038 var value = list.values[index]; 4039 delete list.keys[index]; 4040 delete list.values[index]; 4041 var custom = Element.Events[type]; 4042 if (custom){ 4043 if (custom.onRemove) custom.onRemove.call(this, fn, type); 4044 if (custom.base) type = Function.from(custom.base).call(this, type); 4045 } 4046 return (Element.NativeEvents[type]) ? this.removeListener(type, value, arguments[2]) : this; 4047 }, 4048 4049 addEvents: function(events){ 4050 for (var event in events) this.addEvent(event, events[event]); 4051 return this; 4052 }, 4053 4054 removeEvents: function(events){ 4055 var type; 4056 if (typeOf(events) == 'object'){ 4057 for (type in events) this.removeEvent(type, events[type]); 4058 return this; 4059 } 4060 var attached = this.retrieve('events'); 4061 if (!attached) return this; 4062 if (!events){ 4063 for (type in attached) this.removeEvents(type); 4064 this.eliminate('events'); 4065 } else if (attached[events]){ 4066 attached[events].keys.each(function(fn){ 4067 this.removeEvent(events, fn); 4068 }, this); 4069 delete attached[events]; 4070 } 4071 return this; 4072 }, 4073 4074 fireEvent: function(type, args, delay){ 4075 var events = this.retrieve('events'); 4076 if (!events || !events[type]) return this; 4077 args = Array.from(args); 4078 4079 events[type].keys.each(function(fn){ 4080 if (delay) fn.delay(delay, this, args); 4081 else fn.apply(this, args); 4082 }, this); 4083 return this; 4084 }, 4085 4086 cloneEvents: function(from, type){ 4087 from = document.id(from); 4088 var events = from.retrieve('events'); 4089 if (!events) return this; 4090 if (!type){ 4091 for (var eventType in events) this.cloneEvents(from, eventType); 4092 } else if (events[type]){ 4093 events[type].keys.each(function(fn){ 4094 this.addEvent(type, fn); 4095 }, this); 4096 } 4097 return this; 4098 } 4099 4100 }); 4101 4102 Element.NativeEvents = { 4103 click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons 4104 mousewheel: 2, DOMMouseScroll: 2, //mouse wheel 4105 mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement 4106 keydown: 2, keypress: 2, keyup: 2, //keyboard 4107 orientationchange: 2, // mobile 4108 touchstart: 2, touchmove: 2, touchend: 2, touchcancel: 2, // touch 4109 gesturestart: 2, gesturechange: 2, gestureend: 2, // gesture 4110 focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, paste: 2, input: 2, //form elements 4111 load: 2, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window 4112 hashchange: 1, popstate: 2, // history 4113 error: 1, abort: 1, scroll: 1 //misc 4114 }; 4115 4116 Element.Events = { 4117 mousewheel: { 4118 base: 'onwheel' in document ? 'wheel' : 'onmousewheel' in document ? 'mousewheel' : 'DOMMouseScroll' 4119 } 4120 }; 4121 4122 var check = function(event){ 4123 var related = event.relatedTarget; 4124 if (related == null) return true; 4125 if (!related) return false; 4126 return (related != this && related.prefix != 'xul' && typeOf(this) != 'document' && !this.contains(related)); 4127 }; 4128 4129 if ('onmouseenter' in document.documentElement){ 4130 Element.NativeEvents.mouseenter = Element.NativeEvents.mouseleave = 2; 4131 Element.MouseenterCheck = check; 4132 } else { 4133 Element.Events.mouseenter = { 4134 base: 'mouseover', 4135 condition: check 4136 }; 4137 4138 Element.Events.mouseleave = { 4139 base: 'mouseout', 4140 condition: check 4141 }; 4142 } 4143 4144 /*<ltIE9>*/ 4145 if (!window.addEventListener){ 4146 Element.NativeEvents.propertychange = 2; 4147 Element.Events.change = { 4148 base: function(){ 4149 var type = this.type; 4150 return (this.get('tag') == 'input' && (type == 'radio' || type == 'checkbox')) ? 'propertychange' : 'change'; 4151 }, 4152 condition: function(event){ 4153 return event.type != 'propertychange' || event.event.propertyName == 'checked'; 4154 } 4155 }; 4156 } 4157 /*</ltIE9>*/ 4158 4159 4160 4161 })(); 4162 4163 4164 /* 4165 --- 4166 4167 name: Element.Delegation 4168 4169 description: Extends the Element native object to include the delegate method for more efficient event management. 4170 4171 license: MIT-style license. 4172 4173 requires: [Element.Event] 4174 4175 provides: [Element.Delegation] 4176 4177 ... 4178 */ 4179 4180 (function(){ 4181 4182 var eventListenerSupport = !!window.addEventListener; 4183 4184 Element.NativeEvents.focusin = Element.NativeEvents.focusout = 2; 4185 4186 var bubbleUp = function(self, match, fn, event, target){ 4187 while (target && target != self){ 4188 if (match(target, event)) return fn.call(target, event, target); 4189 target = document.id(target.parentNode); 4190 } 4191 }; 4192 4193 var map = { 4194 mouseenter: { 4195 base: 'mouseover', 4196 condition: Element.MouseenterCheck 4197 }, 4198 mouseleave: { 4199 base: 'mouseout', 4200 condition: Element.MouseenterCheck 4201 }, 4202 focus: { 4203 base: 'focus' + (eventListenerSupport ? '' : 'in'), 4204 capture: true 4205 }, 4206 blur: { 4207 base: eventListenerSupport ? 'blur' : 'focusout', 4208 capture: true 4209 } 4210 }; 4211 4212 /*<ltIE9>*/ 4213 var _key = '$delegation:'; 4214 var formObserver = function(type){ 4215 4216 return { 4217 4218 base: 'focusin', 4219 4220 remove: function(self, uid){ 4221 var list = self.retrieve(_key + type + 'listeners', {})[uid]; 4222 if (list && list.forms) for (var i = list.forms.length; i--;){ 4223 list.forms[i].removeEvent(type, list.fns[i]); 4224 } 4225 }, 4226 4227 listen: function(self, match, fn, event, target, uid){ 4228 var form = (target.get('tag') == 'form') ? target : event.target.getParent('form'); 4229 if (!form) return; 4230 4231 var listeners = self.retrieve(_key + type + 'listeners', {}), 4232 listener = listeners[uid] || {forms: [], fns: []}, 4233 forms = listener.forms, fns = listener.fns; 4234 4235 if (forms.indexOf(form) != -1) return; 4236 forms.push(form); 4237 4238 var _fn = function(event){ 4239 bubbleUp(self, match, fn, event, target); 4240 }; 4241 form.addEvent(type, _fn); 4242 fns.push(_fn); 4243 4244 listeners[uid] = listener; 4245 self.store(_key + type + 'listeners', listeners); 4246 } 4247 }; 4248 }; 4249 4250 var inputObserver = function(type){ 4251 return { 4252 base: 'focusin', 4253 listen: function(self, match, fn, event, target){ 4254 var events = {blur: function(){ 4255 this.removeEvents(events); 4256 }}; 4257 events[type] = function(event){ 4258 bubbleUp(self, match, fn, event, target); 4259 }; 4260 event.target.addEvents(events); 4261 } 4262 }; 4263 }; 4264 4265 if (!eventListenerSupport) Object.append(map, { 4266 submit: formObserver('submit'), 4267 reset: formObserver('reset'), 4268 change: inputObserver('change'), 4269 select: inputObserver('select') 4270 }); 4271 /*</ltIE9>*/ 4272 4273 var proto = Element.prototype, 4274 addEvent = proto.addEvent, 4275 removeEvent = proto.removeEvent; 4276 4277 var relay = function(old, method){ 4278 return function(type, fn, useCapture){ 4279 if (type.indexOf(':relay') == -1) return old.call(this, type, fn, useCapture); 4280 var parsed = Slick.parse(type).expressions[0][0]; 4281 if (parsed.pseudos[0].key != 'relay') return old.call(this, type, fn, useCapture); 4282 var newType = parsed.tag; 4283 parsed.pseudos.slice(1).each(function(pseudo){ 4284 newType += ':' + pseudo.key + (pseudo.value ? '(' + pseudo.value + ')' : ''); 4285 }); 4286 old.call(this, type, fn); 4287 return method.call(this, newType, parsed.pseudos[0].value, fn); 4288 }; 4289 }; 4290 4291 var delegation = { 4292 4293 addEvent: function(type, match, fn){ 4294 var storage = this.retrieve('$delegates', {}), stored = storage[type]; 4295 if (stored) for (var _uid in stored){ 4296 if (stored[_uid].fn == fn && stored[_uid].match == match) return this; 4297 } 4298 4299 var _type = type, _match = match, _fn = fn, _map = map[type] || {}; 4300 type = _map.base || _type; 4301 4302 match = function(target){ 4303 return Slick.match(target, _match); 4304 }; 4305 4306 var elementEvent = Element.Events[_type]; 4307 if (_map.condition || elementEvent && elementEvent.condition){ 4308 var __match = match, condition = _map.condition || elementEvent.condition; 4309 match = function(target, event){ 4310 return __match(target, event) && condition.call(target, event, type); 4311 }; 4312 } 4313 4314 var self = this, uid = String.uniqueID(); 4315 var delegator = _map.listen ? function(event, target){ 4316 if (!target && event && event.target) target = event.target; 4317 if (target) _map.listen(self, match, fn, event, target, uid); 4318 } : function(event, target){ 4319 if (!target && event && event.target) target = event.target; 4320 if (target) bubbleUp(self, match, fn, event, target); 4321 }; 4322 4323 if (!stored) stored = {}; 4324 stored[uid] = { 4325 match: _match, 4326 fn: _fn, 4327 delegator: delegator 4328 }; 4329 storage[_type] = stored; 4330 return addEvent.call(this, type, delegator, _map.capture); 4331 }, 4332 4333 removeEvent: function(type, match, fn, _uid){ 4334 var storage = this.retrieve('$delegates', {}), stored = storage[type]; 4335 if (!stored) return this; 4336 4337 if (_uid){ 4338 var _type = type, delegator = stored[_uid].delegator, _map = map[type] || {}; 4339 type = _map.base || _type; 4340 if (_map.remove) _map.remove(this, _uid); 4341 delete stored[_uid]; 4342 storage[_type] = stored; 4343 return removeEvent.call(this, type, delegator, _map.capture); 4344 } 4345 4346 var __uid, s; 4347 if (fn) for (__uid in stored){ 4348 s = stored[__uid]; 4349 if (s.match == match && s.fn == fn) return delegation.removeEvent.call(this, type, match, fn, __uid); 4350 } else for (__uid in stored){ 4351 s = stored[__uid]; 4352 if (s.match == match) delegation.removeEvent.call(this, type, match, s.fn, __uid); 4353 } 4354 return this; 4355 } 4356 4357 }; 4358 4359 [Element, Window, Document].invoke('implement', { 4360 addEvent: relay(addEvent, delegation.addEvent), 4361 removeEvent: relay(removeEvent, delegation.removeEvent) 4362 }); 4363 4364 })(); 4365 4366 4367 /* 4368 --- 4369 4370 name: Element.Dimensions 4371 4372 description: Contains methods to work with size, scroll, or positioning of Elements and the window object. 4373 4374 license: MIT-style license. 4375 4376 credits: 4377 - Element positioning based on the [qooxdoo](http://qooxdoo.org/) code and smart browser fixes, [LGPL License](http://www.gnu.org/licenses/lgpl.html). 4378 - Viewport dimensions based on [YUI](http://developer.yahoo.com/yui/) code, [BSD License](http://developer.yahoo.com/yui/license.html). 4379 4380 requires: [Element, Element.Style] 4381 4382 provides: [Element.Dimensions] 4383 4384 ... 4385 */ 4386 4387 (function(){ 4388 4389 var element = document.createElement('div'), 4390 child = document.createElement('div'); 4391 element.style.height = '0'; 4392 element.appendChild(child); 4393 var brokenOffsetParent = (child.offsetParent === element); 4394 element = child = null; 4395 4396 var isOffset = function(el){ 4397 return styleString(el, 'position') != 'static' || isBody(el); 4398 }; 4399 4400 var isOffsetStatic = function(el){ 4401 return isOffset(el) || (/^(?:table|td|th)$/i).test(el.tagName); 4402 }; 4403 4404 Element.implement({ 4405 4406 scrollTo: function(x, y){ 4407 if (isBody(this)){ 4408 this.getWindow().scrollTo(x, y); 4409 } else { 4410 this.scrollLeft = x; 4411 this.scrollTop = y; 4412 } 4413 return this; 4414 }, 4415 4416 getSize: function(){ 4417 if (isBody(this)) return this.getWindow().getSize(); 4418 return {x: this.offsetWidth, y: this.offsetHeight}; 4419 }, 4420 4421 getScrollSize: function(){ 4422 if (isBody(this)) return this.getWindow().getScrollSize(); 4423 return {x: this.scrollWidth, y: this.scrollHeight}; 4424 }, 4425 4426 getScroll: function(){ 4427 if (isBody(this)) return this.getWindow().getScroll(); 4428 return {x: this.scrollLeft, y: this.scrollTop}; 4429 }, 4430 4431 getScrolls: function(){ 4432 var element = this.parentNode, position = {x: 0, y: 0}; 4433 while (element && !isBody(element)){ 4434 position.x += element.scrollLeft; 4435 position.y += element.scrollTop; 4436 element = element.parentNode; 4437 } 4438 return position; 4439 }, 4440 4441 getOffsetParent: brokenOffsetParent ? function(){ 4442 var element = this; 4443 if (isBody(element) || styleString(element, 'position') == 'fixed') return null; 4444 4445 var isOffsetCheck = (styleString(element, 'position') == 'static') ? isOffsetStatic : isOffset; 4446 while ((element = element.parentNode)){ 4447 if (isOffsetCheck(element)) return element; 4448 } 4449 return null; 4450 } : function(){ 4451 var element = this; 4452 if (isBody(element) || styleString(element, 'position') == 'fixed') return null; 4453 4454 try { 4455 return element.offsetParent; 4456 } catch(e) {} 4457 return null; 4458 }, 4459 4460 getOffsets: function(){ 4461 var hasGetBoundingClientRect = this.getBoundingClientRect; 4462 4463 if (hasGetBoundingClientRect){ 4464 var bound = this.getBoundingClientRect(), 4465 html = document.id(this.getDocument().documentElement), 4466 htmlScroll = html.getScroll(), 4467 elemScrolls = this.getScrolls(), 4468 isFixed = (styleString(this, 'position') == 'fixed'); 4469 4470 return { 4471 x: bound.left.toInt() + elemScrolls.x + ((isFixed) ? 0 : htmlScroll.x) - html.clientLeft, 4472 y: bound.top.toInt() + elemScrolls.y + ((isFixed) ? 0 : htmlScroll.y) - html.clientTop 4473 }; 4474 } 4475 4476 var element = this, position = {x: 0, y: 0}; 4477 if (isBody(this)) return position; 4478 4479 while (element && !isBody(element)){ 4480 position.x += element.offsetLeft; 4481 position.y += element.offsetTop; 4482 4483 element = element.offsetParent; 4484 } 4485 4486 return position; 4487 }, 4488 4489 getPosition: function(relative){ 4490 var offset = this.getOffsets(), 4491 scroll = this.getScrolls(); 4492 var position = { 4493 x: offset.x - scroll.x, 4494 y: offset.y - scroll.y 4495 }; 4496 4497 if (relative && (relative = document.id(relative))){ 4498 var relativePosition = relative.getPosition(); 4499 return {x: position.x - relativePosition.x - leftBorder(relative), y: position.y - relativePosition.y - topBorder(relative)}; 4500 } 4501 return position; 4502 }, 4503 4504 getCoordinates: function(element){ 4505 if (isBody(this)) return this.getWindow().getCoordinates(); 4506 var position = this.getPosition(element), 4507 size = this.getSize(); 4508 var obj = { 4509 left: position.x, 4510 top: position.y, 4511 width: size.x, 4512 height: size.y 4513 }; 4514 obj.right = obj.left + obj.width; 4515 obj.bottom = obj.top + obj.height; 4516 return obj; 4517 }, 4518 4519 computePosition: function(obj){ 4520 return { 4521 left: obj.x - styleNumber(this, 'margin-left'), 4522 top: obj.y - styleNumber(this, 'margin-top') 4523 }; 4524 }, 4525 4526 setPosition: function(obj){ 4527 return this.setStyles(this.computePosition(obj)); 4528 } 4529 4530 }); 4531 4532 4533 [Document, Window].invoke('implement', { 4534 4535 getSize: function(){ 4536 var doc = getCompatElement(this); 4537 return {x: doc.clientWidth, y: doc.clientHeight}; 4538 }, 4539 4540 getScroll: function(){ 4541 var win = this.getWindow(), doc = getCompatElement(this); 4542 return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop}; 4543 }, 4544 4545 getScrollSize: function(){ 4546 var doc = getCompatElement(this), 4547 min = this.getSize(), 4548 body = this.getDocument().body; 4549 4550 return {x: Math.max(doc.scrollWidth, body.scrollWidth, min.x), y: Math.max(doc.scrollHeight, body.scrollHeight, min.y)}; 4551 }, 4552 4553 getPosition: function(){ 4554 return {x: 0, y: 0}; 4555 }, 4556 4557 getCoordinates: function(){ 4558 var size = this.getSize(); 4559 return {top: 0, left: 0, bottom: size.y, right: size.x, height: size.y, width: size.x}; 4560 } 4561 4562 }); 4563 4564 // private methods 4565 4566 var styleString = Element.getComputedStyle; 4567 4568 function styleNumber(element, style){ 4569 return styleString(element, style).toInt() || 0; 4570 } 4571 4572 function borderBox(element){ 4573 return styleString(element, '-moz-box-sizing') == 'border-box'; 4574 } 4575 4576 function topBorder(element){ 4577 return styleNumber(element, 'border-top-width'); 4578 } 4579 4580 function leftBorder(element){ 4581 return styleNumber(element, 'border-left-width'); 4582 } 4583 4584 function isBody(element){ 4585 return (/^(?:body|html)$/i).test(element.tagName); 4586 } 4587 4588 function getCompatElement(element){ 4589 var doc = element.getDocument(); 4590 return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; 4591 } 4592 4593 })(); 4594 4595 //aliases 4596 Element.alias({position: 'setPosition'}); //compatability 4597 4598 [Window, Document, Element].invoke('implement', { 4599 4600 getHeight: function(){ 4601 return this.getSize().y; 4602 }, 4603 4604 getWidth: function(){ 4605 return this.getSize().x; 4606 }, 4607 4608 getScrollTop: function(){ 4609 return this.getScroll().y; 4610 }, 4611 4612 getScrollLeft: function(){ 4613 return this.getScroll().x; 4614 }, 4615 4616 getScrollHeight: function(){ 4617 return this.getScrollSize().y; 4618 }, 4619 4620 getScrollWidth: function(){ 4621 return this.getScrollSize().x; 4622 }, 4623 4624 getTop: function(){ 4625 return this.getPosition().y; 4626 }, 4627 4628 getLeft: function(){ 4629 return this.getPosition().x; 4630 } 4631 4632 }); 4633 4634 4635 /* 4636 --- 4637 4638 name: Fx 4639 4640 description: Contains the basic animation logic to be extended by all other Fx Classes. 4641 4642 license: MIT-style license. 4643 4644 requires: [Chain, Events, Options] 4645 4646 provides: Fx 4647 4648 ... 4649 */ 4650 4651 (function(){ 4652 4653 var Fx = this.Fx = new Class({ 4654 4655 Implements: [Chain, Events, Options], 4656 4657 options: { 4658 /* 4659 onStart: nil, 4660 onCancel: nil, 4661 onComplete: nil, 4662 */ 4663 fps: 60, 4664 unit: false, 4665 duration: 500, 4666 frames: null, 4667 frameSkip: true, 4668 link: 'ignore' 4669 }, 4670 4671 initialize: function(options){ 4672 this.subject = this.subject || this; 4673 this.setOptions(options); 4674 }, 4675 4676 getTransition: function(){ 4677 return function(p){ 4678 return -(Math.cos(Math.PI * p) - 1) / 2; 4679 }; 4680 }, 4681 4682 step: function(now){ 4683 if (this.options.frameSkip){ 4684 var diff = (this.time != null) ? (now - this.time) : 0, frames = diff / this.frameInterval; 4685 this.time = now; 4686 this.frame += frames; 4687 } else { 4688 this.frame++; 4689 } 4690 4691 if (this.frame < this.frames){ 4692 var delta = this.transition(this.frame / this.frames); 4693 this.set(this.compute(this.from, this.to, delta)); 4694 } else { 4695 this.frame = this.frames; 4696 this.set(this.compute(this.from, this.to, 1)); 4697 this.stop(); 4698 } 4699 }, 4700 4701 set: function(now){ 4702 return now; 4703 }, 4704 4705 compute: function(from, to, delta){ 4706 return Fx.compute(from, to, delta); 4707 }, 4708 4709 check: function(){ 4710 if (!this.isRunning()) return true; 4711 switch (this.options.link){ 4712 case 'cancel': this.cancel(); return true; 4713 case 'chain': this.chain(this.caller.pass(arguments, this)); return false; 4714 } 4715 return false; 4716 }, 4717 4718 start: function(from, to){ 4719 if (!this.check(from, to)) return this; 4720 this.from = from; 4721 this.to = to; 4722 this.frame = (this.options.frameSkip) ? 0 : -1; 4723 this.time = null; 4724 this.transition = this.getTransition(); 4725 var frames = this.options.frames, fps = this.options.fps, duration = this.options.duration; 4726 this.duration = Fx.Durations[duration] || duration.toInt(); 4727 this.frameInterval = 1000 / fps; 4728 this.frames = frames || Math.round(this.duration / this.frameInterval); 4729 this.fireEvent('start', this.subject); 4730 pushInstance.call(this, fps); 4731 return this; 4732 }, 4733 4734 stop: function(){ 4735 if (this.isRunning()){ 4736 this.time = null; 4737 pullInstance.call(this, this.options.fps); 4738 if (this.frames == this.frame){ 4739 this.fireEvent('complete', this.subject); 4740 if (!this.callChain()) this.fireEvent('chainComplete', this.subject); 4741 } else { 4742 this.fireEvent('stop', this.subject); 4743 } 4744 } 4745 return this; 4746 }, 4747 4748 cancel: function(){ 4749 if (this.isRunning()){ 4750 this.time = null; 4751 pullInstance.call(this, this.options.fps); 4752 this.frame = this.frames; 4753 this.fireEvent('cancel', this.subject).clearChain(); 4754 } 4755 return this; 4756 }, 4757 4758 pause: function(){ 4759 if (this.isRunning()){ 4760 this.time = null; 4761 pullInstance.call(this, this.options.fps); 4762 } 4763 return this; 4764 }, 4765 4766 resume: function(){ 4767 if (this.isPaused()) pushInstance.call(this, this.options.fps); 4768 return this; 4769 }, 4770 4771 isRunning: function(){ 4772 var list = instances[this.options.fps]; 4773 return list && list.contains(this); 4774 }, 4775 4776 isPaused: function(){ 4777 return (this.frame < this.frames) && !this.isRunning(); 4778 } 4779 4780 }); 4781 4782 Fx.compute = function(from, to, delta){ 4783 return (to - from) * delta + from; 4784 }; 4785 4786 Fx.Durations = {'short': 250, 'normal': 500, 'long': 1000}; 4787 4788 // global timers 4789 4790 var instances = {}, timers = {}; 4791 4792 var loop = function(){ 4793 var now = Date.now(); 4794 for (var i = this.length; i--;){ 4795 var instance = this[i]; 4796 if (instance) instance.step(now); 4797 } 4798 }; 4799 4800 var pushInstance = function(fps){ 4801 var list = instances[fps] || (instances[fps] = []); 4802 list.push(this); 4803 if (!timers[fps]) timers[fps] = loop.periodical(Math.round(1000 / fps), list); 4804 }; 4805 4806 var pullInstance = function(fps){ 4807 var list = instances[fps]; 4808 if (list){ 4809 list.erase(this); 4810 if (!list.length && timers[fps]){ 4811 delete instances[fps]; 4812 timers[fps] = clearInterval(timers[fps]); 4813 } 4814 } 4815 }; 4816 4817 })(); 4818 4819 4820 /* 4821 --- 4822 4823 name: Fx.CSS 4824 4825 description: Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements. 4826 4827 license: MIT-style license. 4828 4829 requires: [Fx, Element.Style] 4830 4831 provides: Fx.CSS 4832 4833 ... 4834 */ 4835 4836 Fx.CSS = new Class({ 4837 4838 Extends: Fx, 4839 4840 //prepares the base from/to object 4841 4842 prepare: function(element, property, values){ 4843 values = Array.from(values); 4844 var from = values[0], to = values[1]; 4845 if (to == null){ 4846 to = from; 4847 from = element.getStyle(property); 4848 var unit = this.options.unit; 4849 // adapted from: https://github.com/ryanmorr/fx/blob/master/fx.js#L299 4850 if (unit && from && typeof from == 'string' && from.slice(-unit.length) != unit && parseFloat(from) != 0){ 4851 element.setStyle(property, to + unit); 4852 var value = element.getComputedStyle(property); 4853 // IE and Opera support pixelLeft or pixelWidth 4854 if (!(/px$/.test(value))){ 4855 value = element.style[('pixel-' + property).camelCase()]; 4856 if (value == null){ 4857 // adapted from Dean Edwards' http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 4858 var left = element.style.left; 4859 element.style.left = to + unit; 4860 value = element.style.pixelLeft; 4861 element.style.left = left; 4862 } 4863 } 4864 from = (to || 1) / (parseFloat(value) || 1) * (parseFloat(from) || 0); 4865 element.setStyle(property, from + unit); 4866 } 4867 } 4868 return {from: this.parse(from), to: this.parse(to)}; 4869 }, 4870 4871 //parses a value into an array 4872 4873 parse: function(value){ 4874 value = Function.from(value)(); 4875 value = (typeof value == 'string') ? value.split(' ') : Array.from(value); 4876 return value.map(function(val){ 4877 val = String(val); 4878 var found = false; 4879 Object.each(Fx.CSS.Parsers, function(parser, key){ 4880 if (found) return; 4881 var parsed = parser.parse(val); 4882 if (parsed || parsed === 0) found = {value: parsed, parser: parser}; 4883 }); 4884 found = found || {value: val, parser: Fx.CSS.Parsers.String}; 4885 return found; 4886 }); 4887 }, 4888 4889 //computes by a from and to prepared objects, using their parsers. 4890 4891 compute: function(from, to, delta){ 4892 var computed = []; 4893 (Math.min(from.length, to.length)).times(function(i){ 4894 computed.push({value: from[i].parser.compute(from[i].value, to[i].value, delta), parser: from[i].parser}); 4895 }); 4896 computed.$family = Function.from('fx:css:value'); 4897 return computed; 4898 }, 4899 4900 //serves the value as settable 4901 4902 serve: function(value, unit){ 4903 if (typeOf(value) != 'fx:css:value') value = this.parse(value); 4904 var returned = []; 4905 value.each(function(bit){ 4906 returned = returned.concat(bit.parser.serve(bit.value, unit)); 4907 }); 4908 return returned; 4909 }, 4910 4911 //renders the change to an element 4912 4913 render: function(element, property, value, unit){ 4914 element.setStyle(property, this.serve(value, unit)); 4915 }, 4916 4917 //searches inside the page css to find the values for a selector 4918 4919 search: function(selector){ 4920 if (Fx.CSS.Cache[selector]) return Fx.CSS.Cache[selector]; 4921 var to = {}, selectorTest = new RegExp('^' + selector.escapeRegExp() + '$'); 4922 4923 var searchStyles = function(rules){ 4924 Array.each(rules, function(rule, i){ 4925 if (rule.media){ 4926 searchStyles(rule.rules || rule.cssRules); 4927 return; 4928 } 4929 if (!rule.style) return; 4930 var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function(m){ 4931 return m.toLowerCase(); 4932 }) : null; 4933 if (!selectorText || !selectorTest.test(selectorText)) return; 4934 Object.each(Element.Styles, function(value, style){ 4935 if (!rule.style[style] || Element.ShortStyles[style]) return; 4936 value = String(rule.style[style]); 4937 to[style] = ((/^rgb/).test(value)) ? value.rgbToHex() : value; 4938 }); 4939 }); 4940 }; 4941 4942 Array.each(document.styleSheets, function(sheet, j){ 4943 var href = sheet.href; 4944 if (href && href.indexOf('://') > -1 && href.indexOf(document.domain) == -1) return; 4945 var rules = sheet.rules || sheet.cssRules; 4946 searchStyles(rules); 4947 }); 4948 return Fx.CSS.Cache[selector] = to; 4949 } 4950 4951 }); 4952 4953 Fx.CSS.Cache = {}; 4954 4955 Fx.CSS.Parsers = { 4956 4957 Color: { 4958 parse: function(value){ 4959 if (value.match(/^#[0-9a-f]{3,6}$/i)) return value.hexToRgb(true); 4960 return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false; 4961 }, 4962 compute: function(from, to, delta){ 4963 return from.map(function(value, i){ 4964 return Math.round(Fx.compute(from[i], to[i], delta)); 4965 }); 4966 }, 4967 serve: function(value){ 4968 return value.map(Number); 4969 } 4970 }, 4971 4972 Number: { 4973 parse: parseFloat, 4974 compute: Fx.compute, 4975 serve: function(value, unit){ 4976 return (unit) ? value + unit : value; 4977 } 4978 }, 4979 4980 String: { 4981 parse: Function.from(false), 4982 compute: function(zero, one){ 4983 return one; 4984 }, 4985 serve: function(zero){ 4986 return zero; 4987 } 4988 } 4989 4990 }; 4991 4992 4993 4994 4995 /* 4996 --- 4997 4998 name: Fx.Tween 4999 5000 description: Formerly Fx.Style, effect to transition any CSS property for an element. 5001 5002 license: MIT-style license. 5003 5004 requires: Fx.CSS 5005 5006 provides: [Fx.Tween, Element.fade, Element.highlight] 5007 5008 ... 5009 */ 5010 5011 Fx.Tween = new Class({ 5012 5013 Extends: Fx.CSS, 5014 5015 initialize: function(element, options){ 5016 this.element = this.subject = document.id(element); 5017 this.parent(options); 5018 }, 5019 5020 set: function(property, now){ 5021 if (arguments.length == 1){ 5022 now = property; 5023 property = this.property || this.options.property; 5024 } 5025 this.render(this.element, property, now, this.options.unit); 5026 return this; 5027 }, 5028 5029 start: function(property, from, to){ 5030 if (!this.check(property, from, to)) return this; 5031 var args = Array.flatten(arguments); 5032 this.property = this.options.property || args.shift(); 5033 var parsed = this.prepare(this.element, this.property, args); 5034 return this.parent(parsed.from, parsed.to); 5035 } 5036 5037 }); 5038 5039 Element.Properties.tween = { 5040 5041 set: function(options){ 5042 this.get('tween').cancel().setOptions(options); 5043 return this; 5044 }, 5045 5046 get: function(){ 5047 var tween = this.retrieve('tween'); 5048 if (!tween){ 5049 tween = new Fx.Tween(this, {link: 'cancel'}); 5050 this.store('tween', tween); 5051 } 5052 return tween; 5053 } 5054 5055 }; 5056 5057 Element.implement({ 5058 5059 tween: function(property, from, to){ 5060 this.get('tween').start(property, from, to); 5061 return this; 5062 }, 5063 5064 fade: function(how){ 5065 var fade = this.get('tween'), method, args = ['opacity'].append(arguments), toggle; 5066 if (args[1] == null) args[1] = 'toggle'; 5067 switch (args[1]){ 5068 case 'in': method = 'start'; args[1] = 1; break; 5069 case 'out': method = 'start'; args[1] = 0; break; 5070 case 'show': method = 'set'; args[1] = 1; break; 5071 case 'hide': method = 'set'; args[1] = 0; break; 5072 case 'toggle': 5073 var flag = this.retrieve('fade:flag', this.getStyle('opacity') == 1); 5074 method = 'start'; 5075 args[1] = flag ? 0 : 1; 5076 this.store('fade:flag', !flag); 5077 toggle = true; 5078 break; 5079 default: method = 'start'; 5080 } 5081 if (!toggle) this.eliminate('fade:flag'); 5082 fade[method].apply(fade, args); 5083 var to = args[args.length - 1]; 5084 if (method == 'set' || to != 0) this.setStyle('visibility', to == 0 ? 'hidden' : 'visible'); 5085 else fade.chain(function(){ 5086 this.element.setStyle('visibility', 'hidden'); 5087 this.callChain(); 5088 }); 5089 return this; 5090 }, 5091 5092 highlight: function(start, end){ 5093 if (!end){ 5094 end = this.retrieve('highlight:original', this.getStyle('background-color')); 5095 end = (end == 'transparent') ? '#fff' : end; 5096 } 5097 var tween = this.get('tween'); 5098 tween.start('background-color', start || '#ffff88', end).chain(function(){ 5099 this.setStyle('background-color', this.retrieve('highlight:original')); 5100 tween.callChain(); 5101 }.bind(this)); 5102 return this; 5103 } 5104 5105 }); 5106 5107 5108 /* 5109 --- 5110 5111 name: Fx.Morph 5112 5113 description: Formerly Fx.Styles, effect to transition any number of CSS properties for an element using an object of rules, or CSS based selector rules. 5114 5115 license: MIT-style license. 5116 5117 requires: Fx.CSS 5118 5119 provides: Fx.Morph 5120 5121 ... 5122 */ 5123 5124 Fx.Morph = new Class({ 5125 5126 Extends: Fx.CSS, 5127 5128 initialize: function(element, options){ 5129 this.element = this.subject = document.id(element); 5130 this.parent(options); 5131 }, 5132 5133 set: function(now){ 5134 if (typeof now == 'string') now = this.search(now); 5135 for (var p in now) this.render(this.element, p, now[p], this.options.unit); 5136 return this; 5137 }, 5138 5139 compute: function(from, to, delta){ 5140 var now = {}; 5141 for (var p in from) now[p] = this.parent(from[p], to[p], delta); 5142 return now; 5143 }, 5144 5145 start: function(properties){ 5146 if (!this.check(properties)) return this; 5147 if (typeof properties == 'string') properties = this.search(properties); 5148 var from = {}, to = {}; 5149 for (var p in properties){ 5150 var parsed = this.prepare(this.element, p, properties[p]); 5151 from[p] = parsed.from; 5152 to[p] = parsed.to; 5153 } 5154 return this.parent(from, to); 5155 } 5156 5157 }); 5158 5159 Element.Properties.morph = { 5160 5161 set: function(options){ 5162 this.get('morph').cancel().setOptions(options); 5163 return this; 5164 }, 5165 5166 get: function(){ 5167 var morph = this.retrieve('morph'); 5168 if (!morph){ 5169 morph = new Fx.Morph(this, {link: 'cancel'}); 5170 this.store('morph', morph); 5171 } 5172 return morph; 5173 } 5174 5175 }; 5176 5177 Element.implement({ 5178 5179 morph: function(props){ 5180 this.get('morph').start(props); 5181 return this; 5182 } 5183 5184 }); 5185 5186 5187 /* 5188 --- 5189 5190 name: Fx.Transitions 5191 5192 description: Contains a set of advanced transitions to be used with any of the Fx Classes. 5193 5194 license: MIT-style license. 5195 5196 credits: 5197 - Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>, modified and optimized to be used with MooTools. 5198 5199 requires: Fx 5200 5201 provides: Fx.Transitions 5202 5203 ... 5204 */ 5205 5206 Fx.implement({ 5207 5208 getTransition: function(){ 5209 var trans = this.options.transition || Fx.Transitions.Sine.easeInOut; 5210 if (typeof trans == 'string'){ 5211 var data = trans.split(':'); 5212 trans = Fx.Transitions; 5213 trans = trans[data[0]] || trans[data[0].capitalize()]; 5214 if (data[1]) trans = trans['ease' + data[1].capitalize() + (data[2] ? data[2].capitalize() : '')]; 5215 } 5216 return trans; 5217 } 5218 5219 }); 5220 5221 Fx.Transition = function(transition, params){ 5222 params = Array.from(params); 5223 var easeIn = function(pos){ 5224 return transition(pos, params); 5225 }; 5226 return Object.append(easeIn, { 5227 easeIn: easeIn, 5228 easeOut: function(pos){ 5229 return 1 - transition(1 - pos, params); 5230 }, 5231 easeInOut: function(pos){ 5232 return (pos <= 0.5 ? transition(2 * pos, params) : (2 - transition(2 * (1 - pos), params))) / 2; 5233 } 5234 }); 5235 }; 5236 5237 Fx.Transitions = { 5238 5239 linear: function(zero){ 5240 return zero; 5241 } 5242 5243 }; 5244 5245 5246 5247 Fx.Transitions.extend = function(transitions){ 5248 for (var transition in transitions) Fx.Transitions[transition] = new Fx.Transition(transitions[transition]); 5249 }; 5250 5251 Fx.Transitions.extend({ 5252 5253 Pow: function(p, x){ 5254 return Math.pow(p, x && x[0] || 6); 5255 }, 5256 5257 Expo: function(p){ 5258 return Math.pow(2, 8 * (p - 1)); 5259 }, 5260 5261 Circ: function(p){ 5262 return 1 - Math.sin(Math.acos(p)); 5263 }, 5264 5265 Sine: function(p){ 5266 return 1 - Math.cos(p * Math.PI / 2); 5267 }, 5268 5269 Back: function(p, x){ 5270 x = x && x[0] || 1.618; 5271 return Math.pow(p, 2) * ((x + 1) * p - x); 5272 }, 5273 5274 Bounce: function(p){ 5275 var value; 5276 for (var a = 0, b = 1; 1; a += b, b /= 2){ 5277 if (p >= (7 - 4 * a) / 11){ 5278 value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2); 5279 break; 5280 } 5281 } 5282 return value; 5283 }, 5284 5285 Elastic: function(p, x){ 5286 return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x && x[0] || 1) / 3); 5287 } 5288 5289 }); 5290 5291 ['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){ 5292 Fx.Transitions[transition] = new Fx.Transition(function(p){ 5293 return Math.pow(p, i + 2); 5294 }); 5295 }); 5296 5297 5298 /* 5299 --- 5300 5301 name: Request 5302 5303 description: Powerful all purpose Request Class. Uses XMLHTTPRequest. 5304 5305 license: MIT-style license. 5306 5307 requires: [Object, Element, Chain, Events, Options, Browser] 5308 5309 provides: Request 5310 5311 ... 5312 */ 5313 5314 (function(){ 5315 5316 var empty = function(){}, 5317 progressSupport = ('onprogress' in new Browser.Request); 5318 5319 var Request = this.Request = new Class({ 5320 5321 Implements: [Chain, Events, Options], 5322 5323 options: {/* 5324 onRequest: function(){}, 5325 onLoadstart: function(event, xhr){}, 5326 onProgress: function(event, xhr){}, 5327 onComplete: function(){}, 5328 onCancel: function(){}, 5329 onSuccess: function(responseText, responseXML){}, 5330 onFailure: function(xhr){}, 5331 onException: function(headerName, value){}, 5332 onTimeout: function(){}, 5333 user: '', 5334 password: '',*/ 5335 url: '', 5336 data: '', 5337 headers: { 5338 'X-Requested-With': 'XMLHttpRequest', 5339 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' 5340 }, 5341 async: true, 5342 format: false, 5343 method: 'post', 5344 link: 'ignore', 5345 isSuccess: null, 5346 emulation: true, 5347 urlEncoded: true, 5348 encoding: 'utf-8', 5349 evalScripts: false, 5350 evalResponse: false, 5351 timeout: 0, 5352 noCache: false 5353 }, 5354 5355 initialize: function(options){ 5356 this.xhr = new Browser.Request(); 5357 this.setOptions(options); 5358 this.headers = this.options.headers; 5359 }, 5360 5361 onStateChange: function(){ 5362 var xhr = this.xhr; 5363 if (xhr.readyState != 4 || !this.running) return; 5364 this.running = false; 5365 this.status = 0; 5366 Function.attempt(function(){ 5367 var status = xhr.status; 5368 this.status = (status == 1223) ? 204 : status; 5369 }.bind(this)); 5370 xhr.onreadystatechange = empty; 5371 if (progressSupport) xhr.onprogress = xhr.onloadstart = empty; 5372 clearTimeout(this.timer); 5373 5374 this.response = {text: this.xhr.responseText || '', xml: this.xhr.responseXML}; 5375 if (this.options.isSuccess.call(this, this.status)) 5376 this.success(this.response.text, this.response.xml); 5377 else 5378 this.failure(); 5379 }, 5380 5381 isSuccess: function(){ 5382 var status = this.status; 5383 return (status >= 200 && status < 300); 5384 }, 5385 5386 isRunning: function(){ 5387 return !!this.running; 5388 }, 5389 5390 processScripts: function(text){ 5391 if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return Browser.exec(text); 5392 return text.stripScripts(this.options.evalScripts); 5393 }, 5394 5395 success: function(text, xml){ 5396 this.onSuccess(this.processScripts(text), xml); 5397 }, 5398 5399 onSuccess: function(){ 5400 this.fireEvent('complete', arguments).fireEvent('success', arguments).callChain(); 5401 }, 5402 5403 failure: function(){ 5404 this.onFailure(); 5405 }, 5406 5407 onFailure: function(){ 5408 this.fireEvent('complete').fireEvent('failure', this.xhr); 5409 }, 5410 5411 loadstart: function(event){ 5412 this.fireEvent('loadstart', [event, this.xhr]); 5413 }, 5414 5415 progress: function(event){ 5416 this.fireEvent('progress', [event, this.xhr]); 5417 }, 5418 5419 timeout: function(){ 5420 this.fireEvent('timeout', this.xhr); 5421 }, 5422 5423 setHeader: function(name, value){ 5424 this.headers[name] = value; 5425 return this; 5426 }, 5427 5428 getHeader: function(name){ 5429 return Function.attempt(function(){ 5430 return this.xhr.getResponseHeader(name); 5431 }.bind(this)); 5432 }, 5433 5434 check: function(){ 5435 if (!this.running) return true; 5436 switch (this.options.link){ 5437 case 'cancel': this.cancel(); return true; 5438 case 'chain': this.chain(this.caller.pass(arguments, this)); return false; 5439 } 5440 return false; 5441 }, 5442 5443 send: function(options){ 5444 if (!this.check(options)) return this; 5445 5446 this.options.isSuccess = this.options.isSuccess || this.isSuccess; 5447 this.running = true; 5448 5449 var type = typeOf(options); 5450 if (type == 'string' || type == 'element') options = {data: options}; 5451 5452 var old = this.options; 5453 options = Object.append({data: old.data, url: old.url, method: old.method}, options); 5454 var data = options.data, url = String(options.url), method = options.method.toLowerCase(); 5455 5456 switch (typeOf(data)){ 5457 case 'element': data = document.id(data).toQueryString(); break; 5458 case 'object': case 'hash': data = Object.toQueryString(data); 5459 } 5460 5461 if (this.options.format){ 5462 var format = 'format=' + this.options.format; 5463 data = (data) ? format + '&' + data : format; 5464 } 5465 5466 if (this.options.emulation && !['get', 'post'].contains(method)){ 5467 var _method = '_method=' + method; 5468 data = (data) ? _method + '&' + data : _method; 5469 method = 'post'; 5470 } 5471 5472 if (this.options.urlEncoded && ['post', 'put'].contains(method)){ 5473 var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : ''; 5474 this.headers['Content-type'] = 'application/x-www-form-urlencoded' + encoding; 5475 } 5476 5477 if (!url) url = document.location.pathname; 5478 5479 var trimPosition = url.lastIndexOf('/'); 5480 if (trimPosition > -1 && (trimPosition = url.indexOf('#')) > -1) url = url.substr(0, trimPosition); 5481 5482 if (this.options.noCache) 5483 url += (url.indexOf('?') > -1 ? '&' : '?') + String.uniqueID(); 5484 5485 if (data && (method == 'get' || method == 'delete')){ 5486 url += (url.indexOf('?') > -1 ? '&' : '?') + data; 5487 data = null; 5488 } 5489 5490 var xhr = this.xhr; 5491 if (progressSupport){ 5492 xhr.onloadstart = this.loadstart.bind(this); 5493 xhr.onprogress = this.progress.bind(this); 5494 } 5495 5496 xhr.open(method.toUpperCase(), url, this.options.async, this.options.user, this.options.password); 5497 if (this.options.user && 'withCredentials' in xhr) xhr.withCredentials = true; 5498 5499 xhr.onreadystatechange = this.onStateChange.bind(this); 5500 5501 Object.each(this.headers, function(value, key){ 5502 try { 5503 xhr.setRequestHeader(key, value); 5504 } catch (e){ 5505 this.fireEvent('exception', [key, value]); 5506 } 5507 }, this); 5508 5509 this.fireEvent('request'); 5510 xhr.send(data); 5511 if (!this.options.async) this.onStateChange(); 5512 else if (this.options.timeout) this.timer = this.timeout.delay(this.options.timeout, this); 5513 return this; 5514 }, 5515 5516 cancel: function(){ 5517 if (!this.running) return this; 5518 this.running = false; 5519 var xhr = this.xhr; 5520 xhr.abort(); 5521 clearTimeout(this.timer); 5522 xhr.onreadystatechange = empty; 5523 if (progressSupport) xhr.onprogress = xhr.onloadstart = empty; 5524 this.xhr = new Browser.Request(); 5525 this.fireEvent('cancel'); 5526 return this; 5527 } 5528 5529 }); 5530 5531 var methods = {}; 5532 ['get', 'post', 'put', 'delete', 'GET', 'POST', 'PUT', 'DELETE'].each(function(method){ 5533 methods[method] = function(data){ 5534 var object = { 5535 method: method 5536 }; 5537 if (data != null) object.data = data; 5538 return this.send(object); 5539 }; 5540 }); 5541 5542 Request.implement(methods); 5543 5544 Element.Properties.send = { 5545 5546 set: function(options){ 5547 var send = this.get('send').cancel(); 5548 send.setOptions(options); 5549 return this; 5550 }, 5551 5552 get: function(){ 5553 var send = this.retrieve('send'); 5554 if (!send){ 5555 send = new Request({ 5556 data: this, link: 'cancel', method: this.get('method') || 'post', url: this.get('action') 5557 }); 5558 this.store('send', send); 5559 } 5560 return send; 5561 } 5562 5563 }; 5564 5565 Element.implement({ 5566 5567 send: function(url){ 5568 var sender = this.get('send'); 5569 sender.send({data: this, url: url || sender.options.url}); 5570 return this; 5571 } 5572 5573 }); 5574 5575 })(); 5576 5577 5578 /* 5579 --- 5580 5581 name: Request.HTML 5582 5583 description: Extends the basic Request Class with additional methods for interacting with HTML responses. 5584 5585 license: MIT-style license. 5586 5587 requires: [Element, Request] 5588 5589 provides: Request.HTML 5590 5591 ... 5592 */ 5593 5594 Request.HTML = new Class({ 5595 5596 Extends: Request, 5597 5598 options: { 5599 update: false, 5600 append: false, 5601 evalScripts: true, 5602 filter: false, 5603 headers: { 5604 Accept: 'text/html, application/xml, text/xml, */*' 5605 } 5606 }, 5607 5608 success: function(text){ 5609 var options = this.options, response = this.response; 5610 5611 response.html = text.stripScripts(function(script){ 5612 response.javascript = script; 5613 }); 5614 5615 var match = response.html.match(/<body[^>]*>([\s\S]*?)<\/body>/i); 5616 if (match) response.html = match[1]; 5617 var temp = new Element('div').set('html', response.html); 5618 5619 response.tree = temp.childNodes; 5620 response.elements = temp.getElements(options.filter || '*'); 5621 5622 if (options.filter) response.tree = response.elements; 5623 if (options.update){ 5624 var update = document.id(options.update).empty(); 5625 if (options.filter) update.adopt(response.elements); 5626 else update.set('html', response.html); 5627 } else if (options.append){ 5628 var append = document.id(options.append); 5629 if (options.filter) response.elements.reverse().inject(append); 5630 else append.adopt(temp.getChildren()); 5631 } 5632 if (options.evalScripts) Browser.exec(response.javascript); 5633 5634 this.onSuccess(response.tree, response.elements, response.html, response.javascript); 5635 } 5636 5637 }); 5638 5639 Element.Properties.load = { 5640 5641 set: function(options){ 5642 var load = this.get('load').cancel(); 5643 load.setOptions(options); 5644 return this; 5645 }, 5646 5647 get: function(){ 5648 var load = this.retrieve('load'); 5649 if (!load){ 5650 load = new Request.HTML({data: this, link: 'cancel', update: this, method: 'get'}); 5651 this.store('load', load); 5652 } 5653 return load; 5654 } 5655 5656 }; 5657 5658 Element.implement({ 5659 5660 load: function(){ 5661 this.get('load').send(Array.link(arguments, {data: Type.isObject, url: Type.isString})); 5662 return this; 5663 } 5664 5665 }); 5666 5667 5668 /* 5669 --- 5670 5671 name: JSON 5672 5673 description: JSON encoder and decoder. 5674 5675 license: MIT-style license. 5676 5677 SeeAlso: <http://www.json.org/> 5678 5679 requires: [Array, String, Number, Function] 5680 5681 provides: JSON 5682 5683 ... 5684 */ 5685 5686 if (typeof JSON == 'undefined') this.JSON = {}; 5687 5688 5689 5690 (function(){ 5691 5692 var special = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'}; 5693 5694 var escape = function(chr){ 5695 return special[chr] || '\\u' + ('0000' + chr.charCodeAt(0).toString(16)).slice(-4); 5696 }; 5697 5698 JSON.validate = function(string){ 5699 string = string.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'). 5700 replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'). 5701 replace(/(?:^|:|,)(?:\s*\[)+/g, ''); 5702 5703 return (/^[\],:{}\s]*$/).test(string); 5704 }; 5705 5706 JSON.encode = JSON.stringify ? function(obj){ 5707 return JSON.stringify(obj); 5708 } : function(obj){ 5709 if (obj && obj.toJSON) obj = obj.toJSON(); 5710 5711 switch (typeOf(obj)){ 5712 case 'string': 5713 return '"' + obj.replace(/[\x00-\x1f\\"]/g, escape) + '"'; 5714 case 'array': 5715 return '[' + obj.map(JSON.encode).clean() + ']'; 5716 case 'object': case 'hash': 5717 var string = []; 5718 Object.each(obj, function(value, key){ 5719 var json = JSON.encode(value); 5720 if (json) string.push(JSON.encode(key) + ':' + json); 5721 }); 5722 return '{' + string + '}'; 5723 case 'number': case 'boolean': return '' + obj; 5724 case 'null': return 'null'; 5725 } 5726 5727 return null; 5728 }; 5729 5730 JSON.secure = true; 5731 5732 5733 JSON.decode = function(string, secure){ 5734 if (!string || typeOf(string) != 'string') return null; 5735 5736 if (secure == null) secure = JSON.secure; 5737 if (secure){ 5738 if (JSON.parse) return JSON.parse(string); 5739 if (!JSON.validate(string)) throw new Error('JSON could not decode the input; security is enabled and the value is not secure.'); 5740 } 5741 5742 return eval('(' + string + ')'); 5743 }; 5744 5745 })(); 5746 5747 5748 /* 5749 --- 5750 5751 name: Request.JSON 5752 5753 description: Extends the basic Request Class with additional methods for sending and receiving JSON data. 5754 5755 license: MIT-style license. 5756 5757 requires: [Request, JSON] 5758 5759 provides: Request.JSON 5760 5761 ... 5762 */ 5763 5764 Request.JSON = new Class({ 5765 5766 Extends: Request, 5767 5768 options: { 5769 /*onError: function(text, error){},*/ 5770 secure: true 5771 }, 5772 5773 initialize: function(options){ 5774 this.parent(options); 5775 Object.append(this.headers, { 5776 'Accept': 'application/json', 5777 'X-Request': 'JSON' 5778 }); 5779 }, 5780 5781 success: function(text){ 5782 var json; 5783 try { 5784 json = this.response.json = JSON.decode(text, this.options.secure); 5785 } catch (error){ 5786 this.fireEvent('error', [text, error]); 5787 return; 5788 } 5789 if (json == null) this.onFailure(); 5790 else this.onSuccess(json, text); 5791 } 5792 5793 }); 5794 5795 5796 /* 5797 --- 5798 5799 name: Cookie 5800 5801 description: Class for creating, reading, and deleting browser Cookies. 5802 5803 license: MIT-style license. 5804 5805 credits: 5806 - Based on the functions by Peter-Paul Koch (http://quirksmode.org). 5807 5808 requires: [Options, Browser] 5809 5810 provides: Cookie 5811 5812 ... 5813 */ 5814 5815 var Cookie = new Class({ 5816 5817 Implements: Options, 5818 5819 options: { 5820 path: '/', 5821 domain: false, 5822 duration: false, 5823 secure: false, 5824 document: document, 5825 encode: true 5826 }, 5827 5828 initialize: function(key, options){ 5829 this.key = key; 5830 this.setOptions(options); 5831 }, 5832 5833 write: function(value){ 5834 if (this.options.encode) value = encodeURIComponent(value); 5835 if (this.options.domain) value += '; domain=' + this.options.domain; 5836 if (this.options.path) value += '; path=' + this.options.path; 5837 if (this.options.duration){ 5838 var date = new Date(); 5839 date.setTime(date.getTime() + this.options.duration * 24 * 60 * 60 * 1000); 5840 value += '; expires=' + date.toGMTString(); 5841 } 5842 if (this.options.secure) value += '; secure'; 5843 this.options.document.cookie = this.key + '=' + value; 5844 return this; 5845 }, 5846 5847 read: function(){ 5848 var value = this.options.document.cookie.match('(?:^|;)\\s*' + this.key.escapeRegExp() + '=([^;]*)'); 5849 return (value) ? decodeURIComponent(value[1]) : null; 5850 }, 5851 5852 dispose: function(){ 5853 new Cookie(this.key, Object.merge({}, this.options, {duration: -1})).write(''); 5854 return this; 5855 } 5856 5857 }); 5858 5859 Cookie.write = function(key, value, options){ 5860 return new Cookie(key, options).write(value); 5861 }; 5862 5863 Cookie.read = function(key){ 5864 return new Cookie(key).read(); 5865 }; 5866 5867 Cookie.dispose = function(key, options){ 5868 return new Cookie(key, options).dispose(); 5869 }; 5870 5871 5872 /* 5873 --- 5874 5875 name: DOMReady 5876 5877 description: Contains the custom event domready. 5878 5879 license: MIT-style license. 5880 5881 requires: [Browser, Element, Element.Event] 5882 5883 provides: [DOMReady, DomReady] 5884 5885 ... 5886 */ 5887 5888 (function(window, document){ 5889 5890 var ready, 5891 loaded, 5892 checks = [], 5893 shouldPoll, 5894 timer, 5895 testElement = document.createElement('div'); 5896 5897 var domready = function(){ 5898 clearTimeout(timer); 5899 if (ready) return; 5900 Browser.loaded = ready = true; 5901 document.removeListener('DOMContentLoaded', domready).removeListener('readystatechange', check); 5902 5903 document.fireEvent('domready'); 5904 window.fireEvent('domready'); 5905 }; 5906 5907 var check = function(){ 5908 for (var i = checks.length; i--;) if (checks[i]()){ 5909 domready(); 5910 return true; 5911 } 5912 return false; 5913 }; 5914 5915 var poll = function(){ 5916 clearTimeout(timer); 5917 if (!check()) timer = setTimeout(poll, 10); 5918 }; 5919 5920 document.addListener('DOMContentLoaded', domready); 5921 5922 /*<ltIE8>*/ 5923 // doScroll technique by Diego Perini http://javascript.nwbox.com/IEContentLoaded/ 5924 // testElement.doScroll() throws when the DOM is not ready, only in the top window 5925 var doScrollWorks = function(){ 5926 try { 5927 testElement.doScroll(); 5928 return true; 5929 } catch (e){} 5930 return false; 5931 }; 5932 // If doScroll works already, it can't be used to determine domready 5933 // e.g. in an iframe 5934 if (testElement.doScroll && !doScrollWorks()){ 5935 checks.push(doScrollWorks); 5936 shouldPoll = true; 5937 } 5938 /*</ltIE8>*/ 5939 5940 if (document.readyState) checks.push(function(){ 5941 var state = document.readyState; 5942 return (state == 'loaded' || state == 'complete'); 5943 }); 5944 5945 if ('onreadystatechange' in document) document.addListener('readystatechange', check); 5946 else shouldPoll = true; 5947 5948 if (shouldPoll) poll(); 5949 5950 Element.Events.domready = { 5951 onAdd: function(fn){ 5952 if (ready) fn.call(this); 5953 } 5954 }; 5955 5956 // Make sure that domready fires before load 5957 Element.Events.load = { 5958 base: 'load', 5959 onAdd: function(fn){ 5960 if (loaded && this == window) fn.call(this); 5961 }, 5962 condition: function(){ 5963 if (this == window){ 5964 domready(); 5965 delete Element.Events.load; 5966 } 5967 return true; 5968 } 5969 }; 5970 5971 // This is based on the custom load event 5972 window.addEvent('load', function(){ 5973 loaded = true; 5974 }); 5975 5976 })(window, document); 5977 5978