[ Index ] |
PHP Cross Reference of phpwcms V1.4.3 _r380 (23.11.09) |
[Summary view] [Print] [Text view]
1 //MooTools, My Object Oriented Javascript Tools. Copyright (c) 2006 Valerio Proietti, <http://mad4milk.net>, MIT Style License. 2 3 var MooTools = { 4 version: '1.11' 5 }; 6 7 function $defined(obj){ 8 return (obj != undefined); 9 }; 10 11 function $type(obj){ 12 if (!$defined(obj)) return false; 13 if (obj.htmlElement) return 'element'; 14 var type = typeof obj; 15 if (type == 'object' && obj.nodeName){ 16 switch(obj.nodeType){ 17 case 1: return 'element'; 18 case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace'; 19 } 20 } 21 if (type == 'object' || type == 'function'){ 22 switch(obj.constructor){ 23 case Array: return 'array'; 24 case RegExp: return 'regexp'; 25 case Class: return 'class'; 26 } 27 if (typeof obj.length == 'number'){ 28 if (obj.item) return 'collection'; 29 if (obj.callee) return 'arguments'; 30 } 31 } 32 return type; 33 }; 34 35 function $merge(){ 36 var mix = {}; 37 for (var i = 0; i < arguments.length; i++){ 38 for (var property in arguments[i]){ 39 var ap = arguments[i][property]; 40 var mp = mix[property]; 41 if (mp && $type(ap) == 'object' && $type(mp) == 'object') mix[property] = $merge(mp, ap); 42 else mix[property] = ap; 43 } 44 } 45 return mix; 46 }; 47 48 var $extend = function(){ 49 var args = arguments; 50 if (!args[1]) args = [this, args[0]]; 51 for (var property in args[1]) args[0][property] = args[1][property]; 52 return args[0]; 53 }; 54 55 var $native = function(){ 56 for (var i = 0, l = arguments.length; i < l; i++){ 57 arguments[i].extend = function(props){ 58 for (var prop in props){ 59 if (!this.prototype[prop]) this.prototype[prop] = props[prop]; 60 if (!this[prop]) this[prop] = $native.generic(prop); 61 } 62 }; 63 } 64 }; 65 66 $native.generic = function(prop){ 67 return function(bind){ 68 return this.prototype[prop].apply(bind, Array.prototype.slice.call(arguments, 1)); 69 }; 70 }; 71 72 $native(Function, Array, String, Number); 73 74 function $chk(obj){ 75 return !!(obj || obj === 0); 76 }; 77 78 function $pick(obj, picked){ 79 return $defined(obj) ? obj : picked; 80 }; 81 82 function $random(min, max){ 83 return Math.floor(Math.random() * (max - min + 1) + min); 84 }; 85 86 function $time(){ 87 return new Date().getTime(); 88 }; 89 90 function $clear(timer){ 91 clearTimeout(timer); 92 clearInterval(timer); 93 return null; 94 }; 95 96 var Abstract = function(obj){ 97 obj = obj || {}; 98 obj.extend = $extend; 99 return obj; 100 }; 101 102 var Window = new Abstract(window); 103 var Document = new Abstract(document); 104 document.head = document.getElementsByTagName('head')[0]; 105 106 window.xpath = !!(document.evaluate); 107 if (window.ActiveXObject) window.ie = window[window.XMLHttpRequest ? 'ie7' : 'ie6'] = true; 108 else if (document.childNodes && !document.all && !navigator.taintEnabled) window.webkit = window[window.xpath ? 'webkit420' : 'webkit419'] = true; 109 else if (document.getBoxObjectFor != null) window.gecko = true; 110 111 window.khtml = window.webkit; 112 113 Object.extend = $extend; 114 115 if (typeof HTMLElement == 'undefined'){ 116 var HTMLElement = function(){}; 117 if (window.webkit) document.createElement("iframe"); 118 HTMLElement.prototype = (window.webkit) ? window["[[DOMElement.prototype]]"] : {}; 119 } 120 HTMLElement.prototype.htmlElement = function(){}; 121 122 if (window.ie6) try {document.execCommand("BackgroundImageCache", false, true);} catch(e){}; 123 124 var Class = function(properties){ 125 var klass = function(){ 126 return (arguments[0] !== null && this.initialize && $type(this.initialize) == 'function') ? this.initialize.apply(this, arguments) : this; 127 }; 128 $extend(klass, this); 129 klass.prototype = properties; 130 klass.constructor = Class; 131 return klass; 132 }; 133 134 Class.empty = function(){}; 135 136 Class.prototype = { 137 138 extend: function(properties){ 139 var proto = new this(null); 140 for (var property in properties){ 141 var pp = proto[property]; 142 proto[property] = Class.Merge(pp, properties[property]); 143 } 144 return new Class(proto); 145 }, 146 147 implement: function(){ 148 for (var i = 0, l = arguments.length; i < l; i++) $extend(this.prototype, arguments[i]); 149 } 150 151 }; 152 153 Class.Merge = function(previous, current){ 154 if (previous && previous != current){ 155 var type = $type(current); 156 if (type != $type(previous)) return current; 157 switch(type){ 158 case 'function': 159 var merged = function(){ 160 this.parent = arguments.callee.parent; 161 return current.apply(this, arguments); 162 }; 163 merged.parent = previous; 164 return merged; 165 case 'object': return $merge(previous, current); 166 } 167 } 168 return current; 169 }; 170 171 var Chain = new Class({ 172 173 chain: function(fn){ 174 this.chains = this.chains || []; 175 this.chains.push(fn); 176 return this; 177 }, 178 179 callChain: function(){ 180 if (this.chains && this.chains.length) this.chains.shift().delay(10, this); 181 }, 182 183 clearChain: function(){ 184 this.chains = []; 185 } 186 187 }); 188 189 var Events = new Class({ 190 191 addEvent: function(type, fn){ 192 if (fn != Class.empty){ 193 this.$events = this.$events || {}; 194 this.$events[type] = this.$events[type] || []; 195 this.$events[type].include(fn); 196 } 197 return this; 198 }, 199 200 fireEvent: function(type, args, delay){ 201 if (this.$events && this.$events[type]){ 202 this.$events[type].each(function(fn){ 203 fn.create({'bind': this, 'delay': delay, 'arguments': args})(); 204 }, this); 205 } 206 return this; 207 }, 208 209 removeEvent: function(type, fn){ 210 if (this.$events && this.$events[type]) this.$events[type].remove(fn); 211 return this; 212 } 213 214 }); 215 216 var Options = new Class({ 217 218 setOptions: function(){ 219 this.options = $merge.apply(null, [this.options].extend(arguments)); 220 if (this.addEvent){ 221 for (var option in this.options){ 222 if ($type(this.options[option] == 'function') && (/^on[A-Z]/).test(option)) this.addEvent(option, this.options[option]); 223 } 224 } 225 return this; 226 } 227 228 }); 229 230 Array.extend({ 231 232 forEach: function(fn, bind){ 233 for (var i = 0, j = this.length; i < j; i++) fn.call(bind, this[i], i, this); 234 }, 235 236 filter: function(fn, bind){ 237 var results = []; 238 for (var i = 0, j = this.length; i < j; i++){ 239 if (fn.call(bind, this[i], i, this)) results.push(this[i]); 240 } 241 return results; 242 }, 243 244 map: function(fn, bind){ 245 var results = []; 246 for (var i = 0, j = this.length; i < j; i++) results[i] = fn.call(bind, this[i], i, this); 247 return results; 248 }, 249 250 every: function(fn, bind){ 251 for (var i = 0, j = this.length; i < j; i++){ 252 if (!fn.call(bind, this[i], i, this)) return false; 253 } 254 return true; 255 }, 256 257 some: function(fn, bind){ 258 for (var i = 0, j = this.length; i < j; i++){ 259 if (fn.call(bind, this[i], i, this)) return true; 260 } 261 return false; 262 }, 263 264 indexOf: function(item, from){ 265 var len = this.length; 266 for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){ 267 if (this[i] === item) return i; 268 } 269 return -1; 270 }, 271 272 copy: function(start, length){ 273 start = start || 0; 274 if (start < 0) start = this.length + start; 275 length = length || (this.length - start); 276 var newArray = []; 277 for (var i = 0; i < length; i++) newArray[i] = this[start++]; 278 return newArray; 279 }, 280 281 remove: function(item){ 282 var i = 0; 283 var len = this.length; 284 while (i < len){ 285 if (this[i] === item){ 286 this.splice(i, 1); 287 len--; 288 } else { 289 i++; 290 } 291 } 292 return this; 293 }, 294 295 contains: function(item, from){ 296 return this.indexOf(item, from) != -1; 297 }, 298 299 associate: function(keys){ 300 var obj = {}, length = Math.min(this.length, keys.length); 301 for (var i = 0; i < length; i++) obj[keys[i]] = this[i]; 302 return obj; 303 }, 304 305 extend: function(array){ 306 for (var i = 0, j = array.length; i < j; i++) this.push(array[i]); 307 return this; 308 }, 309 310 merge: function(array){ 311 for (var i = 0, l = array.length; i < l; i++) this.include(array[i]); 312 return this; 313 }, 314 315 include: function(item){ 316 if (!this.contains(item)) this.push(item); 317 return this; 318 }, 319 320 getRandom: function(){ 321 return this[$random(0, this.length - 1)] || null; 322 }, 323 324 getLast: function(){ 325 return this[this.length - 1] || null; 326 } 327 328 }); 329 330 Array.prototype.each = Array.prototype.forEach; 331 Array.each = Array.forEach; 332 333 function $A(array){ 334 return Array.copy(array); 335 }; 336 337 function $each(iterable, fn, bind){ 338 if (iterable && typeof iterable.length == 'number' && $type(iterable) != 'object'){ 339 Array.forEach(iterable, fn, bind); 340 } else { 341 for (var name in iterable) fn.call(bind || iterable, iterable[name], name); 342 } 343 }; 344 345 Array.prototype.test = Array.prototype.contains; 346 347 String.extend({ 348 349 test: function(regex, params){ 350 return (($type(regex) == 'string') ? new RegExp(regex, params) : regex).test(this); 351 }, 352 353 toInt: function(){ 354 return parseInt(this, 10); 355 }, 356 357 toFloat: function(){ 358 return parseFloat(this); 359 }, 360 361 camelCase: function(){ 362 return this.replace(/-\D/g, function(match){ 363 return match.charAt(1).toUpperCase(); 364 }); 365 }, 366 367 hyphenate: function(){ 368 return this.replace(/\w[A-Z]/g, function(match){ 369 return (match.charAt(0) + '-' + match.charAt(1).toLowerCase()); 370 }); 371 }, 372 373 capitalize: function(){ 374 return this.replace(/\b[a-z]/g, function(match){ 375 return match.toUpperCase(); 376 }); 377 }, 378 379 trim: function(){ 380 return this.replace(/^\s+|\s+$/g, ''); 381 }, 382 383 clean: function(){ 384 return this.replace(/\s{2,}/g, ' ').trim(); 385 }, 386 387 rgbToHex: function(array){ 388 var rgb = this.match(/\d{1,3}/g); 389 return (rgb) ? rgb.rgbToHex(array) : false; 390 }, 391 392 hexToRgb: function(array){ 393 var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); 394 return (hex) ? hex.slice(1).hexToRgb(array) : false; 395 }, 396 397 contains: function(string, s){ 398 return (s) ? (s + this + s).indexOf(s + string + s) > -1 : this.indexOf(string) > -1; 399 }, 400 401 escapeRegExp: function(){ 402 return this.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1'); 403 } 404 405 }); 406 407 Array.extend({ 408 409 rgbToHex: function(array){ 410 if (this.length < 3) return false; 411 if (this.length == 4 && this[3] == 0 && !array) return 'transparent'; 412 var hex = []; 413 for (var i = 0; i < 3; i++){ 414 var bit = (this[i] - 0).toString(16); 415 hex.push((bit.length == 1) ? '0' + bit : bit); 416 } 417 return array ? hex : '#' + hex.join(''); 418 }, 419 420 hexToRgb: function(array){ 421 if (this.length != 3) return false; 422 var rgb = []; 423 for (var i = 0; i < 3; i++){ 424 rgb.push(parseInt((this[i].length == 1) ? this[i] + this[i] : this[i], 16)); 425 } 426 return array ? rgb : 'rgb(' + rgb.join(',') + ')'; 427 } 428 429 }); 430 431 Function.extend({ 432 433 create: function(options){ 434 var fn = this; 435 options = $merge({ 436 'bind': fn, 437 'event': false, 438 'arguments': null, 439 'delay': false, 440 'periodical': false, 441 'attempt': false 442 }, options); 443 if ($chk(options.arguments) && $type(options.arguments) != 'array') options.arguments = [options.arguments]; 444 return function(event){ 445 var args; 446 if (options.event){ 447 event = event || window.event; 448 args = [(options.event === true) ? event : new options.event(event)]; 449 if (options.arguments) args.extend(options.arguments); 450 } 451 else args = options.arguments || arguments; 452 var returns = function(){ 453 return fn.apply($pick(options.bind, fn), args); 454 }; 455 if (options.delay) return setTimeout(returns, options.delay); 456 if (options.periodical) return setInterval(returns, options.periodical); 457 if (options.attempt) try {return returns();} catch(err){return false;}; 458 return returns(); 459 }; 460 }, 461 462 pass: function(args, bind){ 463 return this.create({'arguments': args, 'bind': bind}); 464 }, 465 466 attempt: function(args, bind){ 467 return this.create({'arguments': args, 'bind': bind, 'attempt': true})(); 468 }, 469 470 bind: function(bind, args){ 471 return this.create({'bind': bind, 'arguments': args}); 472 }, 473 474 bindAsEventListener: function(bind, args){ 475 return this.create({'bind': bind, 'event': true, 'arguments': args}); 476 }, 477 478 delay: function(delay, bind, args){ 479 return this.create({'delay': delay, 'bind': bind, 'arguments': args})(); 480 }, 481 482 periodical: function(interval, bind, args){ 483 return this.create({'periodical': interval, 'bind': bind, 'arguments': args})(); 484 } 485 486 }); 487 488 Number.extend({ 489 490 toInt: function(){ 491 return parseInt(this); 492 }, 493 494 toFloat: function(){ 495 return parseFloat(this); 496 }, 497 498 limit: function(min, max){ 499 return Math.min(max, Math.max(min, this)); 500 }, 501 502 round: function(precision){ 503 precision = Math.pow(10, precision || 0); 504 return Math.round(this * precision) / precision; 505 }, 506 507 times: function(fn){ 508 for (var i = 0; i < this; i++) fn(i); 509 } 510 511 }); 512 513 var Element = new Class({ 514 515 initialize: function(el, props){ 516 if ($type(el) == 'string'){ 517 if (window.ie && props && (props.name || props.type)){ 518 var name = (props.name) ? ' name="' + props.name + '"' : ''; 519 var type = (props.type) ? ' type="' + props.type + '"' : ''; 520 delete props.name; 521 delete props.type; 522 el = '<' + el + name + type + '>'; 523 } 524 el = document.createElement(el); 525 } 526 el = $(el); 527 return (!props || !el) ? el : el.set(props); 528 } 529 530 }); 531 532 var Elements = new Class({ 533 534 initialize: function(elements){ 535 return (elements) ? $extend(elements, this) : this; 536 } 537 538 }); 539 540 Elements.extend = function(props){ 541 for (var prop in props){ 542 this.prototype[prop] = props[prop]; 543 this[prop] = $native.generic(prop); 544 } 545 }; 546 547 function $(el){ 548 if (!el) return null; 549 if (el.htmlElement) return Garbage.collect(el); 550 if ([window, document].contains(el)) return el; 551 var type = $type(el); 552 if (type == 'string'){ 553 el = document.getElementById(el); 554 type = (el) ? 'element' : false; 555 } 556 if (type != 'element') return null; 557 if (el.htmlElement) return Garbage.collect(el); 558 if (['object', 'embed'].contains(el.tagName.toLowerCase())) return el; 559 $extend(el, Element.prototype); 560 el.htmlElement = function(){}; 561 return Garbage.collect(el); 562 }; 563 564 document.getElementsBySelector = document.getElementsByTagName; 565 566 function $$(){ 567 var elements = []; 568 for (var i = 0, j = arguments.length; i < j; i++){ 569 var selector = arguments[i]; 570 switch($type(selector)){ 571 case 'element': elements.push(selector); 572 case 'boolean': break; 573 case false: break; 574 case 'string': selector = document.getElementsBySelector(selector, true); 575 default: elements.extend(selector); 576 } 577 } 578 return $$.unique(elements); 579 }; 580 581 $$.unique = function(array){ 582 var elements = []; 583 for (var i = 0, l = array.length; i < l; i++){ 584 if (array[i].$included) continue; 585 var element = $(array[i]); 586 if (element && !element.$included){ 587 element.$included = true; 588 elements.push(element); 589 } 590 } 591 for (var n = 0, d = elements.length; n < d; n++) elements[n].$included = null; 592 return new Elements(elements); 593 }; 594 595 Elements.Multi = function(property){ 596 return function(){ 597 var args = arguments; 598 var items = []; 599 var elements = true; 600 for (var i = 0, j = this.length, returns; i < j; i++){ 601 returns = this[i][property].apply(this[i], args); 602 if ($type(returns) != 'element') elements = false; 603 items.push(returns); 604 }; 605 return (elements) ? $$.unique(items) : items; 606 }; 607 }; 608 609 Element.extend = function(properties){ 610 for (var property in properties){ 611 HTMLElement.prototype[property] = properties[property]; 612 Element.prototype[property] = properties[property]; 613 Element[property] = $native.generic(property); 614 var elementsProperty = (Array.prototype[property]) ? property + 'Elements' : property; 615 Elements.prototype[elementsProperty] = Elements.Multi(property); 616 } 617 }; 618 619 Element.extend({ 620 621 set: function(props){ 622 for (var prop in props){ 623 var val = props[prop]; 624 switch(prop){ 625 case 'styles': this.setStyles(val); break; 626 case 'events': if (this.addEvents) this.addEvents(val); break; 627 case 'properties': this.setProperties(val); break; 628 default: this.setProperty(prop, val); 629 } 630 } 631 return this; 632 }, 633 634 inject: function(el, where){ 635 el = $(el); 636 switch(where){ 637 case 'before': el.parentNode.insertBefore(this, el); break; 638 case 'after': 639 var next = el.getNext(); 640 if (!next) el.parentNode.appendChild(this); 641 else el.parentNode.insertBefore(this, next); 642 break; 643 case 'top': 644 var first = el.firstChild; 645 if (first){ 646 el.insertBefore(this, first); 647 break; 648 } 649 default: el.appendChild(this); 650 } 651 return this; 652 }, 653 654 injectBefore: function(el){ 655 return this.inject(el, 'before'); 656 }, 657 658 injectAfter: function(el){ 659 return this.inject(el, 'after'); 660 }, 661 662 injectInside: function(el){ 663 return this.inject(el, 'bottom'); 664 }, 665 666 injectTop: function(el){ 667 return this.inject(el, 'top'); 668 }, 669 670 adopt: function(){ 671 var elements = []; 672 $each(arguments, function(argument){ 673 elements = elements.concat(argument); 674 }); 675 $$(elements).inject(this); 676 return this; 677 }, 678 679 remove: function(){ 680 return this.parentNode.removeChild(this); 681 }, 682 683 clone: function(contents){ 684 var el = $(this.cloneNode(contents !== false)); 685 if (!el.$events) return el; 686 el.$events = {}; 687 for (var type in this.$events) el.$events[type] = { 688 'keys': $A(this.$events[type].keys), 689 'values': $A(this.$events[type].values) 690 }; 691 return el.removeEvents(); 692 }, 693 694 replaceWith: function(el){ 695 el = $(el); 696 this.parentNode.replaceChild(el, this); 697 return el; 698 }, 699 700 appendText: function(text){ 701 this.appendChild(document.createTextNode(text)); 702 return this; 703 }, 704 705 hasClass: function(className){ 706 return this.className.contains(className, ' '); 707 }, 708 709 addClass: function(className){ 710 if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean(); 711 return this; 712 }, 713 714 removeClass: function(className){ 715 this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1').clean(); 716 return this; 717 }, 718 719 toggleClass: function(className){ 720 return this.hasClass(className) ? this.removeClass(className) : this.addClass(className); 721 }, 722 723 setStyle: function(property, value){ 724 switch(property){ 725 case 'opacity': return this.setOpacity(parseFloat(value)); 726 case 'float': property = (window.ie) ? 'styleFloat' : 'cssFloat'; 727 } 728 property = property.camelCase(); 729 switch($type(value)){ 730 case 'number': if (!['zIndex', 'zoom'].contains(property)) value += 'px'; break; 731 case 'array': value = 'rgb(' + value.join(',') + ')'; 732 } 733 this.style[property] = value; 734 return this; 735 }, 736 737 setStyles: function(source){ 738 switch($type(source)){ 739 case 'object': Element.setMany(this, 'setStyle', source); break; 740 case 'string': this.style.cssText = source; 741 } 742 return this; 743 }, 744 745 setOpacity: function(opacity){ 746 if (opacity == 0){ 747 if (this.style.visibility != "hidden") this.style.visibility = "hidden"; 748 } else { 749 if (this.style.visibility != "visible") this.style.visibility = "visible"; 750 } 751 if (!this.currentStyle || !this.currentStyle.hasLayout) this.style.zoom = 1; 752 if (window.ie) this.style.filter = (opacity == 1) ? '' : "alpha(opacity=" + opacity * 100 + ")"; 753 this.style.opacity = this.$tmp.opacity = opacity; 754 return this; 755 }, 756 757 getStyle: function(property){ 758 property = property.camelCase(); 759 var result = this.style[property]; 760 if (!$chk(result)){ 761 if (property == 'opacity') return this.$tmp.opacity; 762 result = []; 763 for (var style in Element.Styles){ 764 if (property == style){ 765 Element.Styles[style].each(function(s){ 766 var style = this.getStyle(s); 767 result.push(parseInt(style) ? style : '0px'); 768 }, this); 769 if (property == 'border'){ 770 var every = result.every(function(bit){ 771 return (bit == result[0]); 772 }); 773 return (every) ? result[0] : false; 774 } 775 return result.join(' '); 776 } 777 } 778 if (property.contains('border')){ 779 if (Element.Styles.border.contains(property)){ 780 return ['Width', 'Style', 'Color'].map(function(p){ 781 return this.getStyle(property + p); 782 }, this).join(' '); 783 } else if (Element.borderShort.contains(property)){ 784 return ['Top', 'Right', 'Bottom', 'Left'].map(function(p){ 785 return this.getStyle('border' + p + property.replace('border', '')); 786 }, this).join(' '); 787 } 788 } 789 if (document.defaultView) result = document.defaultView.getComputedStyle(this, null).getPropertyValue(property.hyphenate()); 790 else if (this.currentStyle) result = this.currentStyle[property]; 791 } 792 if (window.ie) result = Element.fixStyle(property, result, this); 793 if (result && property.test(/color/i) && result.contains('rgb')){ 794 return result.split('rgb').splice(1,4).map(function(color){ 795 return color.rgbToHex(); 796 }).join(' '); 797 } 798 return result; 799 }, 800 801 getStyles: function(){ 802 return Element.getMany(this, 'getStyle', arguments); 803 }, 804 805 walk: function(brother, start){ 806 brother += 'Sibling'; 807 var el = (start) ? this[start] : this[brother]; 808 while (el && $type(el) != 'element') el = el[brother]; 809 return $(el); 810 }, 811 812 getPrevious: function(){ 813 return this.walk('previous'); 814 }, 815 816 getNext: function(){ 817 return this.walk('next'); 818 }, 819 820 getFirst: function(){ 821 return this.walk('next', 'firstChild'); 822 }, 823 824 getLast: function(){ 825 return this.walk('previous', 'lastChild'); 826 }, 827 828 getParent: function(){ 829 return $(this.parentNode); 830 }, 831 832 getChildren: function(){ 833 return $$(this.childNodes); 834 }, 835 836 hasChild: function(el){ 837 return !!$A(this.getElementsByTagName('*')).contains(el); 838 }, 839 840 getProperty: function(property){ 841 var index = Element.Properties[property]; 842 if (index) return this[index]; 843 var flag = Element.PropertiesIFlag[property] || 0; 844 if (!window.ie || flag) return this.getAttribute(property, flag); 845 var node = this.attributes[property]; 846 return (node) ? node.nodeValue : null; 847 }, 848 849 removeProperty: function(property){ 850 var index = Element.Properties[property]; 851 if (index) this[index] = ''; 852 else this.removeAttribute(property); 853 return this; 854 }, 855 856 getProperties: function(){ 857 return Element.getMany(this, 'getProperty', arguments); 858 }, 859 860 setProperty: function(property, value){ 861 var index = Element.Properties[property]; 862 if (index) this[index] = value; 863 else this.setAttribute(property, value); 864 return this; 865 }, 866 867 setProperties: function(source){ 868 return Element.setMany(this, 'setProperty', source); 869 }, 870 871 setHTML: function(){ 872 this.innerHTML = $A(arguments).join(''); 873 return this; 874 }, 875 876 setText: function(text){ 877 var tag = this.getTag(); 878 if (['style', 'script'].contains(tag)){ 879 if (window.ie){ 880 if (tag == 'style') this.styleSheet.cssText = text; 881 else if (tag == 'script') this.setProperty('text', text); 882 return this; 883 } else { 884 this.removeChild(this.firstChild); 885 return this.appendText(text); 886 } 887 } 888 this[$defined(this.innerText) ? 'innerText' : 'textContent'] = text; 889 return this; 890 }, 891 892 getText: function(){ 893 var tag = this.getTag(); 894 if (['style', 'script'].contains(tag)){ 895 if (window.ie){ 896 if (tag == 'style') return this.styleSheet.cssText; 897 else if (tag == 'script') return this.getProperty('text'); 898 } else { 899 return this.innerHTML; 900 } 901 } 902 return ($pick(this.innerText, this.textContent)); 903 }, 904 905 getTag: function(){ 906 return this.tagName.toLowerCase(); 907 }, 908 909 empty: function(){ 910 Garbage.trash(this.getElementsByTagName('*')); 911 return this.setHTML(''); 912 } 913 914 }); 915 916 Element.fixStyle = function(property, result, element){ 917 if ($chk(parseInt(result))) return result; 918 if (['height', 'width'].contains(property)){ 919 var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom']; 920 var size = 0; 921 values.each(function(value){ 922 size += element.getStyle('border-' + value + '-width').toInt() + element.getStyle('padding-' + value).toInt(); 923 }); 924 return element['offset' + property.capitalize()] - size + 'px'; 925 } else if (property.test(/border(.+)Width|margin|padding/)){ 926 return '0px'; 927 } 928 return result; 929 }; 930 931 Element.Styles = {'border': [], 'padding': [], 'margin': []}; 932 ['Top', 'Right', 'Bottom', 'Left'].each(function(direction){ 933 for (var style in Element.Styles) Element.Styles[style].push(style + direction); 934 }); 935 936 Element.borderShort = ['borderWidth', 'borderStyle', 'borderColor']; 937 938 Element.getMany = function(el, method, keys){ 939 var result = {}; 940 $each(keys, function(key){ 941 result[key] = el[method](key); 942 }); 943 return result; 944 }; 945 946 Element.setMany = function(el, method, pairs){ 947 for (var key in pairs) el[method](key, pairs[key]); 948 return el; 949 }; 950 951 Element.Properties = new Abstract({ 952 'class': 'className', 'for': 'htmlFor', 'colspan': 'colSpan', 'rowspan': 'rowSpan', 953 'accesskey': 'accessKey', 'tabindex': 'tabIndex', 'maxlength': 'maxLength', 954 'readonly': 'readOnly', 'frameborder': 'frameBorder', 'value': 'value', 955 'disabled': 'disabled', 'checked': 'checked', 'multiple': 'multiple', 'selected': 'selected' 956 }); 957 Element.PropertiesIFlag = { 958 'href': 2, 'src': 2 959 }; 960 961 Element.Methods = { 962 Listeners: { 963 addListener: function(type, fn){ 964 if (this.addEventListener) this.addEventListener(type, fn, false); 965 else this.attachEvent('on' + type, fn); 966 return this; 967 }, 968 969 removeListener: function(type, fn){ 970 if (this.removeEventListener) this.removeEventListener(type, fn, false); 971 else this.detachEvent('on' + type, fn); 972 return this; 973 } 974 } 975 }; 976 977 window.extend(Element.Methods.Listeners); 978 document.extend(Element.Methods.Listeners); 979 Element.extend(Element.Methods.Listeners); 980 981 var Garbage = { 982 983 elements: [], 984 985 collect: function(el){ 986 if (!el.$tmp){ 987 Garbage.elements.push(el); 988 el.$tmp = {'opacity': 1}; 989 } 990 return el; 991 }, 992 993 trash: function(elements){ 994 for (var i = 0, j = elements.length, el; i < j; i++){ 995 if (!(el = elements[i]) || !el.$tmp) continue; 996 if (el.$events) el.fireEvent('trash').removeEvents(); 997 for (var p in el.$tmp) el.$tmp[p] = null; 998 for (var d in Element.prototype) el[d] = null; 999 Garbage.elements[Garbage.elements.indexOf(el)] = null; 1000 el.htmlElement = el.$tmp = el = null; 1001 } 1002 Garbage.elements.remove(null); 1003 }, 1004 1005 empty: function(){ 1006 Garbage.collect(window); 1007 Garbage.collect(document); 1008 Garbage.trash(Garbage.elements); 1009 } 1010 1011 }; 1012 1013 window.addListener('beforeunload', function(){ 1014 window.addListener('unload', Garbage.empty); 1015 if (window.ie) window.addListener('unload', CollectGarbage); 1016 }); 1017 1018 var Event = new Class({ 1019 1020 initialize: function(event){ 1021 if (event && event.$extended) return event; 1022 this.$extended = true; 1023 event = event || window.event; 1024 this.event = event; 1025 this.type = event.type; 1026 this.target = event.target || event.srcElement; 1027 if (this.target.nodeType == 3) this.target = this.target.parentNode; 1028 this.shift = event.shiftKey; 1029 this.control = event.ctrlKey; 1030 this.alt = event.altKey; 1031 this.meta = event.metaKey; 1032 if (['DOMMouseScroll', 'mousewheel'].contains(this.type)){ 1033 this.wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3; 1034 } else if (this.type.contains('key')){ 1035 this.code = event.which || event.keyCode; 1036 for (var name in Event.keys){ 1037 if (Event.keys[name] == this.code){ 1038 this.key = name; 1039 break; 1040 } 1041 } 1042 if (this.type == 'keydown'){ 1043 var fKey = this.code - 111; 1044 if (fKey > 0 && fKey < 13) this.key = 'f' + fKey; 1045 } 1046 this.key = this.key || String.fromCharCode(this.code).toLowerCase(); 1047 } else if (this.type.test(/(click|mouse|menu)/)){ 1048 this.page = { 1049 'x': event.pageX || event.clientX + document.documentElement.scrollLeft, 1050 'y': event.pageY || event.clientY + document.documentElement.scrollTop 1051 }; 1052 this.client = { 1053 'x': event.pageX ? event.pageX - window.pageXOffset : event.clientX, 1054 'y': event.pageY ? event.pageY - window.pageYOffset : event.clientY 1055 }; 1056 this.rightClick = (event.which == 3) || (event.button == 2); 1057 switch(this.type){ 1058 case 'mouseover': this.relatedTarget = event.relatedTarget || event.fromElement; break; 1059 case 'mouseout': this.relatedTarget = event.relatedTarget || event.toElement; 1060 } 1061 this.fixRelatedTarget(); 1062 } 1063 return this; 1064 }, 1065 1066 stop: function(){ 1067 return this.stopPropagation().preventDefault(); 1068 }, 1069 1070 stopPropagation: function(){ 1071 if (this.event.stopPropagation) this.event.stopPropagation(); 1072 else this.event.cancelBubble = true; 1073 return this; 1074 }, 1075 1076 preventDefault: function(){ 1077 if (this.event.preventDefault) this.event.preventDefault(); 1078 else this.event.returnValue = false; 1079 return this; 1080 } 1081 1082 }); 1083 1084 Event.fix = { 1085 1086 relatedTarget: function(){ 1087 if (this.relatedTarget && this.relatedTarget.nodeType == 3) this.relatedTarget = this.relatedTarget.parentNode; 1088 }, 1089 1090 relatedTargetGecko: function(){ 1091 try {Event.fix.relatedTarget.call(this);} catch(e){this.relatedTarget = this.target;} 1092 } 1093 1094 }; 1095 1096 Event.prototype.fixRelatedTarget = (window.gecko) ? Event.fix.relatedTargetGecko : Event.fix.relatedTarget; 1097 1098 Event.keys = new Abstract({ 1099 'enter': 13, 1100 'up': 38, 1101 'down': 40, 1102 'left': 37, 1103 'right': 39, 1104 'esc': 27, 1105 'space': 32, 1106 'backspace': 8, 1107 'tab': 9, 1108 'delete': 46 1109 }); 1110 1111 Element.Methods.Events = { 1112 1113 addEvent: function(type, fn){ 1114 this.$events = this.$events || {}; 1115 this.$events[type] = this.$events[type] || {'keys': [], 'values': []}; 1116 if (this.$events[type].keys.contains(fn)) return this; 1117 this.$events[type].keys.push(fn); 1118 var realType = type; 1119 var custom = Element.Events[type]; 1120 if (custom){ 1121 if (custom.add) custom.add.call(this, fn); 1122 if (custom.map) fn = custom.map; 1123 if (custom.type) realType = custom.type; 1124 } 1125 if (!this.addEventListener) fn = fn.create({'bind': this, 'event': true}); 1126 this.$events[type].values.push(fn); 1127 return (Element.NativeEvents.contains(realType)) ? this.addListener(realType, fn) : this; 1128 }, 1129 1130 removeEvent: function(type, fn){ 1131 if (!this.$events || !this.$events[type]) return this; 1132 var pos = this.$events[type].keys.indexOf(fn); 1133 if (pos == -1) return this; 1134 var key = this.$events[type].keys.splice(pos,1)[0]; 1135 var value = this.$events[type].values.splice(pos,1)[0]; 1136 var custom = Element.Events[type]; 1137 if (custom){ 1138 if (custom.remove) custom.remove.call(this, fn); 1139 if (custom.type) type = custom.type; 1140 } 1141 return (Element.NativeEvents.contains(type)) ? this.removeListener(type, value) : this; 1142 }, 1143 1144 addEvents: function(source){ 1145 return Element.setMany(this, 'addEvent', source); 1146 }, 1147 1148 removeEvents: function(type){ 1149 if (!this.$events) return this; 1150 if (!type){ 1151 for (var evType in this.$events) this.removeEvents(evType); 1152 this.$events = null; 1153 } else if (this.$events[type]){ 1154 this.$events[type].keys.each(function(fn){ 1155 this.removeEvent(type, fn); 1156 }, this); 1157 this.$events[type] = null; 1158 } 1159 return this; 1160 }, 1161 1162 fireEvent: function(type, args, delay){ 1163 if (this.$events && this.$events[type]){ 1164 this.$events[type].keys.each(function(fn){ 1165 fn.create({'bind': this, 'delay': delay, 'arguments': args})(); 1166 }, this); 1167 } 1168 return this; 1169 }, 1170 1171 cloneEvents: function(from, type){ 1172 if (!from.$events) return this; 1173 if (!type){ 1174 for (var evType in from.$events) this.cloneEvents(from, evType); 1175 } else if (from.$events[type]){ 1176 from.$events[type].keys.each(function(fn){ 1177 this.addEvent(type, fn); 1178 }, this); 1179 } 1180 return this; 1181 } 1182 1183 }; 1184 1185 window.extend(Element.Methods.Events); 1186 document.extend(Element.Methods.Events); 1187 Element.extend(Element.Methods.Events); 1188 1189 Element.Events = new Abstract({ 1190 1191 'mouseenter': { 1192 type: 'mouseover', 1193 map: function(event){ 1194 event = new Event(event); 1195 if (event.relatedTarget != this && !this.hasChild(event.relatedTarget)) this.fireEvent('mouseenter', event); 1196 } 1197 }, 1198 1199 'mouseleave': { 1200 type: 'mouseout', 1201 map: function(event){ 1202 event = new Event(event); 1203 if (event.relatedTarget != this && !this.hasChild(event.relatedTarget)) this.fireEvent('mouseleave', event); 1204 } 1205 }, 1206 1207 'mousewheel': { 1208 type: (window.gecko) ? 'DOMMouseScroll' : 'mousewheel' 1209 } 1210 1211 }); 1212 1213 Element.NativeEvents = [ 1214 'click', 'dblclick', 'mouseup', 'mousedown', 1215 'mousewheel', 'DOMMouseScroll', 1216 'mouseover', 'mouseout', 'mousemove', 1217 'keydown', 'keypress', 'keyup', 1218 'load', 'unload', 'beforeunload', 'resize', 'move', 1219 'focus', 'blur', 'change', 'submit', 'reset', 'select', 1220 'error', 'abort', 'contextmenu', 'scroll' 1221 ]; 1222 1223 Function.extend({ 1224 1225 bindWithEvent: function(bind, args){ 1226 return this.create({'bind': bind, 'arguments': args, 'event': Event}); 1227 } 1228 1229 }); 1230 1231 Elements.extend({ 1232 1233 filterByTag: function(tag){ 1234 return new Elements(this.filter(function(el){ 1235 return (Element.getTag(el) == tag); 1236 })); 1237 }, 1238 1239 filterByClass: function(className, nocash){ 1240 var elements = this.filter(function(el){ 1241 return (el.className && el.className.contains(className, ' ')); 1242 }); 1243 return (nocash) ? elements : new Elements(elements); 1244 }, 1245 1246 filterById: function(id, nocash){ 1247 var elements = this.filter(function(el){ 1248 return (el.id == id); 1249 }); 1250 return (nocash) ? elements : new Elements(elements); 1251 }, 1252 1253 filterByAttribute: function(name, operator, value, nocash){ 1254 var elements = this.filter(function(el){ 1255 var current = Element.getProperty(el, name); 1256 if (!current) return false; 1257 if (!operator) return true; 1258 switch(operator){ 1259 case '=': return (current == value); 1260 case '*=': return (current.contains(value)); 1261 case '^=': return (current.substr(0, value.length) == value); 1262 case '$=': return (current.substr(current.length - value.length) == value); 1263 case '!=': return (current != value); 1264 case '~=': return current.contains(value, ' '); 1265 } 1266 return false; 1267 }); 1268 return (nocash) ? elements : new Elements(elements); 1269 } 1270 1271 }); 1272 1273 function $E(selector, filter){ 1274 return ($(filter) || document).getElement(selector); 1275 }; 1276 1277 function $ES(selector, filter){ 1278 return ($(filter) || document).getElementsBySelector(selector); 1279 }; 1280 1281 $$.shared = { 1282 1283 'regexp': /^(\w*|\*)(?:#([\w-]+)|\.([\w-]+))?(?:\[(\w+)(?:([!*^$]?=)["']?([^"'\]]*)["']?)?])?$/, 1284 1285 'xpath': { 1286 1287 getParam: function(items, context, param, i){ 1288 var temp = [context.namespaceURI ? 'xhtml:' : '', param[1]]; 1289 if (param[2]) temp.push('[@id="', param[2], '"]'); 1290 if (param[3]) temp.push('[contains(concat(" ", @class, " "), " ', param[3], ' ")]'); 1291 if (param[4]){ 1292 if (param[5] && param[6]){ 1293 switch(param[5]){ 1294 case '*=': temp.push('[contains(@', param[4], ', "', param[6], '")]'); break; 1295 case '^=': temp.push('[starts-with(@', param[4], ', "', param[6], '")]'); break; 1296 case '$=': temp.push('[substring(@', param[4], ', string-length(@', param[4], ') - ', param[6].length, ' + 1) = "', param[6], '"]'); break; 1297 case '=': temp.push('[@', param[4], '="', param[6], '"]'); break; 1298 case '!=': temp.push('[@', param[4], '!="', param[6], '"]'); 1299 } 1300 } else { 1301 temp.push('[@', param[4], ']'); 1302 } 1303 } 1304 items.push(temp.join('')); 1305 return items; 1306 }, 1307 1308 getItems: function(items, context, nocash){ 1309 var elements = []; 1310 var xpath = document.evaluate('.//' + items.join('//'), context, $$.shared.resolver, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); 1311 for (var i = 0, j = xpath.snapshotLength; i < j; i++) elements.push(xpath.snapshotItem(i)); 1312 return (nocash) ? elements : new Elements(elements.map($)); 1313 } 1314 1315 }, 1316 1317 'normal': { 1318 1319 getParam: function(items, context, param, i){ 1320 if (i == 0){ 1321 if (param[2]){ 1322 var el = context.getElementById(param[2]); 1323 if (!el || ((param[1] != '*') && (Element.getTag(el) != param[1]))) return false; 1324 items = [el]; 1325 } else { 1326 items = $A(context.getElementsByTagName(param[1])); 1327 } 1328 } else { 1329 items = $$.shared.getElementsByTagName(items, param[1]); 1330 if (param[2]) items = Elements.filterById(items, param[2], true); 1331 } 1332 if (param[3]) items = Elements.filterByClass(items, param[3], true); 1333 if (param[4]) items = Elements.filterByAttribute(items, param[4], param[5], param[6], true); 1334 return items; 1335 }, 1336 1337 getItems: function(items, context, nocash){ 1338 return (nocash) ? items : $$.unique(items); 1339 } 1340 1341 }, 1342 1343 resolver: function(prefix){ 1344 return (prefix == 'xhtml') ? 'http://www.w3.org/1999/xhtml' : false; 1345 }, 1346 1347 getElementsByTagName: function(context, tagName){ 1348 var found = []; 1349 for (var i = 0, j = context.length; i < j; i++) found.extend(context[i].getElementsByTagName(tagName)); 1350 return found; 1351 } 1352 1353 }; 1354 1355 $$.shared.method = (window.xpath) ? 'xpath' : 'normal'; 1356 1357 Element.Methods.Dom = { 1358 1359 getElements: function(selector, nocash){ 1360 var items = []; 1361 selector = selector.trim().split(' '); 1362 for (var i = 0, j = selector.length; i < j; i++){ 1363 var sel = selector[i]; 1364 var param = sel.match($$.shared.regexp); 1365 if (!param) break; 1366 param[1] = param[1] || '*'; 1367 var temp = $$.shared[$$.shared.method].getParam(items, this, param, i); 1368 if (!temp) break; 1369 items = temp; 1370 } 1371 return $$.shared[$$.shared.method].getItems(items, this, nocash); 1372 }, 1373 1374 getElement: function(selector){ 1375 return $(this.getElements(selector, true)[0] || false); 1376 }, 1377 1378 getElementsBySelector: function(selector, nocash){ 1379 var elements = []; 1380 selector = selector.split(','); 1381 for (var i = 0, j = selector.length; i < j; i++) elements = elements.concat(this.getElements(selector[i], true)); 1382 return (nocash) ? elements : $$.unique(elements); 1383 } 1384 1385 }; 1386 1387 Element.extend({ 1388 1389 getElementById: function(id){ 1390 var el = document.getElementById(id); 1391 if (!el) return false; 1392 for (var parent = el.parentNode; parent != this; parent = parent.parentNode){ 1393 if (!parent) return false; 1394 } 1395 return el; 1396 }/*compatibility*/, 1397 1398 getElementsByClassName: function(className){ 1399 return this.getElements('.' + className); 1400 } 1401 1402 }); 1403 1404 document.extend(Element.Methods.Dom); 1405 Element.extend(Element.Methods.Dom); 1406 1407 Element.extend({ 1408 1409 getValue: function(){ 1410 switch(this.getTag()){ 1411 case 'select': 1412 var values = []; 1413 $each(this.options, function(option){ 1414 if (option.selected) values.push($pick(option.value, option.text)); 1415 }); 1416 return (this.multiple) ? values : values[0]; 1417 case 'input': if (!(this.checked && ['checkbox', 'radio'].contains(this.type)) && !['hidden', 'text', 'password'].contains(this.type)) break; 1418 case 'textarea': return this.value; 1419 } 1420 return false; 1421 }, 1422 1423 getFormElements: function(){ 1424 return $$(this.getElementsByTagName('input'), this.getElementsByTagName('select'), this.getElementsByTagName('textarea')); 1425 }, 1426 1427 toQueryString: function(){ 1428 var queryString = []; 1429 this.getFormElements().each(function(el){ 1430 var name = el.name; 1431 var value = el.getValue(); 1432 if (value === false || !name || el.disabled) return; 1433 var qs = function(val){ 1434 queryString.push(name + '=' + encodeURIComponent(val)); 1435 }; 1436 if ($type(value) == 'array') value.each(qs); 1437 else qs(value); 1438 }); 1439 return queryString.join('&'); 1440 } 1441 1442 }); 1443 1444 Element.extend({ 1445 1446 scrollTo: function(x, y){ 1447 this.scrollLeft = x; 1448 this.scrollTop = y; 1449 }, 1450 1451 getSize: function(){ 1452 return { 1453 'scroll': {'x': this.scrollLeft, 'y': this.scrollTop}, 1454 'size': {'x': this.offsetWidth, 'y': this.offsetHeight}, 1455 'scrollSize': {'x': this.scrollWidth, 'y': this.scrollHeight} 1456 }; 1457 }, 1458 1459 getPosition: function(overflown){ 1460 overflown = overflown || []; 1461 var el = this, left = 0, top = 0; 1462 do { 1463 left += el.offsetLeft || 0; 1464 top += el.offsetTop || 0; 1465 el = el.offsetParent; 1466 } while (el); 1467 overflown.each(function(element){ 1468 left -= element.scrollLeft || 0; 1469 top -= element.scrollTop || 0; 1470 }); 1471 return {'x': left, 'y': top}; 1472 }, 1473 1474 getTop: function(overflown){ 1475 return this.getPosition(overflown).y; 1476 }, 1477 1478 getLeft: function(overflown){ 1479 return this.getPosition(overflown).x; 1480 }, 1481 1482 getCoordinates: function(overflown){ 1483 var position = this.getPosition(overflown); 1484 var obj = { 1485 'width': this.offsetWidth, 1486 'height': this.offsetHeight, 1487 'left': position.x, 1488 'top': position.y 1489 }; 1490 obj.right = obj.left + obj.width; 1491 obj.bottom = obj.top + obj.height; 1492 return obj; 1493 } 1494 1495 }); 1496 1497 Element.Events.domready = { 1498 1499 add: function(fn){ 1500 if (window.loaded){ 1501 fn.call(this); 1502 return; 1503 } 1504 var domReady = function(){ 1505 if (window.loaded) return; 1506 window.loaded = true; 1507 window.timer = $clear(window.timer); 1508 this.fireEvent('domready'); 1509 }.bind(this); 1510 if (document.readyState && window.webkit){ 1511 window.timer = function(){ 1512 if (['loaded','complete'].contains(document.readyState)) domReady(); 1513 }.periodical(50); 1514 } else if (document.readyState && window.ie){ 1515 if (!$('ie_ready')){ 1516 var src = (window.location.protocol == 'https:') ? '://0' : 'javascript:void(0)'; 1517 document.write('<script id="ie_ready" defer src="' + src + '"><\/script>'); 1518 $('ie_ready').onreadystatechange = function(){ 1519 if (this.readyState == 'complete') domReady(); 1520 }; 1521 } 1522 } else { 1523 window.addListener("load", domReady); 1524 document.addListener("DOMContentLoaded", domReady); 1525 } 1526 } 1527 1528 }; 1529 1530 window.onDomReady = function(fn){ 1531 return this.addEvent('domready', fn); 1532 }; 1533 1534 window.extend({ 1535 1536 getWidth: function(){ 1537 if (this.webkit419) return this.innerWidth; 1538 if (this.opera) return document.body.clientWidth; 1539 return document.documentElement.clientWidth; 1540 }, 1541 1542 getHeight: function(){ 1543 if (this.webkit419) return this.innerHeight; 1544 if (this.opera) return document.body.clientHeight; 1545 return document.documentElement.clientHeight; 1546 }, 1547 1548 getScrollWidth: function(){ 1549 if (this.ie) return Math.max(document.documentElement.offsetWidth, document.documentElement.scrollWidth); 1550 if (this.webkit) return document.body.scrollWidth; 1551 return document.documentElement.scrollWidth; 1552 }, 1553 1554 getScrollHeight: function(){ 1555 if (this.ie) return Math.max(document.documentElement.offsetHeight, document.documentElement.scrollHeight); 1556 if (this.webkit) return document.body.scrollHeight; 1557 return document.documentElement.scrollHeight; 1558 }, 1559 1560 getScrollLeft: function(){ 1561 return this.pageXOffset || document.documentElement.scrollLeft; 1562 }, 1563 1564 getScrollTop: function(){ 1565 return this.pageYOffset || document.documentElement.scrollTop; 1566 }, 1567 1568 getSize: function(){ 1569 return { 1570 'size': {'x': this.getWidth(), 'y': this.getHeight()}, 1571 'scrollSize': {'x': this.getScrollWidth(), 'y': this.getScrollHeight()}, 1572 'scroll': {'x': this.getScrollLeft(), 'y': this.getScrollTop()} 1573 }; 1574 }, 1575 getPosition: function(){return {'x': 0, 'y': 0};} 1576 1577 }); 1578 1579 var Fx = {}; 1580 1581 Fx.Base = new Class({ 1582 1583 options: { 1584 onStart: Class.empty, 1585 onComplete: Class.empty, 1586 onCancel: Class.empty, 1587 transition: function(p){ 1588 return -(Math.cos(Math.PI * p) - 1) / 2; 1589 }, 1590 duration: 500, 1591 unit: 'px', 1592 wait: true, 1593 fps: 50 1594 }, 1595 1596 initialize: function(options){ 1597 this.element = this.element || null; 1598 this.setOptions(options); 1599 if (this.options.initialize) this.options.initialize.call(this); 1600 }, 1601 1602 step: function(){ 1603 var time = $time(); 1604 if (time < this.time + this.options.duration){ 1605 this.delta = this.options.transition((time - this.time) / this.options.duration); 1606 this.setNow(); 1607 this.increase(); 1608 } else { 1609 this.stop(true); 1610 this.set(this.to); 1611 this.fireEvent('onComplete', this.element, 10); 1612 this.callChain(); 1613 } 1614 }, 1615 1616 set: function(to){ 1617 this.now = to; 1618 this.increase(); 1619 return this; 1620 }, 1621 1622 setNow: function(){ 1623 this.now = this.compute(this.from, this.to); 1624 }, 1625 1626 compute: function(from, to){ 1627 return (to - from) * this.delta + from; 1628 }, 1629 1630 start: function(from, to){ 1631 if (!this.options.wait) this.stop(); 1632 else if (this.timer) return this; 1633 this.from = from; 1634 this.to = to; 1635 this.change = this.to - this.from; 1636 this.time = $time(); 1637 this.timer = this.step.periodical(Math.round(1000 / this.options.fps), this); 1638 this.fireEvent('onStart', this.element); 1639 return this; 1640 }, 1641 1642 stop: function(end){ 1643 if (!this.timer) return this; 1644 this.timer = $clear(this.timer); 1645 if (!end) this.fireEvent('onCancel', this.element); 1646 return this; 1647 }/*compatibility*/, 1648 1649 custom: function(from, to){ 1650 return this.start(from, to); 1651 }, 1652 1653 clearTimer: function(end){ 1654 return this.stop(end); 1655 } 1656 1657 }); 1658 1659 Fx.Base.implement(new Chain, new Events, new Options); 1660 1661 Fx.CSS = { 1662 1663 select: function(property, to){ 1664 if (property.test(/color/i)) return this.Color; 1665 var type = $type(to); 1666 if ((type == 'array') || (type == 'string' && to.contains(' '))) return this.Multi; 1667 return this.Single; 1668 }, 1669 1670 parse: function(el, property, fromTo){ 1671 if (!fromTo.push) fromTo = [fromTo]; 1672 var from = fromTo[0], to = fromTo[1]; 1673 if (!$chk(to)){ 1674 to = from; 1675 from = el.getStyle(property); 1676 } 1677 var css = this.select(property, to); 1678 return {'from': css.parse(from), 'to': css.parse(to), 'css': css}; 1679 } 1680 1681 }; 1682 1683 Fx.CSS.Single = { 1684 1685 parse: function(value){ 1686 return parseFloat(value); 1687 }, 1688 1689 getNow: function(from, to, fx){ 1690 return fx.compute(from, to); 1691 }, 1692 1693 getValue: function(value, unit, property){ 1694 if (unit == 'px' && property != 'opacity') value = Math.round(value); 1695 return value + unit; 1696 } 1697 1698 }; 1699 1700 Fx.CSS.Multi = { 1701 1702 parse: function(value){ 1703 return value.push ? value : value.split(' ').map(function(v){ 1704 return parseFloat(v); 1705 }); 1706 }, 1707 1708 getNow: function(from, to, fx){ 1709 var now = []; 1710 for (var i = 0; i < from.length; i++) now[i] = fx.compute(from[i], to[i]); 1711 return now; 1712 }, 1713 1714 getValue: function(value, unit, property){ 1715 if (unit == 'px' && property != 'opacity') value = value.map(Math.round); 1716 return value.join(unit + ' ') + unit; 1717 } 1718 1719 }; 1720 1721 Fx.CSS.Color = { 1722 1723 parse: function(value){ 1724 return value.push ? value : value.hexToRgb(true); 1725 }, 1726 1727 getNow: function(from, to, fx){ 1728 var now = []; 1729 for (var i = 0; i < from.length; i++) now[i] = Math.round(fx.compute(from[i], to[i])); 1730 return now; 1731 }, 1732 1733 getValue: function(value){ 1734 return 'rgb(' + value.join(',') + ')'; 1735 } 1736 1737 }; 1738 1739 Fx.Style = Fx.Base.extend({ 1740 1741 initialize: function(el, property, options){ 1742 this.element = $(el); 1743 this.property = property; 1744 this.parent(options); 1745 }, 1746 1747 hide: function(){ 1748 return this.set(0); 1749 }, 1750 1751 setNow: function(){ 1752 this.now = this.css.getNow(this.from, this.to, this); 1753 }, 1754 1755 set: function(to){ 1756 this.css = Fx.CSS.select(this.property, to); 1757 return this.parent(this.css.parse(to)); 1758 }, 1759 1760 start: function(from, to){ 1761 if (this.timer && this.options.wait) return this; 1762 var parsed = Fx.CSS.parse(this.element, this.property, [from, to]); 1763 this.css = parsed.css; 1764 return this.parent(parsed.from, parsed.to); 1765 }, 1766 1767 increase: function(){ 1768 this.element.setStyle(this.property, this.css.getValue(this.now, this.options.unit, this.property)); 1769 } 1770 1771 }); 1772 1773 Element.extend({ 1774 1775 effect: function(property, options){ 1776 return new Fx.Style(this, property, options); 1777 } 1778 1779 }); 1780 1781 Fx.Styles = Fx.Base.extend({ 1782 1783 initialize: function(el, options){ 1784 this.element = $(el); 1785 this.parent(options); 1786 }, 1787 1788 setNow: function(){ 1789 for (var p in this.from) this.now[p] = this.css[p].getNow(this.from[p], this.to[p], this); 1790 }, 1791 1792 set: function(to){ 1793 var parsed = {}; 1794 this.css = {}; 1795 for (var p in to){ 1796 this.css[p] = Fx.CSS.select(p, to[p]); 1797 parsed[p] = this.css[p].parse(to[p]); 1798 } 1799 return this.parent(parsed); 1800 }, 1801 1802 start: function(obj){ 1803 if (this.timer && this.options.wait) return this; 1804 this.now = {}; 1805 this.css = {}; 1806 var from = {}, to = {}; 1807 for (var p in obj){ 1808 var parsed = Fx.CSS.parse(this.element, p, obj[p]); 1809 from[p] = parsed.from; 1810 to[p] = parsed.to; 1811 this.css[p] = parsed.css; 1812 } 1813 return this.parent(from, to); 1814 }, 1815 1816 increase: function(){ 1817 for (var p in this.now) this.element.setStyle(p, this.css[p].getValue(this.now[p], this.options.unit, p)); 1818 } 1819 1820 }); 1821 1822 Element.extend({ 1823 1824 effects: function(options){ 1825 return new Fx.Styles(this, options); 1826 } 1827 1828 }); 1829 1830 Fx.Elements = Fx.Base.extend({ 1831 1832 initialize: function(elements, options){ 1833 this.elements = $$(elements); 1834 this.parent(options); 1835 }, 1836 1837 setNow: function(){ 1838 for (var i in this.from){ 1839 var iFrom = this.from[i], iTo = this.to[i], iCss = this.css[i], iNow = this.now[i] = {}; 1840 for (var p in iFrom) iNow[p] = iCss[p].getNow(iFrom[p], iTo[p], this); 1841 } 1842 }, 1843 1844 set: function(to){ 1845 var parsed = {}; 1846 this.css = {}; 1847 for (var i in to){ 1848 var iTo = to[i], iCss = this.css[i] = {}, iParsed = parsed[i] = {}; 1849 for (var p in iTo){ 1850 iCss[p] = Fx.CSS.select(p, iTo[p]); 1851 iParsed[p] = iCss[p].parse(iTo[p]); 1852 } 1853 } 1854 return this.parent(parsed); 1855 }, 1856 1857 start: function(obj){ 1858 if (this.timer && this.options.wait) return this; 1859 this.now = {}; 1860 this.css = {}; 1861 var from = {}, to = {}; 1862 for (var i in obj){ 1863 var iProps = obj[i], iFrom = from[i] = {}, iTo = to[i] = {}, iCss = this.css[i] = {}; 1864 for (var p in iProps){ 1865 var parsed = Fx.CSS.parse(this.elements[i], p, iProps[p]); 1866 iFrom[p] = parsed.from; 1867 iTo[p] = parsed.to; 1868 iCss[p] = parsed.css; 1869 } 1870 } 1871 return this.parent(from, to); 1872 }, 1873 1874 increase: function(){ 1875 for (var i in this.now){ 1876 var iNow = this.now[i], iCss = this.css[i]; 1877 for (var p in iNow) this.elements[i].setStyle(p, iCss[p].getValue(iNow[p], this.options.unit, p)); 1878 } 1879 } 1880 1881 }); 1882 1883 Fx.Scroll = Fx.Base.extend({ 1884 1885 options: { 1886 overflown: [], 1887 offset: {'x': 0, 'y': 0}, 1888 wheelStops: true 1889 }, 1890 1891 initialize: function(element, options){ 1892 this.now = []; 1893 this.element = $(element); 1894 this.bound = {'stop': this.stop.bind(this, false)}; 1895 this.parent(options); 1896 if (this.options.wheelStops){ 1897 this.addEvent('onStart', function(){ 1898 document.addEvent('mousewheel', this.bound.stop); 1899 }.bind(this)); 1900 this.addEvent('onComplete', function(){ 1901 document.removeEvent('mousewheel', this.bound.stop); 1902 }.bind(this)); 1903 } 1904 }, 1905 1906 setNow: function(){ 1907 for (var i = 0; i < 2; i++) this.now[i] = this.compute(this.from[i], this.to[i]); 1908 }, 1909 1910 scrollTo: function(x, y){ 1911 if (this.timer && this.options.wait) return this; 1912 var el = this.element.getSize(); 1913 var values = {'x': x, 'y': y}; 1914 for (var z in el.size){ 1915 var max = el.scrollSize[z] - el.size[z]; 1916 if ($chk(values[z])) values[z] = ($type(values[z]) == 'number') ? values[z].limit(0, max) : max; 1917 else values[z] = el.scroll[z]; 1918 values[z] += this.options.offset[z]; 1919 } 1920 return this.start([el.scroll.x, el.scroll.y], [values.x, values.y]); 1921 }, 1922 1923 toTop: function(){ 1924 return this.scrollTo(false, 0); 1925 }, 1926 1927 toBottom: function(){ 1928 return this.scrollTo(false, 'full'); 1929 }, 1930 1931 toLeft: function(){ 1932 return this.scrollTo(0, false); 1933 }, 1934 1935 toRight: function(){ 1936 return this.scrollTo('full', false); 1937 }, 1938 1939 toElement: function(el){ 1940 var parent = this.element.getPosition(this.options.overflown); 1941 var target = $(el).getPosition(this.options.overflown); 1942 return this.scrollTo(target.x - parent.x, target.y - parent.y); 1943 }, 1944 1945 increase: function(){ 1946 this.element.scrollTo(this.now[0], this.now[1]); 1947 } 1948 1949 }); 1950 1951 Fx.Slide = Fx.Base.extend({ 1952 1953 options: { 1954 mode: 'vertical' 1955 }, 1956 1957 initialize: function(el, options){ 1958 this.element = $(el); 1959 this.wrapper = new Element('div', {'styles': $extend(this.element.getStyles('margin'), {'overflow': 'hidden'})}).injectAfter(this.element).adopt(this.element); 1960 this.element.setStyle('margin', 0); 1961 this.setOptions(options); 1962 this.now = []; 1963 this.parent(this.options); 1964 this.open = true; 1965 this.addEvent('onComplete', function(){ 1966 this.open = (this.now[0] === 0); 1967 }); 1968 if (window.webkit419) this.addEvent('onComplete', function(){ 1969 if (this.open) this.element.remove().inject(this.wrapper); 1970 }); 1971 }, 1972 1973 setNow: function(){ 1974 for (var i = 0; i < 2; i++) this.now[i] = this.compute(this.from[i], this.to[i]); 1975 }, 1976 1977 vertical: function(){ 1978 this.margin = 'margin-top'; 1979 this.layout = 'height'; 1980 this.offset = this.element.offsetHeight; 1981 }, 1982 1983 horizontal: function(){ 1984 this.margin = 'margin-left'; 1985 this.layout = 'width'; 1986 this.offset = this.element.offsetWidth; 1987 }, 1988 1989 slideIn: function(mode){ 1990 this[mode || this.options.mode](); 1991 return this.start([this.element.getStyle(this.margin).toInt(), this.wrapper.getStyle(this.layout).toInt()], [0, this.offset]); 1992 }, 1993 1994 slideOut: function(mode){ 1995 this[mode || this.options.mode](); 1996 return this.start([this.element.getStyle(this.margin).toInt(), this.wrapper.getStyle(this.layout).toInt()], [-this.offset, 0]); 1997 }, 1998 1999 hide: function(mode){ 2000 this[mode || this.options.mode](); 2001 this.open = false; 2002 return this.set([-this.offset, 0]); 2003 }, 2004 2005 show: function(mode){ 2006 this[mode || this.options.mode](); 2007 this.open = true; 2008 return this.set([0, this.offset]); 2009 }, 2010 2011 toggle: function(mode){ 2012 if (this.wrapper.offsetHeight == 0 || this.wrapper.offsetWidth == 0) return this.slideIn(mode); 2013 return this.slideOut(mode); 2014 }, 2015 2016 increase: function(){ 2017 this.element.setStyle(this.margin, this.now[0] + this.options.unit); 2018 this.wrapper.setStyle(this.layout, this.now[1] + this.options.unit); 2019 } 2020 2021 }); 2022 2023 Fx.Transition = function(transition, params){ 2024 params = params || []; 2025 if ($type(params) != 'array') params = [params]; 2026 return $extend(transition, { 2027 easeIn: function(pos){ 2028 return transition(pos, params); 2029 }, 2030 easeOut: function(pos){ 2031 return 1 - transition(1 - pos, params); 2032 }, 2033 easeInOut: function(pos){ 2034 return (pos <= 0.5) ? transition(2 * pos, params) / 2 : (2 - transition(2 * (1 - pos), params)) / 2; 2035 } 2036 }); 2037 }; 2038 2039 Fx.Transitions = new Abstract({ 2040 2041 linear: function(p){ 2042 return p; 2043 } 2044 2045 }); 2046 2047 Fx.Transitions.extend = function(transitions){ 2048 for (var transition in transitions){ 2049 Fx.Transitions[transition] = new Fx.Transition(transitions[transition]); 2050 Fx.Transitions.compat(transition); 2051 } 2052 }; 2053 2054 Fx.Transitions.compat = function(transition){ 2055 ['In', 'Out', 'InOut'].each(function(easeType){ 2056 Fx.Transitions[transition.toLowerCase() + easeType] = Fx.Transitions[transition]['ease' + easeType]; 2057 }); 2058 }; 2059 2060 Fx.Transitions.extend({ 2061 2062 Pow: function(p, x){ 2063 return Math.pow(p, x[0] || 6); 2064 }, 2065 2066 Expo: function(p){ 2067 return Math.pow(2, 8 * (p - 1)); 2068 }, 2069 2070 Circ: function(p){ 2071 return 1 - Math.sin(Math.acos(p)); 2072 }, 2073 2074 Sine: function(p){ 2075 return 1 - Math.sin((1 - p) * Math.PI / 2); 2076 }, 2077 2078 Back: function(p, x){ 2079 x = x[0] || 1.618; 2080 return Math.pow(p, 2) * ((x + 1) * p - x); 2081 }, 2082 2083 Bounce: function(p){ 2084 var value; 2085 for (var a = 0, b = 1; 1; a += b, b /= 2){ 2086 if (p >= (7 - 4 * a) / 11){ 2087 value = - Math.pow((11 - 6 * a - 11 * p) / 4, 2) + b * b; 2088 break; 2089 } 2090 } 2091 return value; 2092 }, 2093 2094 Elastic: function(p, x){ 2095 return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3); 2096 } 2097 2098 }); 2099 2100 ['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){ 2101 Fx.Transitions[transition] = new Fx.Transition(function(p){ 2102 return Math.pow(p, [i + 2]); 2103 }); 2104 Fx.Transitions.compat(transition); 2105 }); 2106 2107 var Drag = {}; 2108 2109 Drag.Base = new Class({ 2110 2111 options: { 2112 handle: false, 2113 unit: 'px', 2114 onStart: Class.empty, 2115 onBeforeStart: Class.empty, 2116 onComplete: Class.empty, 2117 onSnap: Class.empty, 2118 onDrag: Class.empty, 2119 limit: false, 2120 modifiers: {x: 'left', y: 'top'}, 2121 grid: false, 2122 snap: 6 2123 }, 2124 2125 initialize: function(el, options){ 2126 this.setOptions(options); 2127 this.element = $(el); 2128 this.handle = $(this.options.handle) || this.element; 2129 this.mouse = {'now': {}, 'pos': {}}; 2130 this.value = {'start': {}, 'now': {}}; 2131 this.bound = { 2132 'start': this.start.bindWithEvent(this), 2133 'check': this.check.bindWithEvent(this), 2134 'drag': this.drag.bindWithEvent(this), 2135 'stop': this.stop.bind(this) 2136 }; 2137 this.attach(); 2138 if (this.options.initialize) this.options.initialize.call(this); 2139 }, 2140 2141 attach: function(){ 2142 this.handle.addEvent('mousedown', this.bound.start); 2143 return this; 2144 }, 2145 2146 detach: function(){ 2147 this.handle.removeEvent('mousedown', this.bound.start); 2148 return this; 2149 }, 2150 2151 start: function(event){ 2152 this.fireEvent('onBeforeStart', this.element); 2153 this.mouse.start = event.page; 2154 var limit = this.options.limit; 2155 this.limit = {'x': [], 'y': []}; 2156 for (var z in this.options.modifiers){ 2157 if (!this.options.modifiers[z]) continue; 2158 this.value.now[z] = this.element.getStyle(this.options.modifiers[z]).toInt(); 2159 this.mouse.pos[z] = event.page[z] - this.value.now[z]; 2160 if (limit && limit[z]){ 2161 for (var i = 0; i < 2; i++){ 2162 if ($chk(limit[z][i])) this.limit[z][i] = ($type(limit[z][i]) == 'function') ? limit[z][i]() : limit[z][i]; 2163 } 2164 } 2165 } 2166 if ($type(this.options.grid) == 'number') this.options.grid = {'x': this.options.grid, 'y': this.options.grid}; 2167 document.addListener('mousemove', this.bound.check); 2168 document.addListener('mouseup', this.bound.stop); 2169 this.fireEvent('onStart', this.element); 2170 event.stop(); 2171 }, 2172 2173 check: function(event){ 2174 var distance = Math.round(Math.sqrt(Math.pow(event.page.x - this.mouse.start.x, 2) + Math.pow(event.page.y - this.mouse.start.y, 2))); 2175 if (distance > this.options.snap){ 2176 document.removeListener('mousemove', this.bound.check); 2177 document.addListener('mousemove', this.bound.drag); 2178 this.drag(event); 2179 this.fireEvent('onSnap', this.element); 2180 } 2181 event.stop(); 2182 }, 2183 2184 drag: function(event){ 2185 this.out = false; 2186 this.mouse.now = event.page; 2187 for (var z in this.options.modifiers){ 2188 if (!this.options.modifiers[z]) continue; 2189 this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z]; 2190 if (this.limit[z]){ 2191 if ($chk(this.limit[z][1]) && (this.value.now[z] > this.limit[z][1])){ 2192 this.value.now[z] = this.limit[z][1]; 2193 this.out = true; 2194 } else if ($chk(this.limit[z][0]) && (this.value.now[z] < this.limit[z][0])){ 2195 this.value.now[z] = this.limit[z][0]; 2196 this.out = true; 2197 } 2198 } 2199 if (this.options.grid[z]) this.value.now[z] -= (this.value.now[z] % this.options.grid[z]); 2200 this.element.setStyle(this.options.modifiers[z], this.value.now[z] + this.options.unit); 2201 } 2202 this.fireEvent('onDrag', this.element); 2203 event.stop(); 2204 }, 2205 2206 stop: function(){ 2207 document.removeListener('mousemove', this.bound.check); 2208 document.removeListener('mousemove', this.bound.drag); 2209 document.removeListener('mouseup', this.bound.stop); 2210 this.fireEvent('onComplete', this.element); 2211 } 2212 2213 }); 2214 2215 Drag.Base.implement(new Events, new Options); 2216 2217 Element.extend({ 2218 2219 makeResizable: function(options){ 2220 return new Drag.Base(this, $merge({modifiers: {x: 'width', y: 'height'}}, options)); 2221 } 2222 2223 }); 2224 2225 Drag.Move = Drag.Base.extend({ 2226 2227 options: { 2228 droppables: [], 2229 container: false, 2230 overflown: [] 2231 }, 2232 2233 initialize: function(el, options){ 2234 this.setOptions(options); 2235 this.element = $(el); 2236 this.droppables = $$(this.options.droppables); 2237 this.container = $(this.options.container); 2238 this.position = {'element': this.element.getStyle('position'), 'container': false}; 2239 if (this.container) this.position.container = this.container.getStyle('position'); 2240 if (!['relative', 'absolute', 'fixed'].contains(this.position.element)) this.position.element = 'absolute'; 2241 var top = this.element.getStyle('top').toInt(); 2242 var left = this.element.getStyle('left').toInt(); 2243 if (this.position.element == 'absolute' && !['relative', 'absolute', 'fixed'].contains(this.position.container)){ 2244 top = $chk(top) ? top : this.element.getTop(this.options.overflown); 2245 left = $chk(left) ? left : this.element.getLeft(this.options.overflown); 2246 } else { 2247 top = $chk(top) ? top : 0; 2248 left = $chk(left) ? left : 0; 2249 } 2250 this.element.setStyles({'top': top, 'left': left, 'position': this.position.element}); 2251 this.parent(this.element); 2252 }, 2253 2254 start: function(event){ 2255 this.overed = null; 2256 if (this.container){ 2257 var cont = this.container.getCoordinates(); 2258 var el = this.element.getCoordinates(); 2259 if (this.position.element == 'absolute' && !['relative', 'absolute', 'fixed'].contains(this.position.container)){ 2260 this.options.limit = { 2261 'x': [cont.left, cont.right - el.width], 2262 'y': [cont.top, cont.bottom - el.height] 2263 }; 2264 } else { 2265 this.options.limit = { 2266 'y': [0, cont.height - el.height], 2267 'x': [0, cont.width - el.width] 2268 }; 2269 } 2270 } 2271 this.parent(event); 2272 }, 2273 2274 drag: function(event){ 2275 this.parent(event); 2276 var overed = this.out ? false : this.droppables.filter(this.checkAgainst, this).getLast(); 2277 if (this.overed != overed){ 2278 if (this.overed) this.overed.fireEvent('leave', [this.element, this]); 2279 this.overed = overed ? overed.fireEvent('over', [this.element, this]) : null; 2280 } 2281 return this; 2282 }, 2283 2284 checkAgainst: function(el){ 2285 el = el.getCoordinates(this.options.overflown); 2286 var now = this.mouse.now; 2287 return (now.x > el.left && now.x < el.right && now.y < el.bottom && now.y > el.top); 2288 }, 2289 2290 stop: function(){ 2291 if (this.overed && !this.out) this.overed.fireEvent('drop', [this.element, this]); 2292 else this.element.fireEvent('emptydrop', this); 2293 this.parent(); 2294 return this; 2295 } 2296 2297 }); 2298 2299 Element.extend({ 2300 2301 makeDraggable: function(options){ 2302 return new Drag.Move(this, options); 2303 } 2304 2305 }); 2306 2307 var XHR = new Class({ 2308 2309 options: { 2310 method: 'post', 2311 async: true, 2312 onRequest: Class.empty, 2313 onSuccess: Class.empty, 2314 onFailure: Class.empty, 2315 urlEncoded: true, 2316 encoding: 'utf-8', 2317 autoCancel: false, 2318 headers: {} 2319 }, 2320 2321 setTransport: function(){ 2322 this.transport = (window.XMLHttpRequest) ? new XMLHttpRequest() : (window.ie ? new ActiveXObject('Microsoft.XMLHTTP') : false); 2323 return this; 2324 }, 2325 2326 initialize: function(options){ 2327 this.setTransport().setOptions(options); 2328 this.options.isSuccess = this.options.isSuccess || this.isSuccess; 2329 this.headers = {}; 2330 if (this.options.urlEncoded && this.options.method == 'post'){ 2331 var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : ''; 2332 this.setHeader('Content-type', 'application/x-www-form-urlencoded' + encoding); 2333 } 2334 if (this.options.initialize) this.options.initialize.call(this); 2335 }, 2336 2337 onStateChange: function(){ 2338 if (this.transport.readyState != 4 || !this.running) return; 2339 this.running = false; 2340 var status = 0; 2341 try {status = this.transport.status;} catch(e){}; 2342 if (this.options.isSuccess.call(this, status)) this.onSuccess(); 2343 else this.onFailure(); 2344 this.transport.onreadystatechange = Class.empty; 2345 }, 2346 2347 isSuccess: function(status){ 2348 return ((status >= 200) && (status < 300)); 2349 }, 2350 2351 onSuccess: function(){ 2352 this.response = { 2353 'text': this.transport.responseText, 2354 'xml': this.transport.responseXML 2355 }; 2356 this.fireEvent('onSuccess', [this.response.text, this.response.xml]); 2357 this.callChain(); 2358 }, 2359 2360 onFailure: function(){ 2361 this.fireEvent('onFailure', this.transport); 2362 }, 2363 2364 setHeader: function(name, value){ 2365 this.headers[name] = value; 2366 return this; 2367 }, 2368 2369 send: function(url, data){ 2370 if (this.options.autoCancel) this.cancel(); 2371 else if (this.running) return this; 2372 this.running = true; 2373 if (data && this.options.method == 'get'){ 2374 url = url + (url.contains('?') ? '&' : '?') + data; 2375 data = null; 2376 } 2377 this.transport.open(this.options.method.toUpperCase(), url, this.options.async); 2378 this.transport.onreadystatechange = this.onStateChange.bind(this); 2379 if ((this.options.method == 'post') && this.transport.overrideMimeType) this.setHeader('Connection', 'close'); 2380 $extend(this.headers, this.options.headers); 2381 for (var type in this.headers) try {this.transport.setRequestHeader(type, this.headers[type]);} catch(e){}; 2382 this.fireEvent('onRequest'); 2383 this.transport.send($pick(data, null)); 2384 return this; 2385 }, 2386 2387 cancel: function(){ 2388 if (!this.running) return this; 2389 this.running = false; 2390 this.transport.abort(); 2391 this.transport.onreadystatechange = Class.empty; 2392 this.setTransport(); 2393 this.fireEvent('onCancel'); 2394 return this; 2395 } 2396 2397 }); 2398 2399 XHR.implement(new Chain, new Events, new Options); 2400 2401 var Ajax = XHR.extend({ 2402 2403 options: { 2404 data: null, 2405 update: null, 2406 onComplete: Class.empty, 2407 evalScripts: false, 2408 evalResponse: false 2409 }, 2410 2411 initialize: function(url, options){ 2412 this.addEvent('onSuccess', this.onComplete); 2413 this.setOptions(options); 2414 this.options.data = this.options.data || this.options.postBody; 2415 if (!['post', 'get'].contains(this.options.method)){ 2416 this._method = '_method=' + this.options.method; 2417 this.options.method = 'post'; 2418 } 2419 this.parent(); 2420 this.setHeader('X-Requested-With', 'XMLHttpRequest'); 2421 this.setHeader('Accept', 'text/javascript, text/html, application/xml, text/xml, */*'); 2422 this.url = url; 2423 }, 2424 2425 onComplete: function(){ 2426 if (this.options.update) $(this.options.update).empty().setHTML(this.response.text); 2427 if (this.options.evalScripts || this.options.evalResponse) this.evalScripts(); 2428 this.fireEvent('onComplete', [this.response.text, this.response.xml], 20); 2429 }, 2430 2431 request: function(data){ 2432 data = data || this.options.data; 2433 switch($type(data)){ 2434 case 'element': data = $(data).toQueryString(); break; 2435 case 'object': data = Object.toQueryString(data); 2436 } 2437 if (this._method) data = (data) ? [this._method, data].join('&') : this._method; 2438 return this.send(this.url, data); 2439 }, 2440 2441 evalScripts: function(){ 2442 var script, scripts; 2443 if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) scripts = this.response.text; 2444 else { 2445 scripts = []; 2446 var regexp = /<script[^>]*>([\s\S]*?)<\/script>/gi; 2447 while ((script = regexp.exec(this.response.text))) scripts.push(script[1]); 2448 scripts = scripts.join('\n'); 2449 } 2450 if (scripts) (window.execScript) ? window.execScript(scripts) : window.setTimeout(scripts, 0); 2451 }, 2452 2453 getHeader: function(name){ 2454 try {return this.transport.getResponseHeader(name);} catch(e){}; 2455 return null; 2456 } 2457 2458 }); 2459 2460 Object.toQueryString = function(source){ 2461 var queryString = []; 2462 for (var property in source) queryString.push(encodeURIComponent(property) + '=' + encodeURIComponent(source[property])); 2463 return queryString.join('&'); 2464 }; 2465 2466 Element.extend({ 2467 2468 send: function(options){ 2469 return new Ajax(this.getProperty('action'), $merge({data: this.toQueryString()}, options, {method: 'post'})).request(); 2470 } 2471 2472 }); 2473 2474 var Cookie = new Abstract({ 2475 2476 options: { 2477 domain: false, 2478 path: false, 2479 duration: false, 2480 secure: false 2481 }, 2482 2483 set: function(key, value, options){ 2484 options = $merge(this.options, options); 2485 value = encodeURIComponent(value); 2486 if (options.domain) value += '; domain=' + options.domain; 2487 if (options.path) value += '; path=' + options.path; 2488 if (options.duration){ 2489 var date = new Date(); 2490 date.setTime(date.getTime() + options.duration * 24 * 60 * 60 * 1000); 2491 value += '; expires=' + date.toGMTString(); 2492 } 2493 if (options.secure) value += '; secure'; 2494 document.cookie = key + '=' + value; 2495 return $extend(options, {'key': key, 'value': value}); 2496 }, 2497 2498 get: function(key){ 2499 var value = document.cookie.match('(?:^|;)\\s*' + key.escapeRegExp() + '=([^;]*)'); 2500 return value ? decodeURIComponent(value[1]) : false; 2501 }, 2502 2503 remove: function(cookie, options){ 2504 if ($type(cookie) == 'object') this.set(cookie.key, '', $merge(cookie, {duration: -1})); 2505 else this.set(cookie, '', $merge(options, {duration: -1})); 2506 } 2507 2508 }); 2509 2510 var Json = { 2511 2512 toString: function(obj){ 2513 switch($type(obj)){ 2514 case 'string': 2515 return '"' + obj.replace(/(["\\])/g, '\\$1') + '"'; 2516 case 'array': 2517 return '[' + obj.map(Json.toString).join(',') + ']'; 2518 case 'object': 2519 var string = []; 2520 for (var property in obj) string.push(Json.toString(property) + ':' + Json.toString(obj[property])); 2521 return '{' + string.join(',') + '}'; 2522 case 'number': 2523 if (isFinite(obj)) break; 2524 case false: 2525 return 'null'; 2526 } 2527 return String(obj); 2528 }, 2529 2530 evaluate: function(str, secure){ 2531 return (($type(str) != 'string') || (secure && !str.test(/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/))) ? null : eval('(' + str + ')'); 2532 } 2533 2534 }; 2535 2536 Json.Remote = XHR.extend({ 2537 2538 initialize: function(url, options){ 2539 this.url = url; 2540 this.addEvent('onSuccess', this.onComplete); 2541 this.parent(options); 2542 this.setHeader('X-Request', 'JSON'); 2543 }, 2544 2545 send: function(obj){ 2546 return this.parent(this.url, 'json=' + Json.toString(obj)); 2547 }, 2548 2549 onComplete: function(){ 2550 this.fireEvent('onComplete', [Json.evaluate(this.response.text, this.options.secure)]); 2551 } 2552 2553 }); 2554 2555 var Asset = new Abstract({ 2556 2557 javascript: function(source, properties){ 2558 properties = $merge({ 2559 'onload': Class.empty 2560 }, properties); 2561 var script = new Element('script', {'src': source}).addEvents({ 2562 'load': properties.onload, 2563 'readystatechange': function(){ 2564 if (this.readyState == 'complete') this.fireEvent('load'); 2565 } 2566 }); 2567 delete properties.onload; 2568 return script.setProperties(properties).inject(document.head); 2569 }, 2570 2571 css: function(source, properties){ 2572 return new Element('link', $merge({ 2573 'rel': 'stylesheet', 'media': 'screen', 'type': 'text/css', 'href': source 2574 }, properties)).inject(document.head); 2575 }, 2576 2577 image: function(source, properties){ 2578 properties = $merge({ 2579 'onload': Class.empty, 2580 'onabort': Class.empty, 2581 'onerror': Class.empty 2582 }, properties); 2583 var image = new Image(); 2584 image.src = source; 2585 var element = new Element('img', {'src': source}); 2586 ['load', 'abort', 'error'].each(function(type){ 2587 var event = properties['on' + type]; 2588 delete properties['on' + type]; 2589 element.addEvent(type, function(){ 2590 this.removeEvent(type, arguments.callee); 2591 event.call(this); 2592 }); 2593 }); 2594 if (image.width && image.height) element.fireEvent('load', element, 1); 2595 return element.setProperties(properties); 2596 }, 2597 2598 images: function(sources, options){ 2599 options = $merge({ 2600 onComplete: Class.empty, 2601 onProgress: Class.empty 2602 }, options); 2603 if (!sources.push) sources = [sources]; 2604 var images = []; 2605 var counter = 0; 2606 sources.each(function(source){ 2607 var img = new Asset.image(source, { 2608 'onload': function(){ 2609 options.onProgress.call(this, counter); 2610 counter++; 2611 if (counter == sources.length) options.onComplete(); 2612 } 2613 }); 2614 images.push(img); 2615 }); 2616 return new Elements(images); 2617 } 2618 2619 }); 2620 2621 var Hash = new Class({ 2622 2623 length: 0, 2624 2625 initialize: function(object){ 2626 this.obj = object || {}; 2627 this.setLength(); 2628 }, 2629 2630 get: function(key){ 2631 return (this.hasKey(key)) ? this.obj[key] : null; 2632 }, 2633 2634 hasKey: function(key){ 2635 return (key in this.obj); 2636 }, 2637 2638 set: function(key, value){ 2639 if (!this.hasKey(key)) this.length++; 2640 this.obj[key] = value; 2641 return this; 2642 }, 2643 2644 setLength: function(){ 2645 this.length = 0; 2646 for (var p in this.obj) this.length++; 2647 return this; 2648 }, 2649 2650 remove: function(key){ 2651 if (this.hasKey(key)){ 2652 delete this.obj[key]; 2653 this.length--; 2654 } 2655 return this; 2656 }, 2657 2658 each: function(fn, bind){ 2659 $each(this.obj, fn, bind); 2660 }, 2661 2662 extend: function(obj){ 2663 $extend(this.obj, obj); 2664 return this.setLength(); 2665 }, 2666 2667 merge: function(){ 2668 this.obj = $merge.apply(null, [this.obj].extend(arguments)); 2669 return this.setLength(); 2670 }, 2671 2672 empty: function(){ 2673 this.obj = {}; 2674 this.length = 0; 2675 return this; 2676 }, 2677 2678 keys: function(){ 2679 var keys = []; 2680 for (var property in this.obj) keys.push(property); 2681 return keys; 2682 }, 2683 2684 values: function(){ 2685 var values = []; 2686 for (var property in this.obj) values.push(this.obj[property]); 2687 return values; 2688 } 2689 2690 }); 2691 2692 function $H(obj){ 2693 return new Hash(obj); 2694 }; 2695 2696 Hash.Cookie = Hash.extend({ 2697 2698 initialize: function(name, options){ 2699 this.name = name; 2700 this.options = $extend({'autoSave': true}, options || {}); 2701 this.load(); 2702 }, 2703 2704 save: function(){ 2705 if (this.length == 0){ 2706 Cookie.remove(this.name, this.options); 2707 return true; 2708 } 2709 var str = Json.toString(this.obj); 2710 if (str.length > 4096) return false; 2711 Cookie.set(this.name, str, this.options); 2712 return true; 2713 }, 2714 2715 load: function(){ 2716 this.obj = Json.evaluate(Cookie.get(this.name), true) || {}; 2717 this.setLength(); 2718 } 2719 2720 }); 2721 2722 Hash.Cookie.Methods = {}; 2723 ['extend', 'set', 'merge', 'empty', 'remove'].each(function(method){ 2724 Hash.Cookie.Methods[method] = function(){ 2725 Hash.prototype[method].apply(this, arguments); 2726 if (this.options.autoSave) this.save(); 2727 return this; 2728 }; 2729 }); 2730 Hash.Cookie.implement(Hash.Cookie.Methods); 2731 2732 var Color = new Class({ 2733 2734 initialize: function(color, type){ 2735 type = type || (color.push ? 'rgb' : 'hex'); 2736 var rgb, hsb; 2737 switch(type){ 2738 case 'rgb': 2739 rgb = color; 2740 hsb = rgb.rgbToHsb(); 2741 break; 2742 case 'hsb': 2743 rgb = color.hsbToRgb(); 2744 hsb = color; 2745 break; 2746 default: 2747 rgb = color.hexToRgb(true); 2748 hsb = rgb.rgbToHsb(); 2749 } 2750 rgb.hsb = hsb; 2751 rgb.hex = rgb.rgbToHex(); 2752 return $extend(rgb, Color.prototype); 2753 }, 2754 2755 mix: function(){ 2756 var colors = $A(arguments); 2757 var alpha = ($type(colors[colors.length - 1]) == 'number') ? colors.pop() : 50; 2758 var rgb = this.copy(); 2759 colors.each(function(color){ 2760 color = new Color(color); 2761 for (var i = 0; i < 3; i++) rgb[i] = Math.round((rgb[i] / 100 * (100 - alpha)) + (color[i] / 100 * alpha)); 2762 }); 2763 return new Color(rgb, 'rgb'); 2764 }, 2765 2766 invert: function(){ 2767 return new Color(this.map(function(value){ 2768 return 255 - value; 2769 })); 2770 }, 2771 2772 setHue: function(value){ 2773 return new Color([value, this.hsb[1], this.hsb[2]], 'hsb'); 2774 }, 2775 2776 setSaturation: function(percent){ 2777 return new Color([this.hsb[0], percent, this.hsb[2]], 'hsb'); 2778 }, 2779 2780 setBrightness: function(percent){ 2781 return new Color([this.hsb[0], this.hsb[1], percent], 'hsb'); 2782 } 2783 2784 }); 2785 2786 function $RGB(r, g, b){ 2787 return new Color([r, g, b], 'rgb'); 2788 }; 2789 2790 function $HSB(h, s, b){ 2791 return new Color([h, s, b], 'hsb'); 2792 }; 2793 2794 Array.extend({ 2795 2796 rgbToHsb: function(){ 2797 var red = this[0], green = this[1], blue = this[2]; 2798 var hue, saturation, brightness; 2799 var max = Math.max(red, green, blue), min = Math.min(red, green, blue); 2800 var delta = max - min; 2801 brightness = max / 255; 2802 saturation = (max != 0) ? delta / max : 0; 2803 if (saturation == 0){ 2804 hue = 0; 2805 } else { 2806 var rr = (max - red) / delta; 2807 var gr = (max - green) / delta; 2808 var br = (max - blue) / delta; 2809 if (red == max) hue = br - gr; 2810 else if (green == max) hue = 2 + rr - br; 2811 else hue = 4 + gr - rr; 2812 hue /= 6; 2813 if (hue < 0) hue++; 2814 } 2815 return [Math.round(hue * 360), Math.round(saturation * 100), Math.round(brightness * 100)]; 2816 }, 2817 2818 hsbToRgb: function(){ 2819 var br = Math.round(this[2] / 100 * 255); 2820 if (this[1] == 0){ 2821 return [br, br, br]; 2822 } else { 2823 var hue = this[0] % 360; 2824 var f = hue % 60; 2825 var p = Math.round((this[2] * (100 - this[1])) / 10000 * 255); 2826 var q = Math.round((this[2] * (6000 - this[1] * f)) / 600000 * 255); 2827 var t = Math.round((this[2] * (6000 - this[1] * (60 - f))) / 600000 * 255); 2828 switch(Math.floor(hue / 60)){ 2829 case 0: return [br, t, p]; 2830 case 1: return [q, br, p]; 2831 case 2: return [p, br, t]; 2832 case 3: return [p, q, br]; 2833 case 4: return [t, p, br]; 2834 case 5: return [br, p, q]; 2835 } 2836 } 2837 return false; 2838 } 2839 2840 }); 2841 2842 var Scroller = new Class({ 2843 2844 options: { 2845 area: 20, 2846 velocity: 1, 2847 onChange: function(x, y){ 2848 this.element.scrollTo(x, y); 2849 } 2850 }, 2851 2852 initialize: function(element, options){ 2853 this.setOptions(options); 2854 this.element = $(element); 2855 this.mousemover = ([window, document].contains(element)) ? $(document.body) : this.element; 2856 }, 2857 2858 start: function(){ 2859 this.coord = this.getCoords.bindWithEvent(this); 2860 this.mousemover.addListener('mousemove', this.coord); 2861 }, 2862 2863 stop: function(){ 2864 this.mousemover.removeListener('mousemove', this.coord); 2865 this.timer = $clear(this.timer); 2866 }, 2867 2868 getCoords: function(event){ 2869 this.page = (this.element == window) ? event.client : event.page; 2870 if (!this.timer) this.timer = this.scroll.periodical(50, this); 2871 }, 2872 2873 scroll: function(){ 2874 var el = this.element.getSize(); 2875 var pos = this.element.getPosition(); 2876 2877 var change = {'x': 0, 'y': 0}; 2878 for (var z in this.page){ 2879 if (this.page[z] < (this.options.area + pos[z]) && el.scroll[z] != 0) 2880 change[z] = (this.page[z] - this.options.area - pos[z]) * this.options.velocity; 2881 else if (this.page[z] + this.options.area > (el.size[z] + pos[z]) && el.scroll[z] + el.size[z] != el.scrollSize[z]) 2882 change[z] = (this.page[z] - el.size[z] + this.options.area - pos[z]) * this.options.velocity; 2883 } 2884 if (change.y || change.x) this.fireEvent('onChange', [el.scroll.x + change.x, el.scroll.y + change.y]); 2885 } 2886 2887 }); 2888 2889 Scroller.implement(new Events, new Options); 2890 2891 var Slider = new Class({ 2892 2893 options: { 2894 onChange: Class.empty, 2895 onComplete: Class.empty, 2896 onTick: function(pos){ 2897 this.knob.setStyle(this.p, pos); 2898 }, 2899 mode: 'horizontal', 2900 steps: 100, 2901 offset: 0 2902 }, 2903 2904 initialize: function(el, knob, options){ 2905 this.element = $(el); 2906 this.knob = $(knob); 2907 this.setOptions(options); 2908 this.previousChange = -1; 2909 this.previousEnd = -1; 2910 this.step = -1; 2911 this.element.addEvent('mousedown', this.clickedElement.bindWithEvent(this)); 2912 var mod, offset; 2913 switch(this.options.mode){ 2914 case 'horizontal': 2915 this.z = 'x'; 2916 this.p = 'left'; 2917 mod = {'x': 'left', 'y': false}; 2918 offset = 'offsetWidth'; 2919 break; 2920 case 'vertical': 2921 this.z = 'y'; 2922 this.p = 'top'; 2923 mod = {'x': false, 'y': 'top'}; 2924 offset = 'offsetHeight'; 2925 } 2926 this.max = this.element[offset] - this.knob[offset] + (this.options.offset * 2); 2927 this.half = this.knob[offset]/2; 2928 this.getPos = this.element['get' + this.p.capitalize()].bind(this.element); 2929 this.knob.setStyle('position', 'relative').setStyle(this.p, - this.options.offset); 2930 var lim = {}; 2931 lim[this.z] = [- this.options.offset, this.max - this.options.offset]; 2932 this.drag = new Drag.Base(this.knob, { 2933 limit: lim, 2934 modifiers: mod, 2935 snap: 0, 2936 onStart: function(){ 2937 this.draggedKnob(); 2938 }.bind(this), 2939 onDrag: function(){ 2940 this.draggedKnob(); 2941 }.bind(this), 2942 onComplete: function(){ 2943 this.draggedKnob(); 2944 this.end(); 2945 }.bind(this) 2946 }); 2947 if (this.options.initialize) this.options.initialize.call(this); 2948 }, 2949 2950 set: function(step){ 2951 this.step = step.limit(0, this.options.steps); 2952 this.checkStep(); 2953 this.end(); 2954 this.fireEvent('onTick', this.toPosition(this.step)); 2955 return this; 2956 }, 2957 2958 clickedElement: function(event){ 2959 var position = event.page[this.z] - this.getPos() - this.half; 2960 position = position.limit(-this.options.offset, this.max -this.options.offset); 2961 this.step = this.toStep(position); 2962 this.checkStep(); 2963 this.end(); 2964 this.fireEvent('onTick', position); 2965 }, 2966 2967 draggedKnob: function(){ 2968 this.step = this.toStep(this.drag.value.now[this.z]); 2969 this.checkStep(); 2970 }, 2971 2972 checkStep: function(){ 2973 if (this.previousChange != this.step){ 2974 this.previousChange = this.step; 2975 this.fireEvent('onChange', this.step); 2976 } 2977 }, 2978 2979 end: function(){ 2980 if (this.previousEnd !== this.step){ 2981 this.previousEnd = this.step; 2982 this.fireEvent('onComplete', this.step + ''); 2983 } 2984 }, 2985 2986 toStep: function(position){ 2987 return Math.round((position + this.options.offset) / this.max * this.options.steps); 2988 }, 2989 2990 toPosition: function(step){ 2991 return this.max * step / this.options.steps; 2992 } 2993 2994 }); 2995 2996 Slider.implement(new Events); 2997 Slider.implement(new Options); 2998 2999 var SmoothScroll = Fx.Scroll.extend({ 3000 3001 initialize: function(options){ 3002 this.parent(window, options); 3003 this.links = (this.options.links) ? $$(this.options.links) : $$(document.links); 3004 var location = window.location.href.match(/^[^#]*/)[0] + '#'; 3005 this.links.each(function(link){ 3006 if (link.href.indexOf(location) != 0) return; 3007 var anchor = link.href.substr(location.length); 3008 if (anchor && $(anchor)) this.useLink(link, anchor); 3009 }, this); 3010 if (!window.webkit419) this.addEvent('onComplete', function(){ 3011 window.location.hash = this.anchor; 3012 }); 3013 }, 3014 3015 useLink: function(link, anchor){ 3016 link.addEvent('click', function(event){ 3017 this.anchor = anchor; 3018 this.toElement(anchor); 3019 event.stop(); 3020 }.bindWithEvent(this)); 3021 } 3022 3023 }); 3024 3025 var Sortables = new Class({ 3026 3027 options: { 3028 handles: false, 3029 onStart: Class.empty, 3030 onComplete: Class.empty, 3031 ghost: true, 3032 snap: 3, 3033 onDragStart: function(element, ghost){ 3034 ghost.setStyle('opacity', 0.7); 3035 element.setStyle('opacity', 0.7); 3036 }, 3037 onDragComplete: function(element, ghost){ 3038 element.setStyle('opacity', 1); 3039 ghost.remove(); 3040 this.trash.remove(); 3041 } 3042 }, 3043 3044 initialize: function(list, options){ 3045 this.setOptions(options); 3046 this.list = $(list); 3047 this.elements = this.list.getChildren(); 3048 this.handles = (this.options.handles) ? $$(this.options.handles) : this.elements; 3049 this.bound = { 3050 'start': [], 3051 'moveGhost': this.moveGhost.bindWithEvent(this) 3052 }; 3053 for (var i = 0, l = this.handles.length; i < l; i++){ 3054 this.bound.start[i] = this.start.bindWithEvent(this, this.elements[i]); 3055 } 3056 this.attach(); 3057 if (this.options.initialize) this.options.initialize.call(this); 3058 this.bound.move = this.move.bindWithEvent(this); 3059 this.bound.end = this.end.bind(this); 3060 }, 3061 3062 attach: function(){ 3063 this.handles.each(function(handle, i){ 3064 handle.addEvent('mousedown', this.bound.start[i]); 3065 }, this); 3066 }, 3067 3068 detach: function(){ 3069 this.handles.each(function(handle, i){ 3070 handle.removeEvent('mousedown', this.bound.start[i]); 3071 }, this); 3072 }, 3073 3074 start: function(event, el){ 3075 this.active = el; 3076 this.coordinates = this.list.getCoordinates(); 3077 if (this.options.ghost){ 3078 var position = el.getPosition(); 3079 this.offset = event.page.y - position.y; 3080 this.trash = new Element('div').inject(document.body); 3081 this.ghost = el.clone().inject(this.trash).setStyles({ 3082 'position': 'absolute', 3083 'left': position.x, 3084 'top': event.page.y - this.offset 3085 }); 3086 document.addListener('mousemove', this.bound.moveGhost); 3087 this.fireEvent('onDragStart', [el, this.ghost]); 3088 } 3089 document.addListener('mousemove', this.bound.move); 3090 document.addListener('mouseup', this.bound.end); 3091 this.fireEvent('onStart', el); 3092 event.stop(); 3093 }, 3094 3095 moveGhost: function(event){ 3096 var value = event.page.y - this.offset; 3097 value = value.limit(this.coordinates.top, this.coordinates.bottom - this.ghost.offsetHeight); 3098 this.ghost.setStyle('top', value); 3099 event.stop(); 3100 }, 3101 3102 move: function(event){ 3103 var now = event.page.y; 3104 this.previous = this.previous || now; 3105 var up = ((this.previous - now) > 0); 3106 var prev = this.active.getPrevious(); 3107 var next = this.active.getNext(); 3108 if (prev && up && now < prev.getCoordinates().bottom) this.active.injectBefore(prev); 3109 if (next && !up && now > next.getCoordinates().top) this.active.injectAfter(next); 3110 this.previous = now; 3111 }, 3112 3113 serialize: function(converter){ 3114 return this.list.getChildren().map(converter || function(el){ 3115 return this.elements.indexOf(el); 3116 }, this); 3117 }, 3118 3119 end: function(){ 3120 this.previous = null; 3121 document.removeListener('mousemove', this.bound.move); 3122 document.removeListener('mouseup', this.bound.end); 3123 if (this.options.ghost){ 3124 document.removeListener('mousemove', this.bound.moveGhost); 3125 this.fireEvent('onDragComplete', [this.active, this.ghost]); 3126 } 3127 this.fireEvent('onComplete', this.active); 3128 } 3129 3130 }); 3131 3132 Sortables.implement(new Events, new Options); 3133 3134 var Tips = new Class({ 3135 3136 options: { 3137 onShow: function(tip){ 3138 tip.setStyle('visibility', 'visible'); 3139 }, 3140 onHide: function(tip){ 3141 tip.setStyle('visibility', 'hidden'); 3142 }, 3143 maxTitleChars: 30, 3144 showDelay: 100, 3145 hideDelay: 100, 3146 className: 'tool', 3147 offsets: {'x': 16, 'y': 16}, 3148 fixed: false 3149 }, 3150 3151 initialize: function(elements, options){ 3152 this.setOptions(options); 3153 this.toolTip = new Element('div', { 3154 'class': this.options.className + '-tip', 3155 'styles': { 3156 'position': 'absolute', 3157 'top': '0', 3158 'left': '0', 3159 'visibility': 'hidden' 3160 } 3161 }).inject(document.body); 3162 this.wrapper = new Element('div').inject(this.toolTip); 3163 $$(elements).each(this.build, this); 3164 if (this.options.initialize) this.options.initialize.call(this); 3165 }, 3166 3167 build: function(el){ 3168 el.$tmp.myTitle = (el.href && el.getTag() == 'a') ? el.href.replace('http://', '') : (el.rel || false); 3169 if (el.title){ 3170 var dual = el.title.split('::'); 3171 if (dual.length > 1){ 3172 el.$tmp.myTitle = dual[0].trim(); 3173 el.$tmp.myText = dual[1].trim(); 3174 } else { 3175 el.$tmp.myText = el.title; 3176 } 3177 el.removeAttribute('title'); 3178 } else { 3179 el.$tmp.myText = false; 3180 } 3181 if (el.$tmp.myTitle && el.$tmp.myTitle.length > this.options.maxTitleChars) el.$tmp.myTitle = el.$tmp.myTitle.substr(0, this.options.maxTitleChars - 1) + "…"; 3182 el.addEvent('mouseenter', function(event){ 3183 this.start(el); 3184 if (!this.options.fixed) this.locate(event); 3185 else this.position(el); 3186 }.bind(this)); 3187 if (!this.options.fixed) el.addEvent('mousemove', this.locate.bindWithEvent(this)); 3188 var end = this.end.bind(this); 3189 el.addEvent('mouseleave', end); 3190 el.addEvent('trash', end); 3191 }, 3192 3193 start: function(el){ 3194 this.wrapper.empty(); 3195 if (el.$tmp.myTitle){ 3196 this.title = new Element('span').inject(new Element('div', {'class': this.options.className + '-title'}).inject(this.wrapper)).setHTML(el.$tmp.myTitle); 3197 } 3198 if (el.$tmp.myText){ 3199 this.text = new Element('span').inject(new Element('div', {'class': this.options.className + '-text'}).inject(this.wrapper)).setHTML(el.$tmp.myText); 3200 } 3201 $clear(this.timer); 3202 this.timer = this.show.delay(this.options.showDelay, this); 3203 }, 3204 3205 end: function(event){ 3206 $clear(this.timer); 3207 this.timer = this.hide.delay(this.options.hideDelay, this); 3208 }, 3209 3210 position: function(element){ 3211 var pos = element.getPosition(); 3212 this.toolTip.setStyles({ 3213 'left': pos.x + this.options.offsets.x, 3214 'top': pos.y + this.options.offsets.y 3215 }); 3216 }, 3217 3218 locate: function(event){ 3219 var win = {'x': window.getWidth(), 'y': window.getHeight()}; 3220 var scroll = {'x': window.getScrollLeft(), 'y': window.getScrollTop()}; 3221 var tip = {'x': this.toolTip.offsetWidth, 'y': this.toolTip.offsetHeight}; 3222 var prop = {'x': 'left', 'y': 'top'}; 3223 for (var z in prop){ 3224 var pos = event.page[z] + this.options.offsets[z]; 3225 if ((pos + tip[z] - scroll[z]) > win[z]) pos = event.page[z] - this.options.offsets[z] - tip[z]; 3226 this.toolTip.setStyle(prop[z], pos); 3227 }; 3228 }, 3229 3230 show: function(){ 3231 if (this.options.timeout) this.timer = this.hide.delay(this.options.timeout, this); 3232 this.fireEvent('onShow', [this.toolTip]); 3233 }, 3234 3235 hide: function(){ 3236 this.fireEvent('onHide', [this.toolTip]); 3237 } 3238 3239 }); 3240 3241 Tips.implement(new Events, new Options); 3242 3243 var Group = new Class({ 3244 3245 initialize: function(){ 3246 this.instances = $A(arguments); 3247 this.events = {}; 3248 this.checker = {}; 3249 }, 3250 3251 addEvent: function(type, fn){ 3252 this.checker[type] = this.checker[type] || {}; 3253 this.events[type] = this.events[type] || []; 3254 if (this.events[type].contains(fn)) return false; 3255 else this.events[type].push(fn); 3256 this.instances.each(function(instance, i){ 3257 instance.addEvent(type, this.check.bind(this, [type, instance, i])); 3258 }, this); 3259 return this; 3260 }, 3261 3262 check: function(type, instance, i){ 3263 this.checker[type][i] = true; 3264 var every = this.instances.every(function(current, j){ 3265 return this.checker[type][j] || false; 3266 }, this); 3267 if (!every) return; 3268 this.checker[type] = {}; 3269 this.events[type].each(function(event){ 3270 event.call(this, this.instances, instance); 3271 }, this); 3272 } 3273 3274 }); 3275 3276 var Accordion = Fx.Elements.extend({ 3277 3278 options: { 3279 onActive: Class.empty, 3280 onBackground: Class.empty, 3281 display: 0, 3282 show: false, 3283 height: true, 3284 width: false, 3285 opacity: true, 3286 fixedHeight: false, 3287 fixedWidth: false, 3288 wait: false, 3289 alwaysHide: false 3290 }, 3291 3292 initialize: function(){ 3293 var options, togglers, elements, container; 3294 $each(arguments, function(argument, i){ 3295 switch($type(argument)){ 3296 case 'object': options = argument; break; 3297 case 'element': container = $(argument); break; 3298 default: 3299 var temp = $$(argument); 3300 if (!togglers) togglers = temp; 3301 else elements = temp; 3302 } 3303 }); 3304 this.togglers = togglers || []; 3305 this.elements = elements || []; 3306 this.container = $(container); 3307 this.setOptions(options); 3308 this.previous = -1; 3309 if (this.options.alwaysHide) this.options.wait = true; 3310 if ($chk(this.options.show)){ 3311 this.options.display = false; 3312 this.previous = this.options.show; 3313 } 3314 if (this.options.start){ 3315 this.options.display = false; 3316 this.options.show = false; 3317 } 3318 this.effects = {}; 3319 if (this.options.opacity) this.effects.opacity = 'fullOpacity'; 3320 if (this.options.width) this.effects.width = this.options.fixedWidth ? 'fullWidth' : 'offsetWidth'; 3321 if (this.options.height) this.effects.height = this.options.fixedHeight ? 'fullHeight' : 'scrollHeight'; 3322 for (var i = 0, l = this.togglers.length; i < l; i++) this.addSection(this.togglers[i], this.elements[i]); 3323 this.elements.each(function(el, i){ 3324 if (this.options.show === i){ 3325 this.fireEvent('onActive', [this.togglers[i], el]); 3326 } else { 3327 for (var fx in this.effects) el.setStyle(fx, 0); 3328 } 3329 }, this); 3330 this.parent(this.elements); 3331 if ($chk(this.options.display)) this.display(this.options.display); 3332 }, 3333 3334 addSection: function(toggler, element, pos){ 3335 toggler = $(toggler); 3336 element = $(element); 3337 var test = this.togglers.contains(toggler); 3338 var len = this.togglers.length; 3339 this.togglers.include(toggler); 3340 this.elements.include(element); 3341 if (len && (!test || pos)){ 3342 pos = $pick(pos, len - 1); 3343 toggler.injectBefore(this.togglers[pos]); 3344 element.injectAfter(toggler); 3345 } else if (this.container && !test){ 3346 toggler.inject(this.container); 3347 element.inject(this.container); 3348 } 3349 var idx = this.togglers.indexOf(toggler); 3350 toggler.addEvent('click', this.display.bind(this, idx)); 3351 if (this.options.height) element.setStyles({'padding-top': 0, 'border-top': 'none', 'padding-bottom': 0, 'border-bottom': 'none'}); 3352 if (this.options.width) element.setStyles({'padding-left': 0, 'border-left': 'none', 'padding-right': 0, 'border-right': 'none'}); 3353 element.fullOpacity = 1; 3354 if (this.options.fixedWidth) element.fullWidth = this.options.fixedWidth; 3355 if (this.options.fixedHeight) element.fullHeight = this.options.fixedHeight; 3356 element.setStyle('overflow', 'hidden'); 3357 if (!test){ 3358 for (var fx in this.effects) element.setStyle(fx, 0); 3359 } 3360 return this; 3361 }, 3362 3363 display: function(index){ 3364 index = ($type(index) == 'element') ? this.elements.indexOf(index) : index; 3365 if ((this.timer && this.options.wait) || (index === this.previous && !this.options.alwaysHide)) return this; 3366 this.previous = index; 3367 var obj = {}; 3368 this.elements.each(function(el, i){ 3369 obj[i] = {}; 3370 var hide = (i != index) || (this.options.alwaysHide && (el.offsetHeight > 0)); 3371 this.fireEvent(hide ? 'onBackground' : 'onActive', [this.togglers[i], el]); 3372 for (var fx in this.effects) obj[i][fx] = hide ? 0 : el[this.effects[fx]]; 3373 }, this); 3374 return this.start(obj); 3375 }, 3376 3377 showThisHideOpen: function(index){return this.display(index);} 3378 3379 }); 3380 3381 Fx.Accordion = Accordion;
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Dec 30 05:55:15 2009 | Cross-referenced by PHPXref 0.7 |