1 /* 2 Script: Core.js 3 MooTools - My Object Oriented JavaScript Tools. 4 5 License: 6 MIT-style license. 7 8 Copyright: 9 Copyright (c) 2006-2008 [Valerio Proietti](http://mad4milk.net/). 10 11 Code & Documentation: 12 [The MooTools production team](http://mootools.net/developers/). 13 14 Inspiration: 15 - 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) 16 - Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php) 17 */ 18 19 var MooTools = { 20 'version': '1.2.2', 21 'build': 'f0491d62fbb7e906789aa3733d6a67d43e5af7c9' 22 }; 23 24 var Native = function(options){ 25 options = options || {}; 26 var name = options.name; 27 var legacy = options.legacy; 28 var protect = options.protect; 29 var methods = options.implement; 30 var generics = options.generics; 31 var initialize = options.initialize; 32 var afterImplement = options.afterImplement || function(){}; 33 var object = initialize || legacy; 34 generics = generics !== false; 35 36 object.constructor = Native; 37 object.$family = {name: 'native'}; 38 if (legacy && initialize) object.prototype = legacy.prototype; 39 object.prototype.constructor = object; 40 41 if (name){ 42 var family = name.toLowerCase(); 43 object.prototype.$family = {name: family}; 44 Native.typize(object, family); 45 } 46 47 var add = function(obj, name, method, force){ 48 if (!protect || force || !obj.prototype[name]) obj.prototype[name] = method; 49 if (generics) Native.genericize(obj, name, protect); 50 afterImplement.call(obj, name, method); 51 return obj; 52 }; 53 54 object.alias = function(a1, a2, a3){ 55 if (typeof a1 == 'string'){ 56 if ((a1 = this.prototype[a1])) return add(this, a2, a1, a3); 57 } 58 for (var a in a1) this.alias(a, a1[a], a2); 59 return this; 60 }; 61 62 object.implement = function(a1, a2, a3){ 63 if (typeof a1 == 'string') return add(this, a1, a2, a3); 64 for (var p in a1) add(this, p, a1[p], a2); 65 return this; 66 }; 67 68 if (methods) object.implement(methods); 69 70 return object; 71 }; 72 73 Native.genericize = function(object, property, check){ 74 if ((!check || !object[property]) && typeof object.prototype[property] == 'function') object[property] = function(){ 75 var args = Array.prototype.slice.call(arguments); 76 return object.prototype[property].apply(args.shift(), args); 77 }; 78 }; 79 80 Native.implement = function(objects, properties){ 81 for (var i = 0, l = objects.length; i < l; i++) objects[i].implement(properties); 82 }; 83 84 Native.typize = function(object, family){ 85 if (!object.type) object.type = function(item){ 86 return ($type(item) === family); 87 }; 88 }; 89 90 (function(){ 91 var natives = {'Array': Array, 'Date': Date, 'Function': Function, 'Number': Number, 'RegExp': RegExp, 'String': String}; 92 for (var n in natives) new Native({name: n, initialize: natives[n], protect: true}); 93 94 var types = {'boolean': Boolean, 'native': Native, 'object': Object}; 95 for (var t in types) Native.typize(types[t], t); 96 97 var generics = { 98 'Array': ["concat", "indexOf", "join", "lastIndexOf", "pop", "push", "reverse", "shift", "slice", "sort", "splice", "toString", "unshift", "valueOf"], 99 'String': ["charAt", "charCodeAt", "concat", "indexOf", "lastIndexOf", "match", "replace", "search", "slice", "split", "substr", "substring", "toLowerCase", "toUpperCase", "valueOf"] 100 }; 101 for (var g in generics){ 102 for (var i = generics[g].length; i--;) Native.genericize(window[g], generics[g][i], true); 103 } 104 })(); 105 106 var Hash = new Native({ 107 108 name: 'Hash', 109 110 initialize: function(object){ 111 if ($type(object) == 'hash') object = $unlink(object.getClean()); 112 for (var key in object) this[key] = object[key]; 113 return this; 114 } 115 116 }); 117 118 Hash.implement({ 119 120 forEach: function(fn, bind){ 121 for (var key in this){ 122 if (this.hasOwnProperty(key)) fn.call(bind, this[key], key, this); 123 } 124 }, 125 126 getClean: function(){ 127 var clean = {}; 128 for (var key in this){ 129 if (this.hasOwnProperty(key)) clean[key] = this[key]; 130 } 131 return clean; 132 }, 133 134 getLength: function(){ 135 var length = 0; 136 for (var key in this){ 137 if (this.hasOwnProperty(key)) length++; 138 } 139 return length; 140 } 141 142 }); 143 144 Hash.alias('forEach', 'each'); 145 146 Array.implement({ 147 148 forEach: function(fn, bind){ 149 for (var i = 0, l = this.length; i < l; i++) fn.call(bind, this[i], i, this); 150 } 151 152 }); 153 154 Array.alias('forEach', 'each'); 155 156 function $A(iterable){ 157 if (iterable.item){ 158 var l = iterable.length, array = new Array(l); 159 while (l--) array[l] = iterable[l]; 160 return array; 161 } 162 return Array.prototype.slice.call(iterable); 163 }; 164 165 function $arguments(i){ 166 return function(){ 167 return arguments[i]; 168 }; 169 }; 170 171 function $chk(obj){ 172 return !!(obj || obj === 0); 173 }; 174 175 function $clear(timer){ 176 clearTimeout(timer); 177 clearInterval(timer); 178 return null; 179 }; 180 181 function $defined(obj){ 182 return (obj != undefined); 183 }; 184 185 function $each(iterable, fn, bind){ 186 var type = $type(iterable); 187 ((type == 'arguments' || type == 'collection' || type == 'array') ? Array : Hash).each(iterable, fn, bind); 188 }; 189 190 function $empty(){}; 191 192 function $extend(original, extended){ 193 for (var key in (extended || {})) original[key] = extended[key]; 194 return original; 195 }; 196 197 function $H(object){ 198 return new Hash(object); 199 }; 200 201 function $lambda(value){ 202 return (typeof value == 'function') ? value : function(){ 203 return value; 204 }; 205 }; 206 207 function $merge(){ 208 var args = Array.slice(arguments); 209 args.unshift({}); 210 return $mixin.apply(null, args); 211 }; 212 213 function $mixin(mix){ 214 for (var i = 1, l = arguments.length; i < l; i++){ 215 var object = arguments[i]; 216 if ($type(object) != 'object') continue; 217 for (var key in object){ 218 var op = object[key], mp = mix[key]; 219 mix[key] = (mp && $type(op) == 'object' && $type(mp) == 'object') ? $mixin(mp, op) : $unlink(op); 220 } 221 } 222 return mix; 223 }; 224 225 function $pick(){ 226 for (var i = 0, l = arguments.length; i < l; i++){ 227 if (arguments[i] != undefined) return arguments[i]; 228 } 229 return null; 230 }; 231 232 function $random(min, max){ 233 return Math.floor(Math.random() * (max - min + 1) + min); 234 }; 235 236 function $splat(obj){ 237 var type = $type(obj); 238 return (type) ? ((type != 'array' && type != 'arguments') ? [obj] : obj) : []; 239 }; 240 241 var $time = Date.now || function(){ 242 return +new Date; 243 }; 244 245 function $try(){ 246 for (var i = 0, l = arguments.length; i < l; i++){ 247 try { 248 return arguments[i](); 249 } catch(e){} 250 } 251 return null; 252 }; 253 254 function $type(obj){ 255 if (obj == undefined) return false; 256 if (obj.$family) return (obj.$family.name == 'number' && !isFinite(obj)) ? false : obj.$family.name; 257 if (obj.nodeName){ 258 switch (obj.nodeType){ 259 case 1: return 'element'; 260 case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace'; 261 } 262 } else if (typeof obj.length == 'number'){ 263 if (obj.callee) return 'arguments'; 264 else if (obj.item) return 'collection'; 265 } 266 return typeof obj; 267 }; 268 269 function $unlink(object){ 270 var unlinked; 271 switch ($type(object)){ 272 case 'object': 273 unlinked = {}; 274 for (var p in object) unlinked[p] = $unlink(object[p]); 275 break; 276 case 'hash': 277 unlinked = new Hash(object); 278 break; 279 case 'array': 280 unlinked = []; 281 for (var i = 0, l = object.length; i < l; i++) unlinked[i] = $unlink(object[i]); 282 break; 283 default: return object; 284 } 285 return unlinked; 286 }; 287 288 289 /* 290 Script: Browser.js 291 The Browser Core. Contains Browser initialization, Window and Document, and the Browser Hash. 292 293 License: 294 MIT-style license. 295 */ 296 297 var Browser = $merge({ 298 299 Engine: {name: 'unknown', version: 0}, 300 301 Platform: {name: (window.orientation != undefined) ? 'ipod' : (navigator.platform.match(/mac|win|linux/i) || ['other'])[0].toLowerCase()}, 302 303 Features: {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)}, 304 305 Plugins: {}, 306 307 Engines: { 308 309 presto: function(){ 310 return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925)); 311 }, 312 313 trident: function(){ 314 return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? 5 : 4); 315 }, 316 317 webkit: function(){ 318 return (navigator.taintEnabled) ? false : ((Browser.Features.xpath) ? ((Browser.Features.query) ? 525 : 420) : 419); 319 }, 320 321 gecko: function(){ 322 return (document.getBoxObjectFor == undefined) ? false : ((document.getElementsByClassName) ? 19 : 18); 323 } 324 325 } 326 327 }, Browser || {}); 328 329 Browser.Platform[Browser.Platform.name] = true; 330 331 Browser.detect = function(){ 332 333 for (var engine in this.Engines){ 334 var version = this.Engines[engine](); 335 if (version){ 336 this.Engine = {name: engine, version: version}; 337 this.Engine[engine] = this.Engine[engine + version] = true; 338 break; 339 } 340 } 341 342 return {name: engine, version: version}; 343 344 }; 345 346 Browser.detect(); 347 348 Browser.Request = function(){ 349 return $try(function(){ 350 return new XMLHttpRequest(); 351 }, function(){ 352 return new ActiveXObject('MSXML2.XMLHTTP'); 353 }); 354 }; 355 356 Browser.Features.xhr = !!(Browser.Request()); 357 358 Browser.Plugins.Flash = (function(){ 359 var version = ($try(function(){ 360 return navigator.plugins['Shockwave Flash'].description; 361 }, function(){ 362 return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version'); 363 }) || '0 r0').match(/\d+/g); 364 return {version: parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build: parseInt(version[2], 10) || 0}; 365 })(); 366 367 function $exec(text){ 368 if (!text) return text; 369 if (window.execScript){ 370 window.execScript(text); 371 } else { 372 var script = document.createElement('script'); 373 script.setAttribute('type', 'text/javascript'); 374 script[(Browser.Engine.webkit && Browser.Engine.version < 420) ? 'innerText' : 'text'] = text; 375 document.head.appendChild(script); 376 document.head.removeChild(script); 377 } 378 return text; 379 }; 380 381 Native.UID = 1; 382 383 var $uid = (Browser.Engine.trident) ? function(item){ 384 return (item.uid || (item.uid = [Native.UID++]))[0]; 385 } : function(item){ 386 return item.uid || (item.uid = Native.UID++); 387 }; 388 389 var Window = new Native({ 390 391 name: 'Window', 392 393 legacy: (Browser.Engine.trident) ? null: window.Window, 394 395 initialize: function(win){ 396 $uid(win); 397 if (!win.Element){ 398 win.Element = $empty; 399 if (Browser.Engine.webkit) win.document.createElement("iframe"); //fixes safari 2 400 win.Element.prototype = (Browser.Engine.webkit) ? window["[[DOMElement.prototype]]"] : {}; 401 } 402 win.document.window = win; 403 return $extend(win, Window.Prototype); 404 }, 405 406 afterImplement: function(property, value){ 407 window[property] = Window.Prototype[property] = value; 408 } 409 410 }); 411 412 Window.Prototype = {$family: {name: 'window'}}; 413 414 new Window(window); 415 416 var Document = new Native({ 417 418 name: 'Document', 419 420 legacy: (Browser.Engine.trident) ? null: window.Document, 421 422 initialize: function(doc){ 423 $uid(doc); 424 doc.head = doc.getElementsByTagName('head')[0]; 425 doc.html = doc.getElementsByTagName('html')[0]; 426 if (Browser.Engine.trident && Browser.Engine.version <= 4) $try(function(){ 427 doc.execCommand("BackgroundImageCache", false, true); 428 }); 429 if (Browser.Engine.trident) doc.window.attachEvent('onunload', function() { 430 doc.window.detachEvent('onunload', arguments.callee); 431 doc.head = doc.html = doc.window = null; 432 }); 433 return $extend(doc, Document.Prototype); 434 }, 435 436 afterImplement: function(property, value){ 437 document[property] = Document.Prototype[property] = value; 438 } 439 440 }); 441 442 Document.Prototype = {$family: {name: 'document'}}; 443 444 new Document(document); 445 446 447 /* 448 Script: Array.js 449 Contains Array Prototypes like each, contains, and erase. 450 451 License: 452 MIT-style license. 453 */ 454 455 Array.implement({ 456 457 every: function(fn, bind){ 458 for (var i = 0, l = this.length; i < l; i++){ 459 if (!fn.call(bind, this[i], i, this)) return false; 460 } 461 return true; 462 }, 463 464 filter: function(fn, bind){ 465 var results = []; 466 for (var i = 0, l = this.length; i < l; i++){ 467 if (fn.call(bind, this[i], i, this)) results.push(this[i]); 468 } 469 return results; 470 }, 471 472 clean: function() { 473 return this.filter($defined); 474 }, 475 476 indexOf: function(item, from){ 477 var len = this.length; 478 for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){ 479 if (this[i] === item) return i; 480 } 481 return -1; 482 }, 483 484 map: function(fn, bind){ 485 var results = []; 486 for (var i = 0, l = this.length; i < l; i++) results[i] = fn.call(bind, this[i], i, this); 487 return results; 488 }, 489 490 some: function(fn, bind){ 491 for (var i = 0, l = this.length; i < l; i++){ 492 if (fn.call(bind, this[i], i, this)) return true; 493 } 494 return false; 495 }, 496 497 associate: function(keys){ 498 var obj = {}, length = Math.min(this.length, keys.length); 499 for (var i = 0; i < length; i++) obj[keys[i]] = this[i]; 500 return obj; 501 }, 502 503 link: function(object){ 504 var result = {}; 505 for (var i = 0, l = this.length; i < l; i++){ 506 for (var key in object){ 507 if (object[key](this[i])){ 508 result[key] = this[i]; 509 delete object[key]; 510 break; 511 } 512 } 513 } 514 return result; 515 }, 516 517 contains: function(item, from){ 518 return this.indexOf(item, from) != -1; 519 }, 520 521 extend: function(array){ 522 for (var i = 0, j = array.length; i < j; i++) this.push(array[i]); 523 return this; 524 }, 525 526 getLast: function(){ 527 return (this.length) ? this[this.length - 1] : null; 528 }, 529 530 getRandom: function(){ 531 return (this.length) ? this[$random(0, this.length - 1)] : null; 532 }, 533 534 include: function(item){ 535 if (!this.contains(item)) this.push(item); 536 return this; 537 }, 538 539 combine: function(array){ 540 for (var i = 0, l = array.length; i < l; i++) this.include(array[i]); 541 return this; 542 }, 543 544 erase: function(item){ 545 for (var i = this.length; i--; i){ 546 if (this[i] === item) this.splice(i, 1); 547 } 548 return this; 549 }, 550 551 empty: function(){ 552 this.length = 0; 553 return this; 554 }, 555 556 flatten: function(){ 557 var array = []; 558 for (var i = 0, l = this.length; i < l; i++){ 559 var type = $type(this[i]); 560 if (!type) continue; 561 array = array.concat((type == 'array' || type == 'collection' || type == 'arguments') ? Array.flatten(this[i]) : this[i]); 562 } 563 return array; 564 }, 565 566 hexToRgb: function(array){ 567 if (this.length != 3) return null; 568 var rgb = this.map(function(value){ 569 if (value.length == 1) value += value; 570 return value.toInt(16); 571 }); 572 return (array) ? rgb : 'rgb(' + rgb + ')'; 573 }, 574 575 rgbToHex: function(array){ 576 if (this.length < 3) return null; 577 if (this.length == 4 && this[3] == 0 && !array) return 'transparent'; 578 var hex = []; 579 for (var i = 0; i < 3; i++){ 580 var bit = (this[i] - 0).toString(16); 581 hex.push((bit.length == 1) ? '0' + bit : bit); 582 } 583 return (array) ? hex : '#' + hex.join(''); 584 } 585 586 }); 587 588 589 /* 590 Script: Function.js 591 Contains Function Prototypes like create, bind, pass, and delay. 592 593 License: 594 MIT-style license. 595 */ 596 597 Function.implement({ 598 599 extend: function(properties){ 600 for (var property in properties) this[property] = properties[property]; 601 return this; 602 }, 603 604 create: function(options){ 605 var self = this; 606 options = options || {}; 607 return function(event){ 608 var args = options.arguments; 609 args = (args != undefined) ? $splat(args) : Array.slice(arguments, (options.event) ? 1 : 0); 610 if (options.event) args = [event || window.event].extend(args); 611 var returns = function(){ 612 return self.apply(options.bind || null, args); 613 }; 614 if (options.delay) return setTimeout(returns, options.delay); 615 if (options.periodical) return setInterval(returns, options.periodical); 616 if (options.attempt) return $try(returns); 617 return returns(); 618 }; 619 }, 620 621 run: function(args, bind){ 622 return this.apply(bind, $splat(args)); 623 }, 624 625 pass: function(args, bind){ 626 return this.create({bind: bind, arguments: args}); 627 }, 628 629 bind: function(bind, args){ 630 return this.create({bind: bind, arguments: args}); 631 }, 632 633 bindWithEvent: function(bind, args){ 634 return this.create({bind: bind, arguments: args, event: true}); 635 }, 636 637 attempt: function(args, bind){ 638 return this.create({bind: bind, arguments: args, attempt: true})(); 639 }, 640 641 delay: function(delay, bind, args){ 642 return this.create({bind: bind, arguments: args, delay: delay})(); 643 }, 644 645 periodical: function(periodical, bind, args){ 646 return this.create({bind: bind, arguments: args, periodical: periodical})(); 647 } 648 649 }); 650 651 652 /* 653 Script: Number.js 654 Contains Number Prototypes like limit, round, times, and ceil. 655 656 License: 657 MIT-style license. 658 */ 659 660 Number.implement({ 661 662 limit: function(min, max){ 663 return Math.min(max, Math.max(min, this)); 664 }, 665 666 round: function(precision){ 667 precision = Math.pow(10, precision || 0); 668 return Math.round(this * precision) / precision; 669 }, 670 671 times: function(fn, bind){ 672 for (var i = 0; i < this; i++) fn.call(bind, i, this); 673 }, 674 675 toFloat: function(){ 676 return parseFloat(this); 677 }, 678 679 toInt: function(base){ 680 return parseInt(this, base || 10); 681 } 682 683 }); 684 685 Number.alias('times', 'each'); 686 687 (function(math){ 688 var methods = {}; 689 math.each(function(name){ 690 if (!Number[name]) methods[name] = function(){ 691 return Math[name].apply(null, [this].concat($A(arguments))); 692 }; 693 }); 694 Number.implement(methods); 695 })(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']); 696 697 698 /* 699 Script: String.js 700 Contains String Prototypes like camelCase, capitalize, test, and toInt. 701 702 License: 703 MIT-style license. 704 */ 705 706 String.implement({ 707 708 test: function(regex, params){ 709 return ((typeof regex == 'string') ? new RegExp(regex, params) : regex).test(this); 710 }, 711 712 contains: function(string, separator){ 713 return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : this.indexOf(string) > -1; 714 }, 715 716 trim: function(){ 717 return this.replace(/^\s+|\s+$/g, ''); 718 }, 719 720 clean: function(){ 721 return this.replace(/\s+/g, ' ').trim(); 722 }, 723 724 camelCase: function(){ 725 return this.replace(/-\D/g, function(match){ 726 return match.charAt(1).toUpperCase(); 727 }); 728 }, 729 730 hyphenate: function(){ 731 return this.replace(/[A-Z]/g, function(match){ 732 return ('-' + match.charAt(0).toLowerCase()); 733 }); 734 }, 735 736 capitalize: function(){ 737 return this.replace(/\b[a-z]/g, function(match){ 738 return match.toUpperCase(); 739 }); 740 }, 741 742 escapeRegExp: function(){ 743 return this.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1'); 744 }, 745 746 toInt: function(base){ 747 return parseInt(this, base || 10); 748 }, 749 750 toFloat: function(){ 751 return parseFloat(this); 752 }, 753 754 hexToRgb: function(array){ 755 var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); 756 return (hex) ? hex.slice(1).hexToRgb(array) : null; 757 }, 758 759 rgbToHex: function(array){ 760 var rgb = this.match(/\d{1,3}/g); 761 return (rgb) ? rgb.rgbToHex(array) : null; 762 }, 763 764 stripScripts: function(option){ 765 var scripts = ''; 766 var text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(){ 767 scripts += arguments[1] + '\n'; 768 return ''; 769 }); 770 if (option === true) $exec(scripts); 771 else if ($type(option) == 'function') option(scripts, text); 772 return text; 773 }, 774 775 substitute: function(object, regexp){ 776 return this.replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){ 777 if (match.charAt(0) == '\\') return match.slice(1); 778 return (object[name] != undefined) ? object[name] : ''; 779 }); 780 } 781 782 }); 783 784 785 /* 786 Script: Hash.js 787 Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects. 788 789 License: 790 MIT-style license. 791 */ 792 793 Hash.implement({ 794 795 has: Object.prototype.hasOwnProperty, 796 797 keyOf: function(value){ 798 for (var key in this){ 799 if (this.hasOwnProperty(key) && this[key] === value) return key; 800 } 801 return null; 802 }, 803 804 hasValue: function(value){ 805 return (Hash.keyOf(this, value) !== null); 806 }, 807 808 extend: function(properties){ 809 Hash.each(properties, function(value, key){ 810 Hash.set(this, key, value); 811 }, this); 812 return this; 813 }, 814 815 combine: function(properties){ 816 Hash.each(properties, function(value, key){ 817 Hash.include(this, key, value); 818 }, this); 819 return this; 820 }, 821 822 erase: function(key){ 823 if (this.hasOwnProperty(key)) delete this[key]; 824 return this; 825 }, 826 827 get: function(key){ 828 return (this.hasOwnProperty(key)) ? this[key] : null; 829 }, 830 831 set: function(key, value){ 832 if (!this[key] || this.hasOwnProperty(key)) this[key] = value; 833 return this; 834 }, 835 836 empty: function(){ 837 Hash.each(this, function(value, key){ 838 delete this[key]; 839 }, this); 840 return this; 841 }, 842 843 include: function(key, value){ 844 if (this[key] == undefined) this[key] = value; 845 return this; 846 }, 847 848 map: function(fn, bind){ 849 var results = new Hash; 850 Hash.each(this, function(value, key){ 851 results.set(key, fn.call(bind, value, key, this)); 852 }, this); 853 return results; 854 }, 855 856 filter: function(fn, bind){ 857 var results = new Hash; 858 Hash.each(this, function(value, key){ 859 if (fn.call(bind, value, key, this)) results.set(key, value); 860 }, this); 861 return results; 862 }, 863 864 every: function(fn, bind){ 865 for (var key in this){ 866 if (this.hasOwnProperty(key) && !fn.call(bind, this[key], key)) return false; 867 } 868 return true; 869 }, 870 871 some: function(fn, bind){ 872 for (var key in this){ 873 if (this.hasOwnProperty(key) && fn.call(bind, this[key], key)) return true; 874 } 875 return false; 876 }, 877 878 getKeys: function(){ 879 var keys = []; 880 Hash.each(this, function(value, key){ 881 keys.push(key); 882 }); 883 return keys; 884 }, 885 886 getValues: function(){ 887 var values = []; 888 Hash.each(this, function(value){ 889 values.push(value); 890 }); 891 return values; 892 }, 893 894 toQueryString: function(base){ 895 var queryString = []; 896 Hash.each(this, function(value, key){ 897 if (base) key = base + '[' + key + ']'; 898 var result; 899 switch ($type(value)){ 900 case 'object': result = Hash.toQueryString(value, key); break; 901 case 'array': 902 var qs = {}; 903 value.each(function(val, i){ 904 qs[i] = val; 905 }); 906 result = Hash.toQueryString(qs, key); 907 break; 908 default: result = key + '=' + encodeURIComponent(value); 909 } 910 if (value != undefined) queryString.push(result); 911 }); 912 913 return queryString.join('&'); 914 } 915 916 }); 917 918 Hash.alias({keyOf: 'indexOf', hasValue: 'contains'}); 919 920 921 /* 922 Script: Event.js 923 Contains the Event Native, to make the event object completely crossbrowser. 924 925 License: 926 MIT-style license. 927 */ 928 929 var Event = new Native({ 930 931 name: 'Event', 932 933 initialize: function(event, win){ 934 win = win || window; 935 var doc = win.document; 936 event = event || win.event; 937 if (event.$extended) return event; 938 this.$extended = true; 939 var type = event.type; 940 var target = event.target || event.srcElement; 941 while (target && target.nodeType == 3) target = target.parentNode; 942 943 if (type.test(/key/)){ 944 var code = event.which || event.keyCode; 945 var key = Event.Keys.keyOf(code); 946 if (type == 'keydown'){ 947 var fKey = code - 111; 948 if (fKey > 0 && fKey < 13) key = 'f' + fKey; 949 } 950 key = key || String.fromCharCode(code).toLowerCase(); 951 } else if (type.match(/(click|mouse|menu)/i)){ 952 doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; 953 var page = { 954 x: event.pageX || event.clientX + doc.scrollLeft, 955 y: event.pageY || event.clientY + doc.scrollTop 956 }; 957 var client = { 958 x: (event.pageX) ? event.pageX - win.pageXOffset : event.clientX, 959 y: (event.pageY) ? event.pageY - win.pageYOffset : event.clientY 960 }; 961 if (type.match(/DOMMouseScroll|mousewheel/)){ 962 var wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3; 963 } 964 var rightClick = (event.which == 3) || (event.button == 2); 965 var related = null; 966 if (type.match(/over|out/)){ 967 switch (type){ 968 case 'mouseover': related = event.relatedTarget || event.fromElement; break; 969 case 'mouseout': related = event.relatedTarget || event.toElement; 970 } 971 if (!(function(){ 972 while (related && related.nodeType == 3) related = related.parentNode; 973 return true; 974 }).create({attempt: Browser.Engine.gecko})()) related = false; 975 } 976 } 977 978 return $extend(this, { 979 event: event, 980 type: type, 981 982 page: page, 983 client: client, 984 rightClick: rightClick, 985 986 wheel: wheel, 987 988 relatedTarget: related, 989 target: target, 990 991 code: code, 992 key: key, 993 994 shift: event.shiftKey, 995 control: event.ctrlKey, 996 alt: event.altKey, 997 meta: event.metaKey 998 }); 999 } 1000 1001 }); 1002 1003 Event.Keys = new Hash({ 1004 'enter': 13, 1005 'up': 38, 1006 'down': 40, 1007 'left': 37, 1008 'right': 39, 1009 'esc': 27, 1010 'space': 32, 1011 'backspace': 8, 1012 'tab': 9, 1013 'delete': 46 1014 }); 1015 1016 Event.implement({ 1017 1018 stop: function(){ 1019 return this.stopPropagation().preventDefault(); 1020 }, 1021 1022 stopPropagation: function(){ 1023 if (this.event.stopPropagation) this.event.stopPropagation(); 1024 else this.event.cancelBubble = true; 1025 return this; 1026 }, 1027 1028 preventDefault: function(){ 1029 if (this.event.preventDefault) this.event.preventDefault(); 1030 else this.event.returnValue = false; 1031 return this; 1032 } 1033 1034 }); 1035 1036 1037 /* 1038 Script: Class.js 1039 Contains the Class Function for easily creating, extending, and implementing reusable Classes. 1040 1041 License: 1042 MIT-style license. 1043 */ 1044 1045 function Class(params){ 1046 1047 if (params instanceof Function) params = {initialize: params}; 1048 1049 var newClass = function(){ 1050 Object.reset(this); 1051 if (newClass._prototyping) return this; 1052 this._current = $empty; 1053 var value = (this.initialize) ? this.initialize.apply(this, arguments) : this; 1054 delete this._current; delete this.caller; 1055 return value; 1056 }.extend(this); 1057 1058 newClass.implement(params); 1059 1060 newClass.constructor = Class; 1061 newClass.prototype.constructor = newClass; 1062 1063 return newClass; 1064 1065 }; 1066 1067 Function.prototype.protect = function(){ 1068 this._protected = true; 1069 return this; 1070 }; 1071 1072 Object.reset = function(object, key){ 1073 1074 if (key == null){ 1075 for (var p in object) Object.reset(object, p); 1076 return object; 1077 } 1078 1079 delete object[key]; 1080 1081 switch ($type(object[key])){ 1082 case 'object': 1083 var F = function(){}; 1084 F.prototype = object[key]; 1085 var i = new F; 1086 object[key] = Object.reset(i); 1087 break; 1088 case 'array': object[key] = $unlink(object[key]); break; 1089 } 1090 1091 return object; 1092 1093 }; 1094 1095 new Native({name: 'Class', initialize: Class}).extend({ 1096 1097 instantiate: function(F){ 1098 F._prototyping = true; 1099 var proto = new F; 1100 delete F._prototyping; 1101 return proto; 1102 }, 1103 1104 wrap: function(self, key, method){ 1105 if (method._origin) method = method._origin; 1106 1107 return function(){ 1108 if (method._protected && this._current == null) throw new Error('The method "' + key + '" cannot be called.'); 1109 var caller = this.caller, current = this._current; 1110 this.caller = current; this._current = arguments.callee; 1111 var result = method.apply(this, arguments); 1112 this._current = current; this.caller = caller; 1113 return result; 1114 }.extend({_owner: self, _origin: method, _name: key}); 1115 1116 } 1117 1118 }); 1119 1120 Class.implement({ 1121 1122 implement: function(key, value){ 1123 1124 if ($type(key) == 'object'){ 1125 for (var p in key) this.implement(p, key[p]); 1126 return this; 1127 } 1128 1129 var mutator = Class.Mutators[key]; 1130 1131 if (mutator){ 1132 value = mutator.call(this, value); 1133 if (value == null) return this; 1134 } 1135 1136 var proto = this.prototype; 1137 1138 switch ($type(value)){ 1139 1140 case 'function': 1141 if (value._hidden) return this; 1142 proto[key] = Class.wrap(this, key, value); 1143 break; 1144 1145 case 'object': 1146 var previous = proto[key]; 1147 if ($type(previous) == 'object') $mixin(previous, value); 1148 else proto[key] = $unlink(value); 1149 break; 1150 1151 case 'array': 1152 proto[key] = $unlink(value); 1153 break; 1154 1155 default: proto[key] = value; 1156 1157 } 1158 1159 return this; 1160 1161 } 1162 1163 }); 1164 1165 Class.Mutators = { 1166 1167 Extends: function(parent){ 1168 1169 this.parent = parent; 1170 this.prototype = Class.instantiate(parent); 1171 1172 this.implement('parent', function(){ 1173 var name = this.caller._name, previous = this.caller._owner.parent.prototype[name]; 1174 if (!previous) throw new Error('The method "' + name + '" has no parent.'); 1175 return previous.apply(this, arguments); 1176 }.protect()); 1177 1178 }, 1179 1180 Implements: function(items){ 1181 $splat(items).each(function(item){ 1182 if (item instanceof Function) item = Class.instantiate(item); 1183 this.implement(item); 1184 }, this); 1185 1186 } 1187 1188 }; 1189 1190 1191 /* 1192 Script: Class.Extras.js 1193 Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks. 1194 1195 License: 1196 MIT-style license. 1197 */ 1198 1199 var Chain = new Class({ 1200 1201 $chain: [], 1202 1203 chain: function(){ 1204 this.$chain.extend(Array.flatten(arguments)); 1205 return this; 1206 }, 1207 1208 callChain: function(){ 1209 return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false; 1210 }, 1211 1212 clearChain: function(){ 1213 this.$chain.empty(); 1214 return this; 1215 } 1216 1217 }); 1218 1219 var Events = new Class({ 1220 1221 $events: {}, 1222 1223 addEvent: function(type, fn, internal){ 1224 type = Events.removeOn(type); 1225 if (fn != $empty){ 1226 this.$events[type] = this.$events[type] || []; 1227 this.$events[type].include(fn); 1228 if (internal) fn.internal = true; 1229 } 1230 return this; 1231 }, 1232 1233 addEvents: function(events){ 1234 for (var type in events) this.addEvent(type, events[type]); 1235 return this; 1236 }, 1237 1238 fireEvent: function(type, args, delay){ 1239 type = Events.removeOn(type); 1240 if (!this.$events || !this.$events[type]) return this; 1241 this.$events[type].each(function(fn){ 1242 fn.create({'bind': this, 'delay': delay, 'arguments': args})(); 1243 }, this); 1244 return this; 1245 }, 1246 1247 removeEvent: function(type, fn){ 1248 type = Events.removeOn(type); 1249 if (!this.$events[type]) return this; 1250 if (!fn.internal) this.$events[type].erase(fn); 1251 return this; 1252 }, 1253 1254 removeEvents: function(events){ 1255 var type; 1256 if ($type(events) == 'object'){ 1257 for (type in events) this.removeEvent(type, events[type]); 1258 return this; 1259 } 1260 if (events) events = Events.removeOn(events); 1261 for (type in this.$events){ 1262 if (events && events != type) continue; 1263 var fns = this.$events[type]; 1264 for (var i = fns.length; i--; i) this.removeEvent(type, fns[i]); 1265 } 1266 return this; 1267 } 1268 1269 }); 1270 1271 Events.removeOn = function(string){ 1272 return string.replace(/^on([A-Z])/, function(full, first) { 1273 return first.toLowerCase(); 1274 }); 1275 }; 1276 1277 var Options = new Class({ 1278 1279 setOptions: function(){ 1280 this.options = $merge.run([this.options].extend(arguments)); 1281 if (!this.addEvent) return this; 1282 for (var option in this.options){ 1283 if ($type(this.options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue; 1284 this.addEvent(option, this.options[option]); 1285 delete this.options[option]; 1286 } 1287 return this; 1288 } 1289 1290 }); 1291 1292 1293 /* 1294 Script: Element.js 1295 One of the most important items in MooTools. Contains the dollar function, the dollars function, and an handful of cross-browser, 1296 time-saver methods to let you easily work with HTML Elements. 1297 1298 License: 1299 MIT-style license. 1300 */ 1301 1302 var Element = new Native({ 1303 1304 name: 'Element', 1305 1306 legacy: window.Element, 1307 1308 initialize: function(tag, props){ 1309 var konstructor = Element.Constructors.get(tag); 1310 if (konstructor) return konstructor(props); 1311 if (typeof tag == 'string') return document.newElement(tag, props); 1312 return $(tag).set(props); 1313 }, 1314 1315 afterImplement: function(key, value){ 1316 Element.Prototype[key] = value; 1317 if (Array[key]) return; 1318 Elements.implement(key, function(){ 1319 var items = [], elements = true; 1320 for (var i = 0, j = this.length; i < j; i++){ 1321 var returns = this[i][key].apply(this[i], arguments); 1322 items.push(returns); 1323 if (elements) elements = ($type(returns) == 'element'); 1324 } 1325 return (elements) ? new Elements(items) : items; 1326 }); 1327 } 1328 1329 }); 1330 1331 Element.Prototype = {$family: {name: 'element'}}; 1332 1333 Element.Constructors = new Hash; 1334 1335 var IFrame = new Native({ 1336 1337 name: 'IFrame', 1338 1339 generics: false, 1340 1341 initialize: function(){ 1342 var params = Array.link(arguments, {properties: Object.type, iframe: $defined}); 1343 var props = params.properties || {}; 1344 var iframe = $(params.iframe) || false; 1345 var onload = props.onload || $empty; 1346 delete props.onload; 1347 props.id = props.name = $pick(props.id, props.name, iframe.id, iframe.name, 'IFrame_' + $time()); 1348 iframe = new Element(iframe || 'iframe', props); 1349 var onFrameLoad = function(){ 1350 var host = $try(function(){ 1351 return iframe.contentWindow.location.host; 1352 }); 1353 if (host && host == window.location.host){ 1354 var win = new Window(iframe.contentWindow); 1355 new Document(iframe.contentWindow.document); 1356 $extend(win.Element.prototype, Element.Prototype); 1357 } 1358 onload.call(iframe.contentWindow, iframe.contentWindow.document); 1359 }; 1360 (window.frames[props.id]) ? onFrameLoad() : iframe.addListener('load', onFrameLoad); 1361 return iframe; 1362 } 1363 1364 }); 1365 1366 var Elements = new Native({ 1367 1368 initialize: function(elements, options){ 1369 options = $extend({ddup: true, cash: true}, options); 1370 elements = elements || []; 1371 if (options.ddup || options.cash){ 1372 var uniques = {}, returned = []; 1373 for (var i = 0, l = elements.length; i < l; i++){ 1374 var el = $.element(elements[i], !options.cash); 1375 if (options.ddup){ 1376 if (uniques[el.uid]) continue; 1377 uniques[el.uid] = true; 1378 } 1379 returned.push(el); 1380 } 1381 elements = returned; 1382 } 1383 return (options.cash) ? $extend(elements, this) : elements; 1384 } 1385 1386 }); 1387 1388 Elements.implement({ 1389 1390 filter: function(filter, bind){ 1391 if (!filter) return this; 1392 return new Elements(Array.filter(this, (typeof filter == 'string') ? function(item){ 1393 return item.match(filter); 1394 } : filter, bind)); 1395 } 1396 1397 }); 1398 1399 Document.implement({ 1400 1401 newElement: function(tag, props){ 1402 if (Browser.Engine.trident && props){ 1403 ['name', 'type', 'checked'].each(function(attribute){ 1404 if (!props[attribute]) return; 1405 tag += ' ' + attribute + '="' + props[attribute] + '"'; 1406 if (attribute != 'checked') delete props[attribute]; 1407 }); 1408 tag = '<' + tag + '>'; 1409 } 1410 return $.element(this.createElement(tag)).set(props); 1411 }, 1412 1413 newTextNode: function(text){ 1414 return this.createTextNode(text); 1415 }, 1416 1417 getDocument: function(){ 1418 return this; 1419 }, 1420 1421 getWindow: function(){ 1422 return this.window; 1423 } 1424 1425 }); 1426 1427 Window.implement({ 1428 1429 $: function(el, nocash){ 1430 if (el && el.$family && el.uid) return el; 1431 var type = $type(el); 1432 return ($[type]) ? $[type](el, nocash, this.document) : null; 1433 }, 1434 1435 $$: function(selector){ 1436 if (arguments.length == 1 && typeof selector == 'string') return this.document.getElements(selector); 1437 var elements = []; 1438 var args = Array.flatten(arguments); 1439 for (var i = 0, l = args.length; i < l; i++){ 1440 var item = args[i]; 1441 switch ($type(item)){ 1442 case 'element': elements.push(item); break; 1443 case 'string': elements.extend(this.document.getElements(item, true)); 1444 } 1445 } 1446 return new Elements(elements); 1447 }, 1448 1449 getDocument: function(){ 1450 return this.document; 1451 }, 1452 1453 getWindow: function(){ 1454 return this; 1455 } 1456 1457 }); 1458 1459 $.string = function(id, nocash, doc){ 1460 id = doc.getElementById(id); 1461 return (id) ? $.element(id, nocash) : null; 1462 }; 1463 1464 $.element = function(el, nocash){ 1465 $uid(el); 1466 if (!nocash && !el.$family && !(/^object|embed$/i).test(el.tagName)){ 1467 var proto = Element.Prototype; 1468 for (var p in proto) el[p] = proto[p]; 1469 }; 1470 return el; 1471 }; 1472 1473 $.object = function(obj, nocash, doc){ 1474 if (obj.toElement) return $.element(obj.toElement(doc), nocash); 1475 return null; 1476 }; 1477 1478 $.textnode = $.whitespace = $.window = $.document = $arguments(0); 1479 1480 Native.implement([Element, Document], { 1481 1482 getElement: function(selector, nocash){ 1483 return $(this.getElements(selector, true)[0] || null, nocash); 1484 }, 1485 1486 getElements: function(tags, nocash){ 1487 tags = tags.split(','); 1488 var elements = []; 1489 var ddup = (tags.length > 1); 1490 tags.each(function(tag){ 1491 var partial = this.getElementsByTagName(tag.trim()); 1492 (ddup) ? elements.extend(partial) : elements = partial; 1493 }, this); 1494 return new Elements(elements, {ddup: ddup, cash: !nocash}); 1495 } 1496 1497 }); 1498 1499 (function(){ 1500 1501 var collected = {}, storage = {}; 1502 var props = {input: 'checked', option: 'selected', textarea: (Browser.Engine.webkit && Browser.Engine.version < 420) ? 'innerHTML' : 'value'}; 1503 1504 var get = function(uid){ 1505 return (storage[uid] || (storage[uid] = {})); 1506 }; 1507 1508 var clean = function(item, retain){ 1509 if (!item) return; 1510 var uid = item.uid; 1511 if (Browser.Engine.trident){ 1512 if (item.clearAttributes){ 1513 var clone = retain && item.cloneNode(false); 1514 item.clearAttributes(); 1515 if (clone) item.mergeAttributes(clone); 1516 } else if (item.removeEvents){ 1517 item.removeEvents(); 1518 } 1519 if ((/object/i).test(item.tagName)){ 1520 for (var p in item){ 1521 if (typeof item[p] == 'function') item[p] = $empty; 1522 } 1523 Element.dispose(item); 1524 } 1525 } 1526 if (!uid) return; 1527 collected[uid] = storage[uid] = null; 1528 }; 1529 1530 var purge = function(){ 1531 Hash.each(collected, clean); 1532 if (Browser.Engine.trident) $A(document.getElementsByTagName('object')).each(clean); 1533 if (window.CollectGarbage) CollectGarbage(); 1534 collected = storage = null; 1535 }; 1536 1537 var walk = function(element, walk, start, match, all, nocash){ 1538 var el = element[start || walk]; 1539 var elements = []; 1540 while (el){ 1541 if (el.nodeType == 1 && (!match || Element.match(el, match))){ 1542 if (!all) return $(el, nocash); 1543 elements.push(el); 1544 } 1545 el = el[walk]; 1546 } 1547 return (all) ? new Elements(elements, {ddup: false, cash: !nocash}) : null; 1548 }; 1549 1550 var attributes = { 1551 'html': 'innerHTML', 1552 'class': 'className', 1553 'for': 'htmlFor', 1554 'text': (Browser.Engine.trident || (Browser.Engine.webkit && Browser.Engine.version < 420)) ? 'innerText' : 'textContent' 1555 }; 1556 var bools = ['compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', 'disabled', 'readonly', 'multiple', 'selected', 'noresize', 'defer']; 1557 var camels = ['value', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan', 'frameBorder', 'maxLength', 'readOnly', 'rowSpan', 'tabIndex', 'useMap']; 1558 1559 bools = bools.associate(bools); 1560 1561 Hash.extend(attributes, bools); 1562 Hash.extend(attributes, camels.associate(camels.map(String.toLowerCase))); 1563 1564 var inserters = { 1565 1566 before: function(context, element){ 1567 if (element.parentNode) element.parentNode.insertBefore(context, element); 1568 }, 1569 1570 after: function(context, element){ 1571 if (!element.parentNode) return; 1572 var next = element.nextSibling; 1573 (next) ? element.parentNode.insertBefore(context, next) : element.parentNode.appendChild(context); 1574 }, 1575 1576 bottom: function(context, element){ 1577 element.appendChild(context); 1578 }, 1579 1580 top: function(context, element){ 1581 var first = element.firstChild; 1582 (first) ? element.insertBefore(context, first) : element.appendChild(context); 1583 } 1584 1585 }; 1586 1587 inserters.inside = inserters.bottom; 1588 1589 Hash.each(inserters, function(inserter, where){ 1590 1591 where = where.capitalize(); 1592 1593 Element.implement('inject' + where, function(el){ 1594 inserter(this, $(el, true)); 1595 return this; 1596 }); 1597 1598 Element.implement('grab' + where, function(el){ 1599 inserter($(el, true), this); 1600 return this; 1601 }); 1602 1603 }); 1604 1605 Element.implement({ 1606 1607 set: function(prop, value){ 1608 switch ($type(prop)){ 1609 case 'object': 1610 for (var p in prop) this.set(p, prop[p]); 1611 break; 1612 case 'string': 1613 var property = Element.Properties.get(prop); 1614 (property && property.set) ? property.set.apply(this, Array.slice(arguments, 1)) : this.setProperty(prop, value); 1615 } 1616 return this; 1617 }, 1618 1619 get: function(prop){ 1620 var property = Element.Properties.get(prop); 1621 return (property && property.get) ? property.get.apply(this, Array.slice(arguments, 1)) : this.getProperty(prop); 1622 }, 1623 1624 erase: function(prop){ 1625 var property = Element.Properties.get(prop); 1626 (property && property.erase) ? property.erase.apply(this) : this.removeProperty(prop); 1627 return this; 1628 }, 1629 1630 setProperty: function(attribute, value){ 1631 var key = attributes[attribute]; 1632 if (value == undefined) return this.removeProperty(attribute); 1633 if (key && bools[attribute]) value = !!value; 1634 (key) ? this[key] = value : this.setAttribute(attribute, '' + value); 1635 return this; 1636 }, 1637 1638 setProperties: function(attributes){ 1639 for (var attribute in attributes) this.setProperty(attribute, attributes[attribute]); 1640 return this; 1641 }, 1642 1643 getProperty: function(attribute){ 1644 var key = attributes[attribute]; 1645 var value = (key) ? this[key] : this.getAttribute(attribute, 2); 1646 return (bools[attribute]) ? !!value : (key) ? value : value || null; 1647 }, 1648 1649 getProperties: function(){ 1650 var args = $A(arguments); 1651 return args.map(this.getProperty, this).associate(args); 1652 }, 1653 1654 removeProperty: function(attribute){ 1655 var key = attributes[attribute]; 1656 (key) ? this[key] = (key && bools[attribute]) ? false : '' : this.removeAttribute(attribute); 1657 return this; 1658 }, 1659 1660 removeProperties: function(){ 1661 Array.each(arguments, this.removeProperty, this); 1662 return this; 1663 }, 1664 1665 hasClass: function(className){ 1666 return this.className.contains(className, ' '); 1667 }, 1668 1669 addClass: function(className){ 1670 if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean(); 1671 return this; 1672 }, 1673 1674 removeClass: function(className){ 1675 this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1'); 1676 return this; 1677 }, 1678 1679 toggleClass: function(className){ 1680 return this.hasClass(className) ? this.removeClass(className) : this.addClass(className); 1681 }, 1682 1683 adopt: function(){ 1684 Array.flatten(arguments).each(function(element){ 1685 element = $(element, true); 1686 if (element) this.appendChild(element); 1687 }, this); 1688 return this; 1689 }, 1690 1691 appendText: function(text, where){ 1692 return this.grab(this.getDocument().newTextNode(text), where); 1693 }, 1694 1695 grab: function(el, where){ 1696 inserters[where || 'bottom']($(el, true), this); 1697 return this; 1698 }, 1699 1700 inject: function(el, where){ 1701 inserters[where || 'bottom'](this, $(el, true)); 1702 return this; 1703 }, 1704 1705 replaces: function(el){ 1706 el = $(el, true); 1707 el.parentNode.replaceChild(this, el); 1708 return this; 1709 }, 1710 1711 wraps: function(el, where){ 1712 el = $(el, true); 1713 return this.replaces(el).grab(el, where); 1714 }, 1715 1716 getPrevious: function(match, nocash){ 1717 return walk(this, 'previousSibling', null, match, false, nocash); 1718 }, 1719 1720 getAllPrevious: function(match, nocash){ 1721 return walk(this, 'previousSibling', null, match, true, nocash); 1722 }, 1723 1724 getNext: function(match, nocash){ 1725 return walk(this, 'nextSibling', null, match, false, nocash); 1726 }, 1727 1728 getAllNext: function(match, nocash){ 1729 return walk(this, 'nextSibling', null, match, true, nocash); 1730 }, 1731 1732 getFirst: function(match, nocash){ 1733 return walk(this, 'nextSibling', 'firstChild', match, false, nocash); 1734 }, 1735 1736 getLast: function(match, nocash){ 1737 return walk(this, 'previousSibling', 'lastChild', match, false, nocash); 1738 }, 1739 1740 getParent: function(match, nocash){ 1741 return walk(this, 'parentNode', null, match, false, nocash); 1742 }, 1743 1744 getParents: function(match, nocash){ 1745 return walk(this, 'parentNode', null, match, true, nocash); 1746 }, 1747 1748 getSiblings: function(match, nocash) { 1749 return this.getParent().getChildren(match, nocash).erase(this); 1750 }, 1751 1752 getChildren: function(match, nocash){ 1753 return walk(this, 'nextSibling', 'firstChild', match, true, nocash); 1754 }, 1755 1756 getWindow: function(){ 1757 return this.ownerDocument.window; 1758 }, 1759 1760 getDocument: function(){ 1761 return this.ownerDocument; 1762 }, 1763 1764 getElementById: function(id, nocash){ 1765 var el = this.ownerDocument.getElementById(id); 1766 if (!el) return null; 1767 for (var parent = el.parentNode; parent != this; parent = parent.parentNode){ 1768 if (!parent) return null; 1769 } 1770 return $.element(el, nocash); 1771 }, 1772 1773 getSelected: function(){ 1774 return new Elements($A(this.options).filter(function(option){ 1775 return option.selected; 1776 })); 1777 }, 1778 1779 getComputedStyle: function(property){ 1780 if (this.currentStyle) return this.currentStyle[property.camelCase()]; 1781 var computed = this.getDocument().defaultView.getComputedStyle(this, null); 1782 return (computed) ? computed.getPropertyValue([property.hyphenate()]) : null; 1783 }, 1784 1785 toQueryString: function(){ 1786 var queryString = []; 1787 this.getElements('input, select, textarea', true).each(function(el){ 1788 if (!el.name || el.disabled) return; 1789 var value = (el.tagName.toLowerCase() == 'select') ? Element.getSelected(el).map(function(opt){ 1790 return opt.value; 1791 }) : ((el.type == 'radio' || el.type == 'checkbox') && !el.checked) ? null : el.value; 1792 $splat(value).each(function(val){ 1793 if (typeof val != 'undefined') queryString.push(el.name + '=' + encodeURIComponent(val)); 1794 }); 1795 }); 1796 return queryString.join('&'); 1797 }, 1798 1799 clone: function(contents, keepid){ 1800 contents = contents !== false; 1801 var clone = this.cloneNode(contents); 1802 var clean = function(node, element){ 1803 if (!keepid) node.removeAttribute('id'); 1804 if (Browser.Engine.trident){ 1805 node.clearAttributes(); 1806 node.mergeAttributes(element); 1807 node.removeAttribute('uid'); 1808 if (node.options){ 1809 var no = node.options, eo = element.options; 1810 for (var j = no.length; j--;) no[j].selected = eo[j].selected; 1811 } 1812 } 1813 var prop = props[element.tagName.toLowerCase()]; 1814 if (prop && element[prop]) node[prop] = element[prop]; 1815 }; 1816 1817 if (contents){ 1818 var ce = clone.getElementsByTagName('*'), te = this.getElementsByTagName('*'); 1819 for (var i = ce.length; i--;) clean(ce[i], te[i]); 1820 } 1821 1822 clean(clone, this); 1823 return $(clone); 1824 }, 1825 1826 destroy: function(){ 1827 Element.empty(this); 1828 Element.dispose(this); 1829 clean(this, true); 1830 return null; 1831 }, 1832 1833 empty: function(){ 1834 $A(this.childNodes).each(function(node){ 1835 Element.destroy(node); 1836 }); 1837 return this; 1838 }, 1839 1840 dispose: function(){ 1841 return (this.parentNode) ? this.parentNode.removeChild(this) : this; 1842 }, 1843 1844 hasChild: function(el){ 1845 el = $(el, true); 1846 if (!el) return false; 1847 if (Browser.Engine.webkit && Browser.Engine.version < 420) return $A(this.getElementsByTagName(el.tagName)).contains(el); 1848 return (this.contains) ? (this != el && this.contains(el)) : !!(this.compareDocumentPosition(el) & 16); 1849 }, 1850 1851 match: function(tag){ 1852 return (!tag || (tag == this) || (Element.get(this, 'tag') == tag)); 1853 } 1854 1855 }); 1856 1857 Native.implement([Element, Window, Document], { 1858 1859 addListener: function(type, fn){ 1860 if (type == 'unload'){ 1861 var old = fn, self = this; 1862 fn = function(){ 1863 self.removeListener('unload', fn); 1864 old(); 1865 }; 1866 } else { 1867 collected[this.uid] = this; 1868 } 1869 if (this.addEventListener) this.addEventListener(type, fn, false); 1870 else this.attachEvent('on' + type, fn); 1871 return this; 1872 }, 1873 1874 removeListener: function(type, fn){ 1875 if (this.removeEventListener) this.removeEventListener(type, fn, false); 1876 else this.detachEvent('on' + type, fn); 1877 return this; 1878 }, 1879 1880 retrieve: function(property, dflt){ 1881 var storage = get(this.uid), prop = storage[property]; 1882 if (dflt != undefined && prop == undefined) prop = storage[property] = dflt; 1883 return $pick(prop); 1884 }, 1885 1886 store: function(property, value){ 1887 var storage = get(this.uid); 1888 storage[property] = value; 1889 return this; 1890 }, 1891 1892 eliminate: function(property){ 1893 var storage = get(this.uid); 1894 delete storage[property]; 1895 return this; 1896 } 1897 1898 }); 1899 1900 window.addListener('unload', purge); 1901 1902 })(); 1903 1904 Element.Properties = new Hash; 1905 1906 Element.Properties.style = { 1907 1908 set: function(style){ 1909 this.style.cssText = style; 1910 }, 1911 1912 get: function(){ 1913 return this.style.cssText; 1914 }, 1915 1916 erase: function(){ 1917 this.style.cssText = ''; 1918 } 1919 1920 }; 1921 1922 Element.Properties.tag = { 1923 1924 get: function(){ 1925 return this.tagName.toLowerCase(); 1926 } 1927 1928 }; 1929 1930 Element.Properties.html = (function(){ 1931 var wrapper = document.createElement('div'); 1932 1933 var translations = { 1934 table: [1, '<table>', '</table>'], 1935 select: [1, '<select>', '</select>'], 1936 tbody: [2, '<table><tbody>', '</tbody></table>'], 1937 tr: [3, '<table><tbody><tr>', '</tr></tbody></table>'] 1938 }; 1939 translations.thead = translations.tfoot = translations.tbody; 1940 1941 var html = { 1942 set: function(){ 1943 var html = Array.flatten(arguments).join(''); 1944 var wrap = Browser.Engine.trident && translations[this.get('tag')]; 1945 if (wrap){ 1946 var first = wrapper; 1947 first.innerHTML = wrap[1] + html + wrap[2]; 1948 for (var i = wrap[0]; i--;) first = first.firstChild; 1949 this.empty().adopt(first.childNodes); 1950 } else { 1951 this.innerHTML = html; 1952 } 1953 } 1954 }; 1955 1956 html.erase = html.set; 1957 1958 return html; 1959 })(); 1960 1961 if (Browser.Engine.webkit && Browser.Engine.version < 420) Element.Properties.text = { 1962 get: function(){ 1963 if (this.innerText) return this.innerText; 1964 var temp = this.ownerDocument.newElement('div', {html: this.innerHTML}).inject(this.ownerDocument.body); 1965 var text = temp.innerText; 1966 temp.destroy(); 1967 return text; 1968 } 1969 }; 1970 1971 1972 /* 1973 Script: Element.Event.js 1974 Contains Element methods for dealing with events, and custom Events. 1975 1976 License: 1977 MIT-style license. 1978 */ 1979 1980 Element.Properties.events = {set: function(events){ 1981 this.addEvents(events); 1982 }}; 1983 1984 Native.implement([Element, Window, Document], { 1985 1986 addEvent: function(type, fn){ 1987 var events = this.retrieve('events', {}); 1988 events[type] = events[type] || {'keys': [], 'values': []}; 1989 if (events[type].keys.contains(fn)) return this; 1990 events[type].keys.push(fn); 1991 var realType = type, custom = Element.Events.get(type), condition = fn, self = this; 1992 if (custom){ 1993 if (custom.onAdd) custom.onAdd.call(this, fn); 1994 if (custom.condition){ 1995 condition = function(event){ 1996 if (custom.condition.call(this, event)) return fn.call(this, event); 1997 return true; 1998 }; 1999 } 2000 realType = custom.base || realType; 2001 } 2002 var defn = function(){ 2003 return fn.call(self); 2004 }; 2005 var nativeEvent = Element.NativeEvents[realType]; 2006 if (nativeEvent){ 2007 if (nativeEvent == 2){ 2008 defn = function(event){ 2009 event = new Event(event, self.getWindow()); 2010 if (condition.call(self, event) === false) event.stop(); 2011 }; 2012 } 2013 this.addListener(realType, defn); 2014 } 2015 events[type].values.push(defn); 2016 return this; 2017 }, 2018 2019 removeEvent: function(type, fn){ 2020 var events = this.retrieve('events'); 2021 if (!events || !events[type]) return this; 2022 var pos = events[type].keys.indexOf(fn); 2023 if (pos == -1) return this; 2024 events[type].keys.splice(pos, 1); 2025 var value = events[type].values.splice(pos, 1)[0]; 2026 var custom = Element.Events.get(type); 2027 if (custom){ 2028 if (custom.onRemove) custom.onRemove.call(this, fn); 2029 type = custom.base || type; 2030 } 2031 return (Element.NativeEvents[type]) ? this.removeListener(type, value) : this; 2032 }, 2033 2034 addEvents: function(events){ 2035 for (var event in events) this.addEvent(event, events[event]); 2036 return this; 2037 }, 2038 2039 removeEvents: function(events){ 2040 var type; 2041 if ($type(events) == 'object'){ 2042 for (type in events) this.removeEvent(type, events[type]); 2043 return this; 2044 } 2045 var attached = this.retrieve('events'); 2046 if (!attached) return this; 2047 if (!events){ 2048 for (type in attached) this.removeEvents(type); 2049 this.eliminate('events'); 2050 } else if (attached[events]){ 2051 while (attached[events].keys[0]) this.removeEvent(events, attached[events].keys[0]); 2052 attached[events] = null; 2053 } 2054 return this; 2055 }, 2056 2057 fireEvent: function(type, args, delay){ 2058 var events = this.retrieve('events'); 2059 if (!events || !events[type]) return this; 2060 events[type].keys.each(function(fn){ 2061 fn.create({'bind': this, 'delay': delay, 'arguments': args})(); 2062 }, this); 2063 return this; 2064 }, 2065 2066 cloneEvents: function(from, type){ 2067 from = $(from); 2068 var fevents = from.retrieve('events'); 2069 if (!fevents) return this; 2070 if (!type){ 2071 for (var evType in fevents) this.cloneEvents(from, evType); 2072 } else if (fevents[type]){ 2073 fevents[type].keys.each(function(fn){ 2074 this.addEvent(type, fn); 2075 }, this); 2076 } 2077 return this; 2078 } 2079 2080 }); 2081 2082 Element.NativeEvents = { 2083 click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons 2084 mousewheel: 2, DOMMouseScroll: 2, //mouse wheel 2085 mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement 2086 keydown: 2, keypress: 2, keyup: 2, //keyboard 2087 focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, //form elements 2088 load: 1, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window 2089 error: 1, abort: 1, scroll: 1 //misc 2090 }; 2091 2092 (function(){ 2093 2094 var $check = function(event){ 2095 var related = event.relatedTarget; 2096 if (related == undefined) return true; 2097 if (related === false) return false; 2098 return ($type(this) != 'document' && related != this && related.prefix != 'xul' && !this.hasChild(related)); 2099 }; 2100 2101 Element.Events = new Hash({ 2102 2103 mouseenter: { 2104 base: 'mouseover', 2105 condition: $check 2106 }, 2107 2108 mouseleave: { 2109 base: 'mouseout', 2110 condition: $check 2111 }, 2112 2113 mousewheel: { 2114 base: (Browser.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel' 2115 } 2116 2117 }); 2118 2119 })(); 2120 2121 2122 /* 2123 Script: Element.Style.js 2124 Contains methods for interacting with the styles of Elements in a fashionable way. 2125 2126 License: 2127 MIT-style license. 2128 */ 2129 2130 Element.Properties.styles = {set: function(styles){ 2131 this.setStyles(styles); 2132 }}; 2133 2134 Element.Properties.opacity = { 2135 2136 set: function(opacity, novisibility){ 2137 if (!novisibility){ 2138 if (opacity == 0){ 2139 if (this.style.visibility != 'hidden') this.style.visibility = 'hidden'; 2140 } else { 2141 if (this.style.visibility != 'visible') this.style.visibility = 'visible'; 2142 } 2143 } 2144 if (!this.currentStyle || !this.currentStyle.hasLayout) this.style.zoom = 1; 2145 if (Browser.Engine.trident) this.style.filter = (opacity == 1) ? '' : 'alpha(opacity=' + opacity * 100 + ')'; 2146 this.style.opacity = opacity; 2147 this.store('opacity', opacity); 2148 }, 2149 2150 get: function(){ 2151 return this.retrieve('opacity', 1); 2152 } 2153 2154 }; 2155 2156 Element.implement({ 2157 2158 setOpacity: function(value){ 2159 return this.set('opacity', value, true); 2160 }, 2161 2162 getOpacity: function(){ 2163 return this.get('opacity'); 2164 }, 2165 2166 setStyle: function(property, value){ 2167 switch (property){ 2168 case 'opacity': return this.set('opacity', parseFloat(value)); 2169 case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat'; 2170 } 2171 property = property.camelCase(); 2172 if ($type(value) != 'string'){ 2173 var map = (Element.Styles.get(property) || '@').split(' '); 2174 value = $splat(value).map(function(val, i){ 2175 if (!map[i]) return ''; 2176 return ($type(val) == 'number') ? map[i].replace('@', Math.round(val)) : val; 2177 }).join(' '); 2178 } else if (value == String(Number(value))){ 2179 value = Math.round(value); 2180 } 2181 this.style[property] = value; 2182 return this; 2183 }, 2184 2185 getStyle: function(property){ 2186 switch (property){ 2187 case 'opacity': return this.get('opacity'); 2188 case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat'; 2189 } 2190 property = property.camelCase(); 2191 var result = this.style[property]; 2192 if (!$chk(result)){ 2193 result = []; 2194 for (var style in Element.ShortStyles){ 2195 if (property != style) continue; 2196 for (var s in Element.ShortStyles[style]) result.push(this.getStyle(s)); 2197 return result.join(' '); 2198 } 2199 result = this.getComputedStyle(property); 2200 } 2201 if (result){ 2202 result = String(result); 2203 var color = result.match(/rgba?\([\d\s,]+\)/); 2204 if (color) result = result.replace(color[0], color[0].rgbToHex()); 2205 } 2206 if (Browser.Engine.presto || (Browser.Engine.trident && !$chk(parseInt(result, 10)))){ 2207 if (property.test(/^(height|width)$/)){ 2208 var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0; 2209 values.each(function(value){ 2210 size += this.getStyle('border-' + value + '-width').toInt() + this.getStyle('padding-' + value).toInt(); 2211 }, this); 2212 return this['offset' + property.capitalize()] - size + 'px'; 2213 } 2214 if ((Browser.Engine.presto) && String(result).test('px')) return result; 2215 if (property.test(/(border(.+)Width|margin|padding)/)) return '0px'; 2216 } 2217 return result; 2218 }, 2219 2220 setStyles: function(styles){ 2221 for (var style in styles) this.setStyle(style, styles[style]); 2222 return this; 2223 }, 2224 2225 getStyles: function(){ 2226 var result = {}; 2227 Array.each(arguments, function(key){ 2228 result[key] = this.getStyle(key); 2229 }, this); 2230 return result; 2231 } 2232 2233 }); 2234 2235 Element.Styles = new Hash({ 2236 left: '@px', top: '@px', bottom: '@px', right: '@px', 2237 width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px', 2238 backgroundColor: 'rgb(@, @, @)', backgroundPosition: '@px @px', color: 'rgb(@, @, @)', 2239 fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)', 2240 margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)', 2241 borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)', 2242 zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@' 2243 }); 2244 2245 Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}}; 2246 2247 ['Top', 'Right', 'Bottom', 'Left'].each(function(direction){ 2248 var Short = Element.ShortStyles; 2249 var All = Element.Styles; 2250 ['margin', 'padding'].each(function(style){ 2251 var sd = style + direction; 2252 Short[style][sd] = All[sd] = '@px'; 2253 }); 2254 var bd = 'border' + direction; 2255 Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)'; 2256 var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color'; 2257 Short[bd] = {}; 2258 Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px'; 2259 Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@'; 2260 Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)'; 2261 }); 2262 2263 2264 /* 2265 Script: Element.Dimensions.js 2266 Contains methods to work with size, scroll, or positioning of Elements and the window object. 2267 2268 License: 2269 MIT-style license. 2270 2271 Credits: 2272 - Element positioning based on the [qooxdoo](http://qooxdoo.org/) code and smart browser fixes, [LGPL License](http://www.gnu.org/licenses/lgpl.html). 2273 - Viewport dimensions based on [YUI](http://developer.yahoo.com/yui/) code, [BSD License](http://developer.yahoo.com/yui/license.html). 2274 */ 2275 2276 (function(){ 2277 2278 Element.implement({ 2279 2280 scrollTo: function(x, y){ 2281 if (isBody(this)){ 2282 this.getWindow().scrollTo(x, y); 2283 } else { 2284 this.scrollLeft = x; 2285 this.scrollTop = y; 2286 } 2287 return this; 2288 }, 2289 2290 getSize: function(){ 2291 if (isBody(this)) return this.getWindow().getSize(); 2292 return {x: this.offsetWidth, y: this.offsetHeight}; 2293 }, 2294 2295 getScrollSize: function(){ 2296 if (isBody(this)) return this.getWindow().getScrollSize(); 2297 return {x: this.scrollWidth, y: this.scrollHeight}; 2298 }, 2299 2300 getScroll: function(){ 2301 if (isBody(this)) return this.getWindow().getScroll(); 2302 return {x: this.scrollLeft, y: this.scrollTop}; 2303 }, 2304 2305 getScrolls: function(){ 2306 var element = this, position = {x: 0, y: 0}; 2307 while (element && !isBody(element)){ 2308 position.x += element.scrollLeft; 2309 position.y += element.scrollTop; 2310 element = element.parentNode; 2311 } 2312 return position; 2313 }, 2314 2315 getOffsetParent: function(){ 2316 var element = this; 2317 if (isBody(element)) return null; 2318 if (!Browser.Engine.trident) return element.offsetParent; 2319 while ((element = element.parentNode) && !isBody(element)){ 2320 if (styleString(element, 'position') != 'static') return element; 2321 } 2322 return null; 2323 }, 2324 2325 getOffsets: function(){ 2326 if (Browser.Engine.trident){ 2327 var bound = this.getBoundingClientRect(), html = this.getDocument().documentElement; 2328 var isFixed = styleString(this, 'position') == 'fixed'; 2329 return { 2330 x: bound.left + ((isFixed) ? 0 : html.scrollLeft) - html.clientLeft, 2331 y: bound.top + ((isFixed) ? 0 : html.scrollTop) - html.clientTop 2332 }; 2333 } 2334 2335 var element = this, position = {x: 0, y: 0}; 2336 if (isBody(this)) return position; 2337 2338 while (element && !isBody(element)){ 2339 position.x += element.offsetLeft; 2340 position.y += element.offsetTop; 2341 2342 if (Browser.Engine.gecko){ 2343 if (!borderBox(element)){ 2344 position.x += leftBorder(element); 2345 position.y += topBorder(element); 2346 } 2347 var parent = element.parentNode; 2348 if (parent && styleString(parent, 'overflow') != 'visible'){ 2349 position.x += leftBorder(parent); 2350 position.y += topBorder(parent); 2351 } 2352 } else if (element != this && Browser.Engine.webkit){ 2353 position.x += leftBorder(element); 2354 position.y += topBorder(element); 2355 } 2356 2357 element = element.offsetParent; 2358 } 2359 if (Browser.Engine.gecko && !borderBox(this)){ 2360 position.x -= leftBorder(this); 2361 position.y -= topBorder(this); 2362 } 2363 return position; 2364 }, 2365 2366 getPosition: function(relative){ 2367 if (isBody(this)) return {x: 0, y: 0}; 2368 var offset = this.getOffsets(), scroll = this.getScrolls(); 2369 var position = {x: offset.x - scroll.x, y: offset.y - scroll.y}; 2370 var relativePosition = (relative && (relative = $(relative))) ? relative.getPosition() : {x: 0, y: 0}; 2371 return {x: position.x - relativePosition.x, y: position.y - relativePosition.y}; 2372 }, 2373 2374 getCoordinates: function(element){ 2375 if (isBody(this)) return this.getWindow().getCoordinates(); 2376 var position = this.getPosition(element), size = this.getSize(); 2377 var obj = {left: position.x, top: position.y, width: size.x, height: size.y}; 2378 obj.right = obj.left + obj.width; 2379 obj.bottom = obj.top + obj.height; 2380 return obj; 2381 }, 2382 2383 computePosition: function(obj){ 2384 return {left: obj.x - styleNumber(this, 'margin-left'), top: obj.y - styleNumber(this, 'margin-top')}; 2385 }, 2386 2387 position: function(obj){ 2388 return this.setStyles(this.computePosition(obj)); 2389 } 2390 2391 }); 2392 2393 Native.implement([Document, Window], { 2394 2395 getSize: function(){ 2396 if (Browser.Engine.presto || Browser.Engine.webkit) { 2397 var win = this.getWindow(); 2398 return {x: win.innerWidth, y: win.innerHeight}; 2399 } 2400 var doc = getCompatElement(this); 2401 return {x: doc.clientWidth, y: doc.clientHeight}; 2402 }, 2403 2404 getScroll: function(){ 2405 var win = this.getWindow(), doc = getCompatElement(this); 2406 return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop}; 2407 }, 2408 2409 getScrollSize: function(){ 2410 var doc = getCompatElement(this), min = this.getSize(); 2411 return {x: Math.max(doc.scrollWidth, min.x), y: Math.max(doc.scrollHeight, min.y)}; 2412 }, 2413 2414 getPosition: function(){ 2415 return {x: 0, y: 0}; 2416 }, 2417 2418 getCoordinates: function(){ 2419 var size = this.getSize(); 2420 return {top: 0, left: 0, bottom: size.y, right: size.x, height: size.y, width: size.x}; 2421 } 2422 2423 }); 2424 2425 // private methods 2426 2427 var styleString = Element.getComputedStyle; 2428 2429 function styleNumber(element, style){ 2430 return styleString(element, style).toInt() || 0; 2431 }; 2432 2433 function borderBox(element){ 2434 return styleString(element, '-moz-box-sizing') == 'border-box'; 2435 }; 2436 2437 function topBorder(element){ 2438 return styleNumber(element, 'border-top-width'); 2439 }; 2440 2441 function leftBorder(element){ 2442 return styleNumber(element, 'border-left-width'); 2443 }; 2444 2445 function isBody(element){ 2446 return (/^(?:body|html)$/i).test(element.tagName); 2447 }; 2448 2449 function getCompatElement(element){ 2450 var doc = element.getDocument(); 2451 return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; 2452 }; 2453 2454 })(); 2455 2456 //aliases 2457 2458 Native.implement([Window, Document, Element], { 2459 2460 getHeight: function(){ 2461 return this.getSize().y; 2462 }, 2463 2464 getWidth: function(){ 2465 return this.getSize().x; 2466 }, 2467 2468 getScrollTop: function(){ 2469 return this.getScroll().y; 2470 }, 2471 2472 getScrollLeft: function(){ 2473 return this.getScroll().x; 2474 }, 2475 2476 getScrollHeight: function(){ 2477 return this.getScrollSize().y; 2478 }, 2479 2480 getScrollWidth: function(){ 2481 return this.getScrollSize().x; 2482 }, 2483 2484 getTop: function(){ 2485 return this.getPosition().y; 2486 }, 2487 2488 getLeft: function(){ 2489 return this.getPosition().x; 2490 } 2491 2492 }); 2493 2494 2495 /* 2496 Script: Selectors.js 2497 Adds advanced CSS Querying capabilities for targeting elements. Also includes pseudoselectors support. 2498 2499 License: 2500 MIT-style license. 2501 */ 2502 2503 Native.implement([Document, Element], { 2504 2505 getElements: function(expression, nocash){ 2506 expression = expression.split(','); 2507 var items, local = {}; 2508 for (var i = 0, l = expression.length; i < l; i++){ 2509 var selector = expression[i], elements = Selectors.Utils.search(this, selector, local); 2510 if (i != 0 && elements.item) elements = $A(elements); 2511 items = (i == 0) ? elements : (items.item) ? $A(items).concat(elements) : items.concat(elements); 2512 } 2513 return new Elements(items, {ddup: (expression.length > 1), cash: !nocash}); 2514 } 2515 2516 }); 2517 2518 Element.implement({ 2519 2520 match: function(selector){ 2521 if (!selector || (selector == this)) return true; 2522 var tagid = Selectors.Utils.parseTagAndID(selector); 2523 var tag = tagid[0], id = tagid[1]; 2524 if (!Selectors.Filters.byID(this, id) || !Selectors.Filters.byTag(this, tag)) return false; 2525 var parsed = Selectors.Utils.parseSelector(selector); 2526 return (parsed) ? Selectors.Utils.filter(this, parsed, {}) : true; 2527 } 2528 2529 }); 2530 2531 var Selectors = {Cache: {nth: {}, parsed: {}}}; 2532 2533 Selectors.RegExps = { 2534 id: (/#([\w-]+)/), 2535 tag: (/^(\w+|\*)/), 2536 quick: (/^(\w+|\*)$/), 2537 splitter: (/\s*([+>~\s])\s*([a-zA-Z#.*:\[])/g), 2538 combined: (/\.([\w-]+)|\[(\w+)(?:([!*^$~|]?=)(["']?)([^\4]*?)\4)?\]|:([\w-]+)(?:\(["']?(.*?)?["']?\)|$)/g) 2539 }; 2540 2541 Selectors.Utils = { 2542 2543 chk: function(item, uniques){ 2544 if (!uniques) return true; 2545 var uid = $uid(item); 2546 if (!uniques[uid]) return uniques[uid] = true; 2547 return false; 2548 }, 2549 2550 parseNthArgument: function(argument){ 2551 if (Selectors.Cache.nth[argument]) return Selectors.Cache.nth[argument]; 2552 var parsed = argument.match(/^([+-]?\d*)?([a-z]+)?([+-]?\d*)?$/); 2553 if (!parsed) return false; 2554 var inta = parseInt(parsed[1], 10); 2555 var a = (inta || inta === 0) ? inta : 1; 2556 var special = parsed[2] || false; 2557 var b = parseInt(parsed[3], 10) || 0; 2558 if (a != 0){ 2559 b--; 2560 while (b < 1) b += a; 2561 while (b >= a) b -= a; 2562 } else { 2563 a = b; 2564 special = 'index'; 2565 } 2566 switch (special){ 2567 case 'n': parsed = {a: a, b: b, special: 'n'}; break; 2568 case 'odd': parsed = {a: 2, b: 0, special: 'n'}; break; 2569 case 'even': parsed = {a: 2, b: 1, special: 'n'}; break; 2570 case 'first': parsed = {a: 0, special: 'index'}; break; 2571 case 'last': parsed = {special: 'last-child'}; break; 2572 case 'only': parsed = {special: 'only-child'}; break; 2573 default: parsed = {a: (a - 1), special: 'index'}; 2574 } 2575 2576 return Selectors.Cache.nth[argument] = parsed; 2577 }, 2578 2579 parseSelector: function(selector){ 2580 if (Selectors.Cache.parsed[selector]) return Selectors.Cache.parsed[selector]; 2581 var m, parsed = {classes: [], pseudos: [], attributes: []}; 2582 while ((m = Selectors.RegExps.combined.exec(selector))){ 2583 var cn = m[1], an = m[2], ao = m[3], av = m[5], pn = m[6], pa = m[7]; 2584 if (cn){ 2585 parsed.classes.push(cn); 2586 } else if (pn){ 2587 var parser = Selectors.Pseudo.get(pn); 2588 if (parser) parsed.pseudos.push({parser: parser, argument: pa}); 2589 else parsed.attributes.push({name: pn, operator: '=', value: pa}); 2590 } else if (an){ 2591 parsed.attributes.push({name: an, operator: ao, value: av}); 2592 } 2593 } 2594 if (!parsed.classes.length) delete parsed.classes; 2595 if (!parsed.attributes.length) delete parsed.attributes; 2596 if (!parsed.pseudos.length) delete parsed.pseudos; 2597 if (!parsed.classes && !parsed.attributes && !parsed.pseudos) parsed = null; 2598 return Selectors.Cache.parsed[selector] = parsed; 2599 }, 2600 2601 parseTagAndID: function(selector){ 2602 var tag = selector.match(Selectors.RegExps.tag); 2603 var id = selector.match(Selectors.RegExps.id); 2604 return [(tag) ? tag[1] : '*', (id) ? id[1] : false]; 2605 }, 2606 2607 filter: function(item, parsed, local){ 2608 var i; 2609 if (parsed.classes){ 2610 for (i = parsed.classes.length; i--; i){ 2611 var cn = parsed.classes[i]; 2612 if (!Selectors.Filters.byClass(item, cn)) return false; 2613 } 2614 } 2615 if (parsed.attributes){ 2616 for (i = parsed.attributes.length; i--; i){ 2617 var att = parsed.attributes[i]; 2618 if (!Selectors.Filters.byAttribute(item, att.name, att.operator, att.value)) return false; 2619 } 2620 } 2621 if (parsed.pseudos){ 2622 for (i = parsed.pseudos.length; i--; i){ 2623 var psd = parsed.pseudos[i]; 2624 if (!Selectors.Filters.byPseudo(item, psd.parser, psd.argument, local)) return false; 2625 } 2626 } 2627 return true; 2628 }, 2629 2630 getByTagAndID: function(ctx, tag, id){ 2631 if (id){ 2632 var item = (ctx.getElementById) ? ctx.getElementById(id, true) : Element.getElementById(ctx, id, true); 2633 return (item && Selectors.Filters.byTag(item, tag)) ? [item] : []; 2634 } else { 2635 return ctx.getElementsByTagName(tag); 2636 } 2637 }, 2638 2639 search: function(self, expression, local){ 2640 var splitters = []; 2641 2642 var selectors = expression.trim().replace(Selectors.RegExps.splitter, function(m0, m1, m2){ 2643 splitters.push(m1); 2644 return ':)' + m2; 2645 }).split(':)'); 2646 2647 var items, filtered, item; 2648 2649 for (var i = 0, l = selectors.length; i < l; i++){ 2650 2651 var selector = selectors[i]; 2652 2653 if (i == 0 && Selectors.RegExps.quick.test(selector)){ 2654 items = self.getElementsByTagName(selector); 2655 continue; 2656 } 2657 2658 var splitter = splitters[i - 1]; 2659 2660 var tagid = Selectors.Utils.parseTagAndID(selector); 2661 var tag = tagid[0], id = tagid[1]; 2662 2663 if (i == 0){ 2664 items = Selectors.Utils.getByTagAndID(self, tag, id); 2665 } else { 2666 var uniques = {}, found = []; 2667 for (var j = 0, k = items.length; j < k; j++) found = Selectors.Getters[splitter](found, items[j], tag, id, uniques); 2668 items = found; 2669 } 2670 2671 var parsed = Selectors.Utils.parseSelector(selector); 2672 2673 if (parsed){ 2674 filtered = []; 2675 for (var m = 0, n = items.length; m < n; m++){ 2676 item = items[m]; 2677 if (Selectors.Utils.filter(item, parsed, local)) filtered.push(item); 2678 } 2679 items = filtered; 2680 } 2681 2682 } 2683 2684 return items; 2685 2686 } 2687 2688 }; 2689 2690 Selectors.Getters = { 2691 2692 ' ': function(found, self, tag, id, uniques){ 2693 var items = Selectors.Utils.getByTagAndID(self, tag, id); 2694 for (var i = 0, l = items.length; i < l; i++){ 2695 var item = items[i]; 2696 if (Selectors.Utils.chk(item, uniques)) found.push(item); 2697 } 2698 return found; 2699 }, 2700 2701 '>': function(found, self, tag, id, uniques){ 2702 var children = Selectors.Utils.getByTagAndID(self, tag, id); 2703 for (var i = 0, l = children.length; i < l; i++){ 2704 var child = children[i]; 2705 if (child.parentNode == self && Selectors.Utils.chk(child, uniques)) found.push(child); 2706 } 2707 return found; 2708 }, 2709 2710 '+': function(found, self, tag, id, uniques){ 2711 while ((self = self.nextSibling)){ 2712 if (self.nodeType == 1){ 2713 if (Selectors.Utils.chk(self, uniques) && Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self); 2714 break; 2715 } 2716 } 2717 return found; 2718 }, 2719 2720 '~': function(found, self, tag, id, uniques){ 2721 while ((self = self.nextSibling)){ 2722 if (self.nodeType == 1){ 2723 if (!Selectors.Utils.chk(self, uniques)) break; 2724 if (Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self); 2725 } 2726 } 2727 return found; 2728 } 2729 2730 }; 2731 2732 Selectors.Filters = { 2733 2734 byTag: function(self, tag){ 2735 return (tag == '*' || (self.tagName && self.tagName.toLowerCase() == tag)); 2736 }, 2737 2738 byID: function(self, id){ 2739 return (!id || (self.id && self.id == id)); 2740 }, 2741 2742 byClass: function(self, klass){ 2743 return (self.className && self.className.contains(klass, ' ')); 2744 }, 2745 2746 byPseudo: function(self, parser, argument, local){ 2747 return parser.call(self, argument, local); 2748 }, 2749 2750 byAttribute: function(self, name, operator, value){ 2751 var result = Element.prototype.getProperty.call(self, name); 2752 if (!result) return (operator == '!='); 2753 if (!operator || value == undefined) return true; 2754 switch (operator){ 2755 case '=': return (result == value); 2756 case '*=': return (result.contains(value)); 2757 case '^=': return (result.substr(0, value.length) == value); 2758 case '$=': return (result.substr(result.length - value.length) == value); 2759 case '!=': return (result != value); 2760 case '~=': return result.contains(value, ' '); 2761 case '|=': return result.contains(value, '-'); 2762 } 2763 return false; 2764 } 2765 2766 }; 2767 2768 Selectors.Pseudo = new Hash({ 2769 2770 // w3c pseudo selectors 2771 2772 checked: function(){ 2773 return this.checked; 2774 }, 2775 2776 empty: function(){ 2777 return !(this.innerText || this.textContent || '').length; 2778 }, 2779 2780 not: function(selector){ 2781 return !Element.match(this, selector); 2782 }, 2783 2784 contains: function(text){ 2785 return (this.innerText || this.textContent || '').contains(text); 2786 }, 2787 2788 'first-child': function(){ 2789 return Selectors.Pseudo.index.call(this, 0); 2790 }, 2791 2792 'last-child': function(){ 2793 var element = this; 2794 while ((element = element.nextSibling)){ 2795 if (element.nodeType == 1) return false; 2796 } 2797 return true; 2798 }, 2799 2800 'only-child': function(){ 2801 var prev = this; 2802 while ((prev = prev.previousSibling)){ 2803 if (prev.nodeType == 1) return false; 2804 } 2805 var next = this; 2806 while ((next = next.nextSibling)){ 2807 if (next.nodeType == 1) return false; 2808 } 2809 return true; 2810 }, 2811 2812 'nth-child': function(argument, local){ 2813 argument = (argument == undefined) ? 'n' : argument; 2814 var parsed = Selectors.Utils.parseNthArgument(argument); 2815 if (parsed.special != 'n') return Selectors.Pseudo[parsed.special].call(this, parsed.a, local); 2816 var count = 0; 2817 local.positions = local.positions || {}; 2818 var uid = $uid(this); 2819 if (!local.positions[uid]){ 2820 var self = this; 2821 while ((self = self.previousSibling)){ 2822 if (self.nodeType != 1) continue; 2823 count ++; 2824 var position = local.positions[$uid(self)]; 2825 if (position != undefined){ 2826 count = position + count; 2827 break; 2828 } 2829 } 2830 local.positions[uid] = count; 2831 } 2832 return (local.positions[uid] % parsed.a == parsed.b); 2833 }, 2834 2835 // custom pseudo selectors 2836 2837 index: function(index){ 2838 var element = this, count = 0; 2839 while ((element = element.previousSibling)){ 2840 if (element.nodeType == 1 && ++count > index) return false; 2841 } 2842 return (count == index); 2843 }, 2844 2845 even: function(argument, local){ 2846 return Selectors.Pseudo['nth-child'].call(this, '2n+1', local); 2847 }, 2848 2849 odd: function(argument, local){ 2850 return Selectors.Pseudo['nth-child'].call(this, '2n', local); 2851 }, 2852 2853 selected: function() { 2854 return this.selected; 2855 } 2856 2857 }); 2858 2859 2860 /* 2861 Script: Domready.js 2862 Contains the domready custom event. 2863 2864 License: 2865 MIT-style license. 2866 */ 2867 2868 Element.Events.domready = { 2869 2870 onAdd: function(fn){ 2871 if (Browser.loaded) fn.call(this); 2872 } 2873 2874 }; 2875 2876 (function(){ 2877 2878 var domready = function(){ 2879 if (Browser.loaded) return; 2880 Browser.loaded = true; 2881 window.fireEvent('domready'); 2882 document.fireEvent('domready'); 2883 }; 2884 2885 if (Browser.Engine.trident){ 2886 var temp = document.createElement('div'); 2887 (function(){ 2888 ($try(function(){ 2889 temp.doScroll('left'); 2890 return $(temp).inject(document.body).set('html', 'temp').dispose(); 2891 })) ? domready() : arguments.callee.delay(50); 2892 })(); 2893 } else if (Browser.Engine.webkit && Browser.Engine.version < 525){ 2894 (function(){ 2895 (['loaded', 'complete'].contains(document.readyState)) ? domready() : arguments.callee.delay(50); 2896 })(); 2897 } else { 2898 window.addEvent('load', domready); 2899 document.addEvent('DOMContentLoaded', domready); 2900 } 2901 2902 })(); 2903 2904 2905 /* 2906 Script: JSON.js 2907 JSON encoder and decoder. 2908 2909 License: 2910 MIT-style license. 2911 2912 See Also: 2913 <http://www.json.org/> 2914 */ 2915 2916 var JSON = new Hash({ 2917 2918 $specialChars: {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'}, 2919 2920 $replaceChars: function(chr){ 2921 return JSON.$specialChars[chr] || '\\u00' + Math.floor(chr.charCodeAt() / 16).toString(16) + (chr.charCodeAt() % 16).toString(16); 2922 }, 2923 2924 encode: function(obj){ 2925 switch ($type(obj)){ 2926 case 'string': 2927 return '"' + obj.replace(/[\x00-\x1f\\"]/g, JSON.$replaceChars) + '"'; 2928 case 'array': 2929 return '[' + String(obj.map(JSON.encode).filter($defined)) + ']'; 2930 case 'object': case 'hash': 2931 var string = []; 2932 Hash.each(obj, function(value, key){ 2933 var json = JSON.encode(value); 2934 if (json) string.push(JSON.encode(key) + ':' + json); 2935 }); 2936 return '{' + string + '}'; 2937 case 'number': case 'boolean': return String(obj); 2938 case false: return 'null'; 2939 } 2940 return null; 2941 }, 2942 2943 decode: function(string, secure){ 2944 if ($type(string) != 'string' || !string.length) return null; 2945 if (secure && !(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(string.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''))) return null; 2946 return eval('(' + string + ')'); 2947 } 2948 2949 }); 2950 2951 Native.implement([Hash, Array, String, Number], { 2952 2953 toJSON: function(){ 2954 return JSON.encode(this); 2955 } 2956 2957 }); 2958 2959 2960 /* 2961 Script: Cookie.js 2962 Class for creating, loading, and saving browser Cookies. 2963 2964 License: 2965 MIT-style license. 2966 2967 Credits: 2968 Based on the functions by Peter-Paul Koch (http://quirksmode.org). 2969 */ 2970 2971 var Cookie = new Class({ 2972 2973 Implements: Options, 2974 2975 options: { 2976 path: false, 2977 domain: false, 2978 duration: false, 2979 secure: false, 2980 document: document 2981 }, 2982 2983 initialize: function(key, options){ 2984 this.key = key; 2985 this.setOptions(options); 2986 }, 2987 2988 write: function(value){ 2989 value = encodeURIComponent(value); 2990 if (this.options.domain) value += '; domain=' + this.options.domain; 2991 if (this.options.path) value += '; path=' + this.options.path; 2992 if (this.options.duration){ 2993 var date = new Date(); 2994 date.setTime(date.getTime() + this.options.duration * 24 * 60 * 60 * 1000); 2995 value += '; expires=' + date.toGMTString(); 2996 } 2997 if (this.options.secure) value += '; secure'; 2998 this.options.document.cookie = this.key + '=' + value; 2999 return this; 3000 }, 3001 3002 read: function(){ 3003 var value = this.options.document.cookie.match('(?:^|;)\\s*' + this.key.escapeRegExp() + '=([^;]*)'); 3004 return (value) ? decodeURIComponent(value[1]) : null; 3005 }, 3006 3007 dispose: function(){ 3008 new Cookie(this.key, $merge(this.options, {duration: -1})).write(''); 3009 return this; 3010 } 3011 3012 }); 3013 3014 Cookie.write = function(key, value, options){ 3015 return new Cookie(key, options).write(value); 3016 }; 3017 3018 Cookie.read = function(key){ 3019 return new Cookie(key).read(); 3020 }; 3021 3022 Cookie.dispose = function(key, options){ 3023 return new Cookie(key, options).dispose(); 3024 }; 3025 3026 3027 /* 3028 Script: Swiff.js 3029 Wrapper for embedding SWF movies. Supports (and fixes) External Interface Communication. 3030 3031 License: 3032 MIT-style license. 3033 3034 Credits: 3035 Flash detection & Internet Explorer + Flash Player 9 fix inspired by SWFObject. 3036 */ 3037 3038 var Swiff = new Class({ 3039 3040 Implements: [Options], 3041 3042 options: { 3043 id: null, 3044 height: 1, 3045 width: 1, 3046 container: null, 3047 properties: {}, 3048 params: { 3049 quality: 'high', 3050 allowScriptAccess: 'always', 3051 wMode: 'transparent', 3052 swLiveConnect: true 3053 }, 3054 callBacks: {}, 3055 vars: {} 3056 }, 3057 3058 toElement: function(){ 3059 return this.object; 3060 }, 3061 3062 initialize: function(path, options){ 3063 this.instance = 'Swiff_' + $time(); 3064 3065 this.setOptions(options); 3066 options = this.options; 3067 var id = this.id = options.id || this.instance; 3068 var container = $(options.container); 3069 3070 Swiff.CallBacks[this.instance] = {}; 3071 3072 var params = options.params, vars = options.vars, callBacks = options.callBacks; 3073 var properties = $extend({height: options.height, width: options.width}, options.properties); 3074 3075 var self = this; 3076 3077 for (var callBack in callBacks){ 3078 Swiff.CallBacks[this.instance][callBack] = (function(option){ 3079 return function(){ 3080 return option.apply(self.object, arguments); 3081 }; 3082 })(callBacks[callBack]); 3083 vars[callBack] = 'Swiff.CallBacks.' + this.instance + '.' + callBack; 3084 } 3085 3086 params.flashVars = Hash.toQueryString(vars); 3087 if (Browser.Engine.trident){ 3088 properties.classid = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000'; 3089 params.movie = path; 3090 } else { 3091 properties.type = 'application/x-shockwave-flash'; 3092 properties.data = path; 3093 } 3094 var build = '<object id="' + id + '"'; 3095 for (var property in properties) build += ' ' + property + '="' + properties[property] + '"'; 3096 build += '>'; 3097 for (var param in params){ 3098 if (params[param]) build += '<param name="' + param + '" value="' + params[param] + '" />'; 3099 } 3100 build += '</object>'; 3101 this.object = ((container) ? container.empty() : new Element('div')).set('html', build).firstChild; 3102 }, 3103 3104 replaces: function(element){ 3105 element = $(element, true); 3106 element.parentNode.replaceChild(this.toElement(), element); 3107 return this; 3108 }, 3109 3110 inject: function(element){ 3111 $(element, true).appendChild(this.toElement()); 3112 return this; 3113 }, 3114 3115 remote: function(){ 3116 return Swiff.remote.apply(Swiff, [this.toElement()].extend(arguments)); 3117 } 3118 3119 }); 3120 3121 Swiff.CallBacks = {}; 3122 3123 Swiff.remote = function(obj, fn){ 3124 var rs = obj.CallFunction('<invoke name="' + fn + '" returntype="javascript">' + __flash__argumentsToXML(arguments, 2) + '</invoke>'); 3125 return eval(rs); 3126 }; 3127 3128 3129 /* 3130 Script: Fx.js 3131 Contains the basic animation logic to be extended by all other Fx Classes. 3132 3133 License: 3134 MIT-style license. 3135 */ 3136 3137 var Fx = new Class({ 3138 3139 Implements: [Chain, Events, Options], 3140 3141 options: { 3142 /* 3143 onStart: $empty, 3144 onCancel: $empty, 3145 onComplete: $empty, 3146 */ 3147 fps: 50, 3148 unit: false, 3149 duration: 500, 3150 link: 'ignore' 3151 }, 3152 3153 initialize: function(options){ 3154 this.subject = this.subject || this; 3155 this.setOptions(options); 3156 this.options.duration = Fx.Durations[this.options.duration] || this.options.duration.toInt(); 3157 var wait = this.options.wait; 3158 if (wait === false) this.options.link = 'cancel'; 3159 }, 3160 3161 getTransition: function(){ 3162 return function(p){ 3163 return -(Math.cos(Math.PI * p) - 1) / 2; 3164 }; 3165 }, 3166 3167 step: function(){ 3168 var time = $time(); 3169 if (time < this.time + this.options.duration){ 3170 var delta = this.transition((time - this.time) / this.options.duration); 3171 this.set(this.compute(this.from, this.to, delta)); 3172 } else { 3173 this.set(this.compute(this.from, this.to, 1)); 3174 this.complete(); 3175 } 3176 }, 3177 3178 set: function(now){ 3179 return now; 3180 }, 3181 3182 compute: function(from, to, delta){ 3183 return Fx.compute(from, to, delta); 3184 }, 3185 3186 check: function(){ 3187 if (!this.timer) return true; 3188 switch (this.options.link){ 3189 case 'cancel': this.cancel(); return true; 3190 case 'chain': this.chain(this.caller.bind(this, arguments)); return false; 3191 } 3192 return false; 3193 }, 3194 3195 start: function(from, to){ 3196 if (!this.check(from, to)) return this; 3197 this.from = from; 3198 this.to = to; 3199 this.time = 0; 3200 this.transition = this.getTransition(); 3201 this.startTimer(); 3202 this.onStart(); 3203 return this; 3204 }, 3205 3206 complete: function(){ 3207 if (this.stopTimer()) this.onComplete(); 3208 return this; 3209 }, 3210 3211 cancel: function(){ 3212 if (this.stopTimer()) this.onCancel(); 3213 return this; 3214 }, 3215 3216 onStart: function(){ 3217 this.fireEvent('start', this.subject); 3218 }, 3219 3220 onComplete: function(){ 3221 this.fireEvent('complete', this.subject); 3222 if (!this.callChain()) this.fireEvent('chainComplete', this.subject); 3223 }, 3224 3225 onCancel: function(){ 3226 this.fireEvent('cancel', this.subject).clearChain(); 3227 }, 3228 3229 pause: function(){ 3230 this.stopTimer(); 3231 return this; 3232 }, 3233 3234 resume: function(){ 3235 this.startTimer(); 3236 return this; 3237 }, 3238 3239 stopTimer: function(){ 3240 if (!this.timer) return false; 3241 this.time = $time() - this.time; 3242 this.timer = $clear(this.timer); 3243 return true; 3244 }, 3245 3246 startTimer: function(){ 3247 if (this.timer) return false; 3248 this.time = $time() - this.time; 3249 this.timer = this.step.periodical(Math.round(1000 / this.options.fps), this); 3250 return true; 3251 } 3252 3253 }); 3254 3255 Fx.compute = function(from, to, delta){ 3256 return (to - from) * delta + from; 3257 }; 3258 3259 Fx.Durations = {'short': 250, 'normal': 500, 'long': 1000}; 3260 3261 3262 /* 3263 Script: Fx.CSS.js 3264 Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements. 3265 3266 License: 3267 MIT-style license. 3268 */ 3269 3270 Fx.CSS = new Class({ 3271 3272 Extends: Fx, 3273 3274 //prepares the base from/to object 3275 3276 prepare: function(element, property, values){ 3277 values = $splat(values); 3278 var values1 = values[1]; 3279 if (!$chk(values1)){ 3280 values[1] = values[0]; 3281 values[0] = element.getStyle(property); 3282 } 3283 var parsed = values.map(this.parse); 3284 return {from: parsed[0], to: parsed[1]}; 3285 }, 3286 3287 //parses a value into an array 3288 3289 parse: function(value){ 3290 value = $lambda(value)(); 3291 value = (typeof value == 'string') ? value.split(' ') : $splat(value); 3292 return value.map(function(val){ 3293 val = String(val); 3294 var found = false; 3295 Fx.CSS.Parsers.each(function(parser, key){ 3296 if (found) return; 3297 var parsed = parser.parse(val); 3298 if ($chk(parsed)) found = {value: parsed, parser: parser}; 3299 }); 3300 found = found || {value: val, parser: Fx.CSS.Parsers.String}; 3301 return found; 3302 }); 3303 }, 3304 3305 //computes by a from and to prepared objects, using their parsers. 3306 3307 compute: function(from, to, delta){ 3308 var computed = []; 3309 (Math.min(from.length, to.length)).times(function(i){ 3310 computed.push({value: from[i].parser.compute(from[i].value, to[i].value, delta), parser: from[i].parser}); 3311 }); 3312 computed.$family = {name: 'fx:css:value'}; 3313 return computed; 3314 }, 3315 3316 //serves the value as settable 3317 3318 serve: function(value, unit){ 3319 if ($type(value) != 'fx:css:value') value = this.parse(value); 3320 var returned = []; 3321 value.each(function(bit){ 3322 returned = returned.concat(bit.parser.serve(bit.value, unit)); 3323 }); 3324 return returned; 3325 }, 3326 3327 //renders the change to an element 3328 3329 render: function(element, property, value, unit){ 3330 element.setStyle(property, this.serve(value, unit)); 3331 }, 3332 3333 //searches inside the page css to find the values for a selector 3334 3335 search: function(selector){ 3336 if (Fx.CSS.Cache[selector]) return Fx.CSS.Cache[selector]; 3337 var to = {}; 3338 Array.each(document.styleSheets, function(sheet, j){ 3339 var href = sheet.href; 3340 if (href && href.contains('://') && !href.contains(document.domain)) return; 3341 var rules = sheet.rules || sheet.cssRules; 3342 Array.each(rules, function(rule, i){ 3343 if (!rule.style) return; 3344 var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function(m){ 3345 return m.toLowerCase(); 3346 }) : null; 3347 if (!selectorText || !selectorText.test('^' + selector + '$')) return; 3348 Element.Styles.each(function(value, style){ 3349 if (!rule.style[style] || Element.ShortStyles[style]) return; 3350 value = String(rule.style[style]); 3351 to[style] = (value.test(/^rgb/)) ? value.rgbToHex() : value; 3352 }); 3353 }); 3354 }); 3355 return Fx.CSS.Cache[selector] = to; 3356 } 3357 3358 }); 3359 3360 Fx.CSS.Cache = {}; 3361 3362 Fx.CSS.Parsers = new Hash({ 3363 3364 Color: { 3365 parse: function(value){ 3366 if (value.match(/^#[0-9a-f]{3,6}$/i)) return value.hexToRgb(true); 3367 return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false; 3368 }, 3369 compute: function(from, to, delta){ 3370 return from.map(function(value, i){ 3371 return Math.round(Fx.compute(from[i], to[i], delta)); 3372 }); 3373 }, 3374 serve: function(value){ 3375 return value.map(Number); 3376 } 3377 }, 3378 3379 Number: { 3380 parse: parseFloat, 3381 compute: Fx.compute, 3382 serve: function(value, unit){ 3383 return (unit) ? value + unit : value; 3384 } 3385 }, 3386 3387 String: { 3388 parse: $lambda(false), 3389 compute: $arguments(1), 3390 serve: $arguments(0) 3391 } 3392 3393 }); 3394 3395 3396 /* 3397 Script: Fx.Tween.js 3398 Formerly Fx.Style, effect to transition any CSS property for an element. 3399 3400 License: 3401 MIT-style license. 3402 */ 3403 3404 Fx.Tween = new Class({ 3405 3406 Extends: Fx.CSS, 3407 3408 initialize: function(element, options){ 3409 this.element = this.subject = $(element); 3410 this.parent(options); 3411 }, 3412 3413 set: function(property, now){ 3414 if (arguments.length == 1){ 3415 now = property; 3416 property = this.property || this.options.property; 3417 } 3418 this.render(this.element, property, now, this.options.unit); 3419 return this; 3420 }, 3421 3422 start: function(property, from, to){ 3423 if (!this.check(property, from, to)) return this; 3424 var args = Array.flatten(arguments); 3425 this.property = this.options.property || args.shift(); 3426 var parsed = this.prepare(this.element, this.property, args); 3427 return this.parent(parsed.from, parsed.to); 3428 } 3429 3430 }); 3431 3432 Element.Properties.tween = { 3433 3434 set: function(options){ 3435 var tween = this.retrieve('tween'); 3436 if (tween) tween.cancel(); 3437 return this.eliminate('tween').store('tween:options', $extend({link: 'cancel'}, options)); 3438 }, 3439 3440 get: function(options){ 3441 if (options || !this.retrieve('tween')){ 3442 if (options || !this.retrieve('tween:options')) this.set('tween', options); 3443 this.store('tween', new Fx.Tween(this, this.retrieve('tween:options'))); 3444 } 3445 return this.retrieve('tween'); 3446 } 3447 3448 }; 3449 3450 Element.implement({ 3451 3452 tween: function(property, from, to){ 3453 this.get('tween').start(arguments); 3454 return this; 3455 }, 3456 3457 fade: function(how){ 3458 var fade = this.get('tween'), o = 'opacity', toggle; 3459 how = $pick(how, 'toggle'); 3460 switch (how){ 3461 case 'in': fade.start(o, 1); break; 3462 case 'out': fade.start(o, 0); break; 3463 case 'show': fade.set(o, 1); break; 3464 case 'hide': fade.set(o, 0); break; 3465 case 'toggle': 3466 var flag = this.retrieve('fade:flag', this.get('opacity') == 1); 3467 fade.start(o, (flag) ? 0 : 1); 3468 this.store('fade:flag', !flag); 3469 toggle = true; 3470 break; 3471 default: fade.start(o, arguments); 3472 } 3473 if (!toggle) this.eliminate('fade:flag'); 3474 return this; 3475 }, 3476 3477 highlight: function(start, end){ 3478 if (!end){ 3479 end = this.retrieve('highlight:original', this.getStyle('background-color')); 3480 end = (end == 'transparent') ? '#fff' : end; 3481 } 3482 var tween = this.get('tween'); 3483 tween.start('background-color', start || '#ffff88', end).chain(function(){ 3484 this.setStyle('background-color', this.retrieve('highlight:original')); 3485 tween.callChain(); 3486 }.bind(this)); 3487 return this; 3488 } 3489 3490 }); 3491 3492 3493 /* 3494 Script: Fx.Morph.js 3495 Formerly Fx.Styles, effect to transition any number of CSS properties for an element using an object of rules, or CSS based selector rules. 3496 3497 License: 3498 MIT-style license. 3499 */ 3500 3501 Fx.Morph = new Class({ 3502 3503 Extends: Fx.CSS, 3504 3505 initialize: function(element, options){ 3506 this.element = this.subject = $(element); 3507 this.parent(options); 3508 }, 3509 3510 set: function(now){ 3511 if (typeof now == 'string') now = this.search(now); 3512 for (var p in now) this.render(this.element, p, now[p], this.options.unit); 3513 return this; 3514 }, 3515 3516 compute: function(from, to, delta){ 3517 var now = {}; 3518 for (var p in from) now[p] = this.parent(from[p], to[p], delta); 3519 return now; 3520 }, 3521 3522 start: function(properties){ 3523 if (!this.check(properties)) return this; 3524 if (typeof properties == 'string') properties = this.search(properties); 3525 var from = {}, to = {}; 3526 for (var p in properties){ 3527 var parsed = this.prepare(this.element, p, properties[p]); 3528 from[p] = parsed.from; 3529 to[p] = parsed.to; 3530 } 3531 return this.parent(from, to); 3532 } 3533 3534 }); 3535 3536 Element.Properties.morph = { 3537 3538 set: function(options){ 3539 var morph = this.retrieve('morph'); 3540 if (morph) morph.cancel(); 3541 return this.eliminate('morph').store('morph:options', $extend({link: 'cancel'}, options)); 3542 }, 3543 3544 get: function(options){ 3545 if (options || !this.retrieve('morph')){ 3546 if (options || !this.retrieve('morph:options')) this.set('morph', options); 3547 this.store('morph', new Fx.Morph(this, this.retrieve('morph:options'))); 3548 } 3549 return this.retrieve('morph'); 3550 } 3551 3552 }; 3553 3554 Element.implement({ 3555 3556 morph: function(props){ 3557 this.get('morph').start(props); 3558 return this; 3559 } 3560 3561 }); 3562 3563 3564 /* 3565 Script: Fx.Transitions.js 3566 Contains a set of advanced transitions to be used with any of the Fx Classes. 3567 3568 License: 3569 MIT-style license. 3570 3571 Credits: 3572 Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>, modified and optimized to be used with MooTools. 3573 */ 3574 3575 Fx.implement({ 3576 3577 getTransition: function(){ 3578 var trans = this.options.transition || Fx.Transitions.Sine.easeInOut; 3579 if (typeof trans == 'string'){ 3580 var data = trans.split(':'); 3581 trans = Fx.Transitions; 3582 trans = trans[data[0]] || trans[data[0].capitalize()]; 3583 if (data[1]) trans = trans['ease' + data[1].capitalize() + (data[2] ? data[2].capitalize() : '')]; 3584 } 3585 return trans; 3586 } 3587 3588 }); 3589 3590 Fx.Transition = function(transition, params){ 3591 params = $splat(params); 3592 return $extend(transition, { 3593 easeIn: function(pos){ 3594 return transition(pos, params); 3595 }, 3596 easeOut: function(pos){ 3597 return 1 - transition(1 - pos, params); 3598 }, 3599 easeInOut: function(pos){ 3600 return (pos <= 0.5) ? transition(2 * pos, params) / 2 : (2 - transition(2 * (1 - pos), params)) / 2; 3601 } 3602 }); 3603 }; 3604 3605 Fx.Transitions = new Hash({ 3606 3607 linear: $arguments(0) 3608 3609 }); 3610 3611 Fx.Transitions.extend = function(transitions){ 3612 for (var transition in transitions) Fx.Transitions[transition] = new Fx.Transition(transitions[transition]); 3613 }; 3614 3615 Fx.Transitions.extend({ 3616 3617 Pow: function(p, x){ 3618 return Math.pow(p, x[0] || 6); 3619 }, 3620 3621 Expo: function(p){ 3622 return Math.pow(2, 8 * (p - 1)); 3623 }, 3624 3625 Circ: function(p){ 3626 return 1 - Math.sin(Math.acos(p)); 3627 }, 3628 3629 Sine: function(p){ 3630 return 1 - Math.sin((1 - p) * Math.PI / 2); 3631 }, 3632 3633 Back: function(p, x){ 3634 x = x[0] || 1.618; 3635 return Math.pow(p, 2) * ((x + 1) * p - x); 3636 }, 3637 3638 Bounce: function(p){ 3639 var value; 3640 for (var a = 0, b = 1; 1; a += b, b /= 2){ 3641 if (p >= (7 - 4 * a) / 11){ 3642 value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2); 3643 break; 3644 } 3645 } 3646 return value; 3647 }, 3648 3649 Elastic: function(p, x){ 3650 return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3); 3651 } 3652 3653 }); 3654 3655 ['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){ 3656 Fx.Transitions[transition] = new Fx.Transition(function(p){ 3657 return Math.pow(p, [i + 2]); 3658 }); 3659 }); 3660 3661 3662 /* 3663 Script: Request.js 3664 Powerful all purpose Request Class. Uses XMLHTTPRequest. 3665 3666 License: 3667 MIT-style license. 3668 */ 3669 3670 var Request = new Class({ 3671 3672 Implements: [Chain, Events, Options], 3673 3674 options: {/* 3675 onRequest: $empty, 3676 onComplete: $empty, 3677 onCancel: $empty, 3678 onSuccess: $empty, 3679 onFailure: $empty, 3680 onException: $empty,*/ 3681 url: '', 3682 data: '', 3683 headers: { 3684 'X-Requested-With': 'XMLHttpRequest', 3685 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' 3686 }, 3687 async: true, 3688 format: false, 3689 method: 'post', 3690 link: 'ignore', 3691 isSuccess: null, 3692 emulation: true, 3693 urlEncoded: true, 3694 encoding: 'utf-8', 3695 evalScripts: false, 3696 evalResponse: false, 3697 noCache: false 3698 }, 3699 3700 initialize: function(options){ 3701 this.xhr = new Browser.Request(); 3702 this.setOptions(options); 3703 this.options.isSuccess = this.options.isSuccess || this.isSuccess; 3704 this.headers = new Hash(this.options.headers); 3705 }, 3706 3707 onStateChange: function(){ 3708 if (this.xhr.readyState != 4 || !this.running) return; 3709 this.running = false; 3710 this.status = 0; 3711 $try(function(){ 3712 this.status = this.xhr.status; 3713 }.bind(this)); 3714 if (this.options.isSuccess.call(this, this.status)){ 3715 this.response = {text: this.xhr.responseText, xml: this.xhr.responseXML}; 3716 this.success(this.response.text, this.response.xml); 3717 } else { 3718 this.response = {text: null, xml: null}; 3719 this.failure(); 3720 } 3721 this.xhr.onreadystatechange = $empty; 3722 }, 3723 3724 isSuccess: function(){ 3725 return ((this.status >= 200) && (this.status < 300)); 3726 }, 3727 3728 processScripts: function(text){ 3729 if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return $exec(text); 3730 return text.stripScripts(this.options.evalScripts); 3731 }, 3732 3733 success: function(text, xml){ 3734 this.onSuccess(this.processScripts(text), xml); 3735 }, 3736 3737 onSuccess: function(){ 3738 this.fireEvent('complete', arguments).fireEvent('success', arguments).callChain(); 3739 }, 3740 3741 failure: function(){ 3742 this.onFailure(); 3743 }, 3744 3745 onFailure: function(){ 3746 this.fireEvent('complete').fireEvent('failure', this.xhr); 3747 }, 3748 3749 setHeader: function(name, value){ 3750 this.headers.set(name, value); 3751 return this; 3752 }, 3753 3754 getHeader: function(name){ 3755 return $try(function(){ 3756 return this.xhr.getResponseHeader(name); 3757 }.bind(this)); 3758 }, 3759 3760 check: function(){ 3761 if (!this.running) return true; 3762 switch (this.options.link){ 3763 case 'cancel': this.cancel(); return true; 3764 case 'chain': this.chain(this.caller.bind(this, arguments)); return false; 3765 } 3766 return false; 3767 }, 3768 3769 send: function(options){ 3770 if (!this.check(options)) return this; 3771 this.running = true; 3772 3773 var type = $type(options); 3774 if (type == 'string' || type == 'element') options = {data: options}; 3775 3776 var old = this.options; 3777 options = $extend({data: old.data, url: old.url, method: old.method}, options); 3778 var data = options.data, url = options.url, method = options.method; 3779 3780 switch ($type(data)){ 3781 case 'element': data = $(data).toQueryString(); break; 3782 case 'object': case 'hash': data = Hash.toQueryString(data); 3783 } 3784 3785 if (this.options.format){ 3786 var format = 'format=' + this.options.format; 3787 data = (data) ? format + '&' + data : format; 3788 } 3789 3790 if (this.options.emulation && ['put', 'delete'].contains(method)){ 3791 var _method = '_method=' + method; 3792 data = (data) ? _method + '&' + data : _method; 3793 method = 'post'; 3794 } 3795 3796 if (this.options.urlEncoded && method == 'post'){ 3797 var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : ''; 3798 this.headers.set('Content-type', 'application/x-www-form-urlencoded' + encoding); 3799 } 3800 3801 if(this.options.noCache) { 3802 var noCache = "noCache=" + new Date().getTime(); 3803 data = (data) ? noCache + '&' + data : noCache; 3804 } 3805 3806 3807 if (data && method == 'get'){ 3808 url = url + (url.contains('?') ? '&' : '?') + data; 3809 data = null; 3810 } 3811 3812 3813 this.xhr.open(method.toUpperCase(), url, this.options.async); 3814 3815 this.xhr.onreadystatechange = this.onStateChange.bind(this); 3816 3817 this.headers.each(function(value, key){ 3818 try { 3819 this.xhr.setRequestHeader(key, value); 3820 } catch (e){ 3821 this.fireEvent('exception', [key, value]); 3822 } 3823 }, this); 3824 3825 this.fireEvent('request'); 3826 this.xhr.send(data); 3827 if (!this.options.async) this.onStateChange(); 3828 return this; 3829 }, 3830 3831 cancel: function(){ 3832 if (!this.running) return this; 3833 this.running = false; 3834 this.xhr.abort(); 3835 this.xhr.onreadystatechange = $empty; 3836 this.xhr = new Browser.Request(); 3837 this.fireEvent('cancel'); 3838 return this; 3839 } 3840 3841 }); 3842 3843 (function(){ 3844 3845 var methods = {}; 3846 ['get', 'post', 'put', 'delete', 'GET', 'POST', 'PUT', 'DELETE'].each(function(method){ 3847 methods[method] = function(){ 3848 var params = Array.link(arguments, {url: String.type, data: $defined}); 3849 return this.send($extend(params, {method: method.toLowerCase()})); 3850 }; 3851 }); 3852 3853 Request.implement(methods); 3854 3855 })(); 3856 3857 /* 3858 Script: Request.HTML.js 3859 Extends the basic Request Class with additional methods for interacting with HTML responses. 3860 3861 License: 3862 MIT-style license. 3863 */ 3864 3865 Request.HTML = new Class({ 3866 3867 Extends: Request, 3868 3869 options: { 3870 update: false, 3871 append: false, 3872 evalScripts: true, 3873 filter: false 3874 }, 3875 3876 processHTML: function(text){ 3877 var match = text.match(/<body[^>]*>([\s\S]*?)<\/body>/i); 3878 text = (match) ? match[1] : text; 3879 3880 var container = new Element('div'); 3881 3882 return $try(function(){ 3883 var root = '<root>' + text + '</root>', doc; 3884 if (Browser.Engine.trident){ 3885 doc = new ActiveXObject('Microsoft.XMLDOM'); 3886 doc.async = false; 3887 doc.loadXML(root); 3888 } else { 3889 doc = new DOMParser().parseFromString(root, 'text/xml'); 3890 } 3891 root = doc.getElementsByTagName('root')[0]; 3892 if (!root) return null; 3893 for (var i = 0, k = root.childNodes.length; i < k; i++){ 3894 var child = Element.clone(root.childNodes[i], true, true); 3895 if (child) container.grab(child); 3896 } 3897 return container; 3898 }) || container.set('html', text); 3899 }, 3900 3901 success: function(text){ 3902 var options = this.options, response = this.response; 3903 3904 response.html = text.stripScripts(function(script){ 3905 response.javascript = script; 3906 }); 3907 3908 var temp = this.processHTML(response.html); 3909 3910 response.tree = temp.childNodes; 3911 response.elements = temp.getElements('*'); 3912 3913 if (options.filter) response.tree = response.elements.filter(options.filter); 3914 if (options.update) $(options.update).empty().set('html', response.html); 3915 else if (options.append) $(options.append).adopt(temp.getChildren()); 3916 if (options.evalScripts) $exec(response.javascript); 3917 3918 this.onSuccess(response.tree, response.elements, response.html, response.javascript); 3919 } 3920 3921 }); 3922 3923 Element.Properties.send = { 3924 3925 set: function(options){ 3926 var send = this.retrieve('send'); 3927 if (send) send.cancel(); 3928 return this.eliminate('send').store('send:options', $extend({ 3929 data: this, link: 'cancel', method: this.get('method') || 'post', url: this.get('action') 3930 }, options)); 3931 }, 3932 3933 get: function(options){ 3934 if (options || !this.retrieve('send')){ 3935 if (options || !this.retrieve('send:options')) this.set('send', options); 3936 this.store('send', new Request(this.retrieve('send:options'))); 3937 } 3938 return this.retrieve('send'); 3939 } 3940 3941 }; 3942 3943 Element.Properties.load = { 3944 3945 set: function(options){ 3946 var load = this.retrieve('load'); 3947 if (load) load.cancel(); 3948 return this.eliminate('load').store('load:options', $extend({data: this, link: 'cancel', update: this, method: 'get'}, options)); 3949 }, 3950 3951 get: function(options){ 3952 if (options || ! this.retrieve('load')){ 3953 if (options || !this.retrieve('load:options')) this.set('load', options); 3954 this.store('load', new Request.HTML(this.retrieve('load:options'))); 3955 } 3956 return this.retrieve('load'); 3957 } 3958 3959 }; 3960 3961 Element.implement({ 3962 3963 send: function(url){ 3964 var sender = this.get('send'); 3965 sender.send({data: this, url: url || sender.options.url}); 3966 return this; 3967 }, 3968 3969 load: function(){ 3970 this.get('load').send(Array.link(arguments, {data: Object.type, url: String.type})); 3971 return this; 3972 } 3973 3974 }); 3975 3976 3977 /* 3978 Script: Request.JSON.js 3979 Extends the basic Request Class with additional methods for sending and receiving JSON data. 3980 3981 License: 3982 MIT-style license. 3983 */ 3984 3985 Request.JSON = new Class({ 3986 3987 Extends: Request, 3988 3989 options: { 3990 secure: true 3991 }, 3992 3993 initialize: function(options){ 3994 this.parent(options); 3995 this.headers.extend({'Accept': 'application/json', 'X-Request': 'JSON'}); 3996 }, 3997 3998 success: function(text){ 3999 this.response.json = JSON.decode(text, this.options.secure); 4000 this.onSuccess(this.response.json, text); 4001 } 4002 4003 }); 4004