[ Index ] |
|
Code source de Mantis 1.1.0rc3 |
1 /* Prototype JavaScript framework, version 1.5.1.1 2 * (c) 2005-2007 Sam Stephenson 3 * 4 * Prototype is freely distributable under the terms of an MIT-style license. 5 * For details, see the Prototype web site: http://www.prototypejs.org/ 6 * 7 /*--------------------------------------------------------------------------*/ 8 9 var Prototype = { 10 Version: '1.5.1.1', 11 12 Browser: { 13 IE: !!(window.attachEvent && !window.opera), 14 Opera: !!window.opera, 15 WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1, 16 Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1 17 }, 18 19 BrowserFeatures: { 20 XPath: !!document.evaluate, 21 ElementExtensions: !!window.HTMLElement, 22 SpecificElementExtensions: 23 (document.createElement('div').__proto__ !== 24 document.createElement('form').__proto__) 25 }, 26 27 ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>', 28 JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, 29 30 emptyFunction: function() { }, 31 K: function(x) { return x } 32 } 33 34 var Class = { 35 create: function() { 36 return function() { 37 this.initialize.apply(this, arguments); 38 } 39 } 40 } 41 42 var Abstract = new Object(); 43 44 Object.extend = function(destination, source) { 45 for (var property in source) { 46 destination[property] = source[property]; 47 } 48 return destination; 49 } 50 51 Object.extend(Object, { 52 inspect: function(object) { 53 try { 54 if (object === undefined) return 'undefined'; 55 if (object === null) return 'null'; 56 return object.inspect ? object.inspect() : object.toString(); 57 } catch (e) { 58 if (e instanceof RangeError) return '...'; 59 throw e; 60 } 61 }, 62 63 toJSON: function(object) { 64 var type = typeof object; 65 switch(type) { 66 case 'undefined': 67 case 'function': 68 case 'unknown': return; 69 case 'boolean': return object.toString(); 70 } 71 if (object === null) return 'null'; 72 if (object.toJSON) return object.toJSON(); 73 if (object.ownerDocument === document) return; 74 var results = []; 75 for (var property in object) { 76 var value = Object.toJSON(object[property]); 77 if (value !== undefined) 78 results.push(property.toJSON() + ': ' + value); 79 } 80 return '{' + results.join(', ') + '}'; 81 }, 82 83 keys: function(object) { 84 var keys = []; 85 for (var property in object) 86 keys.push(property); 87 return keys; 88 }, 89 90 values: function(object) { 91 var values = []; 92 for (var property in object) 93 values.push(object[property]); 94 return values; 95 }, 96 97 clone: function(object) { 98 return Object.extend({}, object); 99 } 100 }); 101 102 Function.prototype.bind = function() { 103 var __method = this, args = $A(arguments), object = args.shift(); 104 return function() { 105 return __method.apply(object, args.concat($A(arguments))); 106 } 107 } 108 109 Function.prototype.bindAsEventListener = function(object) { 110 var __method = this, args = $A(arguments), object = args.shift(); 111 return function(event) { 112 return __method.apply(object, [event || window.event].concat(args)); 113 } 114 } 115 116 Object.extend(Number.prototype, { 117 toColorPart: function() { 118 return this.toPaddedString(2, 16); 119 }, 120 121 succ: function() { 122 return this + 1; 123 }, 124 125 times: function(iterator) { 126 $R(0, this, true).each(iterator); 127 return this; 128 }, 129 130 toPaddedString: function(length, radix) { 131 var string = this.toString(radix || 10); 132 return '0'.times(length - string.length) + string; 133 }, 134 135 toJSON: function() { 136 return isFinite(this) ? this.toString() : 'null'; 137 } 138 }); 139 140 Date.prototype.toJSON = function() { 141 return '"' + this.getFullYear() + '-' + 142 (this.getMonth() + 1).toPaddedString(2) + '-' + 143 this.getDate().toPaddedString(2) + 'T' + 144 this.getHours().toPaddedString(2) + ':' + 145 this.getMinutes().toPaddedString(2) + ':' + 146 this.getSeconds().toPaddedString(2) + '"'; 147 }; 148 149 var Try = { 150 these: function() { 151 var returnValue; 152 153 for (var i = 0, length = arguments.length; i < length; i++) { 154 var lambda = arguments[i]; 155 try { 156 returnValue = lambda(); 157 break; 158 } catch (e) {} 159 } 160 161 return returnValue; 162 } 163 } 164 165 /*--------------------------------------------------------------------------*/ 166 167 var PeriodicalExecuter = Class.create(); 168 PeriodicalExecuter.prototype = { 169 initialize: function(callback, frequency) { 170 this.callback = callback; 171 this.frequency = frequency; 172 this.currentlyExecuting = false; 173 174 this.registerCallback(); 175 }, 176 177 registerCallback: function() { 178 this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); 179 }, 180 181 stop: function() { 182 if (!this.timer) return; 183 clearInterval(this.timer); 184 this.timer = null; 185 }, 186 187 onTimerEvent: function() { 188 if (!this.currentlyExecuting) { 189 try { 190 this.currentlyExecuting = true; 191 this.callback(this); 192 } finally { 193 this.currentlyExecuting = false; 194 } 195 } 196 } 197 } 198 Object.extend(String, { 199 interpret: function(value) { 200 return value == null ? '' : String(value); 201 }, 202 specialChar: { 203 '\b': '\\b', 204 '\t': '\\t', 205 '\n': '\\n', 206 '\f': '\\f', 207 '\r': '\\r', 208 '\\': '\\\\' 209 } 210 }); 211 212 Object.extend(String.prototype, { 213 gsub: function(pattern, replacement) { 214 var result = '', source = this, match; 215 replacement = arguments.callee.prepareReplacement(replacement); 216 217 while (source.length > 0) { 218 if (match = source.match(pattern)) { 219 result += source.slice(0, match.index); 220 result += String.interpret(replacement(match)); 221 source = source.slice(match.index + match[0].length); 222 } else { 223 result += source, source = ''; 224 } 225 } 226 return result; 227 }, 228 229 sub: function(pattern, replacement, count) { 230 replacement = this.gsub.prepareReplacement(replacement); 231 count = count === undefined ? 1 : count; 232 233 return this.gsub(pattern, function(match) { 234 if (--count < 0) return match[0]; 235 return replacement(match); 236 }); 237 }, 238 239 scan: function(pattern, iterator) { 240 this.gsub(pattern, iterator); 241 return this; 242 }, 243 244 truncate: function(length, truncation) { 245 length = length || 30; 246 truncation = truncation === undefined ? '...' : truncation; 247 return this.length > length ? 248 this.slice(0, length - truncation.length) + truncation : this; 249 }, 250 251 strip: function() { 252 return this.replace(/^\s+/, '').replace(/\s+$/, ''); 253 }, 254 255 stripTags: function() { 256 return this.replace(/<\/?[^>]+>/gi, ''); 257 }, 258 259 stripScripts: function() { 260 return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); 261 }, 262 263 extractScripts: function() { 264 var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); 265 var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); 266 return (this.match(matchAll) || []).map(function(scriptTag) { 267 return (scriptTag.match(matchOne) || ['', ''])[1]; 268 }); 269 }, 270 271 evalScripts: function() { 272 return this.extractScripts().map(function(script) { return eval(script) }); 273 }, 274 275 escapeHTML: function() { 276 var self = arguments.callee; 277 self.text.data = this; 278 return self.div.innerHTML; 279 }, 280 281 unescapeHTML: function() { 282 var div = document.createElement('div'); 283 div.innerHTML = this.stripTags(); 284 return div.childNodes[0] ? (div.childNodes.length > 1 ? 285 $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) : 286 div.childNodes[0].nodeValue) : ''; 287 }, 288 289 toQueryParams: function(separator) { 290 var match = this.strip().match(/([^?#]*)(#.*)?$/); 291 if (!match) return {}; 292 293 return match[1].split(separator || '&').inject({}, function(hash, pair) { 294 if ((pair = pair.split('='))[0]) { 295 var key = decodeURIComponent(pair.shift()); 296 var value = pair.length > 1 ? pair.join('=') : pair[0]; 297 if (value != undefined) value = decodeURIComponent(value); 298 299 if (key in hash) { 300 if (hash[key].constructor != Array) hash[key] = [hash[key]]; 301 hash[key].push(value); 302 } 303 else hash[key] = value; 304 } 305 return hash; 306 }); 307 }, 308 309 toArray: function() { 310 return this.split(''); 311 }, 312 313 succ: function() { 314 return this.slice(0, this.length - 1) + 315 String.fromCharCode(this.charCodeAt(this.length - 1) + 1); 316 }, 317 318 times: function(count) { 319 var result = ''; 320 for (var i = 0; i < count; i++) result += this; 321 return result; 322 }, 323 324 camelize: function() { 325 var parts = this.split('-'), len = parts.length; 326 if (len == 1) return parts[0]; 327 328 var camelized = this.charAt(0) == '-' 329 ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) 330 : parts[0]; 331 332 for (var i = 1; i < len; i++) 333 camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); 334 335 return camelized; 336 }, 337 338 capitalize: function() { 339 return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); 340 }, 341 342 underscore: function() { 343 return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); 344 }, 345 346 dasherize: function() { 347 return this.gsub(/_/,'-'); 348 }, 349 350 inspect: function(useDoubleQuotes) { 351 var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) { 352 var character = String.specialChar[match[0]]; 353 return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16); 354 }); 355 if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; 356 return "'" + escapedString.replace(/'/g, '\\\'') + "'"; 357 }, 358 359 toJSON: function() { 360 return this.inspect(true); 361 }, 362 363 unfilterJSON: function(filter) { 364 return this.sub(filter || Prototype.JSONFilter, '#{1}'); 365 }, 366 367 isJSON: function() { 368 var str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); 369 return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); 370 }, 371 372 evalJSON: function(sanitize) { 373 var json = this.unfilterJSON(); 374 try { 375 if (!sanitize || json.isJSON()) return eval('(' + json + ')'); 376 } catch (e) { } 377 throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); 378 }, 379 380 include: function(pattern) { 381 return this.indexOf(pattern) > -1; 382 }, 383 384 startsWith: function(pattern) { 385 return this.indexOf(pattern) === 0; 386 }, 387 388 endsWith: function(pattern) { 389 var d = this.length - pattern.length; 390 return d >= 0 && this.lastIndexOf(pattern) === d; 391 }, 392 393 empty: function() { 394 return this == ''; 395 }, 396 397 blank: function() { 398 return /^\s*$/.test(this); 399 } 400 }); 401 402 if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, { 403 escapeHTML: function() { 404 return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); 405 }, 406 unescapeHTML: function() { 407 return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); 408 } 409 }); 410 411 String.prototype.gsub.prepareReplacement = function(replacement) { 412 if (typeof replacement == 'function') return replacement; 413 var template = new Template(replacement); 414 return function(match) { return template.evaluate(match) }; 415 } 416 417 String.prototype.parseQuery = String.prototype.toQueryParams; 418 419 Object.extend(String.prototype.escapeHTML, { 420 div: document.createElement('div'), 421 text: document.createTextNode('') 422 }); 423 424 with (String.prototype.escapeHTML) div.appendChild(text); 425 426 var Template = Class.create(); 427 Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; 428 Template.prototype = { 429 initialize: function(template, pattern) { 430 this.template = template.toString(); 431 this.pattern = pattern || Template.Pattern; 432 }, 433 434 evaluate: function(object) { 435 return this.template.gsub(this.pattern, function(match) { 436 var before = match[1]; 437 if (before == '\\') return match[2]; 438 return before + String.interpret(object[match[3]]); 439 }); 440 } 441 } 442 443 var $break = {}, $continue = new Error('"throw $continue" is deprecated, use "return" instead'); 444 445 var Enumerable = { 446 each: function(iterator) { 447 var index = 0; 448 try { 449 this._each(function(value) { 450 iterator(value, index++); 451 }); 452 } catch (e) { 453 if (e != $break) throw e; 454 } 455 return this; 456 }, 457 458 eachSlice: function(number, iterator) { 459 var index = -number, slices = [], array = this.toArray(); 460 while ((index += number) < array.length) 461 slices.push(array.slice(index, index+number)); 462 return slices.map(iterator); 463 }, 464 465 all: function(iterator) { 466 var result = true; 467 this.each(function(value, index) { 468 result = result && !!(iterator || Prototype.K)(value, index); 469 if (!result) throw $break; 470 }); 471 return result; 472 }, 473 474 any: function(iterator) { 475 var result = false; 476 this.each(function(value, index) { 477 if (result = !!(iterator || Prototype.K)(value, index)) 478 throw $break; 479 }); 480 return result; 481 }, 482 483 collect: function(iterator) { 484 var results = []; 485 this.each(function(value, index) { 486 results.push((iterator || Prototype.K)(value, index)); 487 }); 488 return results; 489 }, 490 491 detect: function(iterator) { 492 var result; 493 this.each(function(value, index) { 494 if (iterator(value, index)) { 495 result = value; 496 throw $break; 497 } 498 }); 499 return result; 500 }, 501 502 findAll: function(iterator) { 503 var results = []; 504 this.each(function(value, index) { 505 if (iterator(value, index)) 506 results.push(value); 507 }); 508 return results; 509 }, 510 511 grep: function(pattern, iterator) { 512 var results = []; 513 this.each(function(value, index) { 514 var stringValue = value.toString(); 515 if (stringValue.match(pattern)) 516 results.push((iterator || Prototype.K)(value, index)); 517 }) 518 return results; 519 }, 520 521 include: function(object) { 522 var found = false; 523 this.each(function(value) { 524 if (value == object) { 525 found = true; 526 throw $break; 527 } 528 }); 529 return found; 530 }, 531 532 inGroupsOf: function(number, fillWith) { 533 fillWith = fillWith === undefined ? null : fillWith; 534 return this.eachSlice(number, function(slice) { 535 while(slice.length < number) slice.push(fillWith); 536 return slice; 537 }); 538 }, 539 540 inject: function(memo, iterator) { 541 this.each(function(value, index) { 542 memo = iterator(memo, value, index); 543 }); 544 return memo; 545 }, 546 547 invoke: function(method) { 548 var args = $A(arguments).slice(1); 549 return this.map(function(value) { 550 return value[method].apply(value, args); 551 }); 552 }, 553 554 max: function(iterator) { 555 var result; 556 this.each(function(value, index) { 557 value = (iterator || Prototype.K)(value, index); 558 if (result == undefined || value >= result) 559 result = value; 560 }); 561 return result; 562 }, 563 564 min: function(iterator) { 565 var result; 566 this.each(function(value, index) { 567 value = (iterator || Prototype.K)(value, index); 568 if (result == undefined || value < result) 569 result = value; 570 }); 571 return result; 572 }, 573 574 partition: function(iterator) { 575 var trues = [], falses = []; 576 this.each(function(value, index) { 577 ((iterator || Prototype.K)(value, index) ? 578 trues : falses).push(value); 579 }); 580 return [trues, falses]; 581 }, 582 583 pluck: function(property) { 584 var results = []; 585 this.each(function(value, index) { 586 results.push(value[property]); 587 }); 588 return results; 589 }, 590 591 reject: function(iterator) { 592 var results = []; 593 this.each(function(value, index) { 594 if (!iterator(value, index)) 595 results.push(value); 596 }); 597 return results; 598 }, 599 600 sortBy: function(iterator) { 601 return this.map(function(value, index) { 602 return {value: value, criteria: iterator(value, index)}; 603 }).sort(function(left, right) { 604 var a = left.criteria, b = right.criteria; 605 return a < b ? -1 : a > b ? 1 : 0; 606 }).pluck('value'); 607 }, 608 609 toArray: function() { 610 return this.map(); 611 }, 612 613 zip: function() { 614 var iterator = Prototype.K, args = $A(arguments); 615 if (typeof args.last() == 'function') 616 iterator = args.pop(); 617 618 var collections = [this].concat(args).map($A); 619 return this.map(function(value, index) { 620 return iterator(collections.pluck(index)); 621 }); 622 }, 623 624 size: function() { 625 return this.toArray().length; 626 }, 627 628 inspect: function() { 629 return '#<Enumerable:' + this.toArray().inspect() + '>'; 630 } 631 } 632 633 Object.extend(Enumerable, { 634 map: Enumerable.collect, 635 find: Enumerable.detect, 636 select: Enumerable.findAll, 637 member: Enumerable.include, 638 entries: Enumerable.toArray 639 }); 640 var $A = Array.from = function(iterable) { 641 if (!iterable) return []; 642 if (iterable.toArray) { 643 return iterable.toArray(); 644 } else { 645 var results = []; 646 for (var i = 0, length = iterable.length; i < length; i++) 647 results.push(iterable[i]); 648 return results; 649 } 650 } 651 652 if (Prototype.Browser.WebKit) { 653 $A = Array.from = function(iterable) { 654 if (!iterable) return []; 655 if (!(typeof iterable == 'function' && iterable == '[object NodeList]') && 656 iterable.toArray) { 657 return iterable.toArray(); 658 } else { 659 var results = []; 660 for (var i = 0, length = iterable.length; i < length; i++) 661 results.push(iterable[i]); 662 return results; 663 } 664 } 665 } 666 667 Object.extend(Array.prototype, Enumerable); 668 669 if (!Array.prototype._reverse) 670 Array.prototype._reverse = Array.prototype.reverse; 671 672 Object.extend(Array.prototype, { 673 _each: function(iterator) { 674 for (var i = 0, length = this.length; i < length; i++) 675 iterator(this[i]); 676 }, 677 678 clear: function() { 679 this.length = 0; 680 return this; 681 }, 682 683 first: function() { 684 return this[0]; 685 }, 686 687 last: function() { 688 return this[this.length - 1]; 689 }, 690 691 compact: function() { 692 return this.select(function(value) { 693 return value != null; 694 }); 695 }, 696 697 flatten: function() { 698 return this.inject([], function(array, value) { 699 return array.concat(value && value.constructor == Array ? 700 value.flatten() : [value]); 701 }); 702 }, 703 704 without: function() { 705 var values = $A(arguments); 706 return this.select(function(value) { 707 return !values.include(value); 708 }); 709 }, 710 711 indexOf: function(object) { 712 for (var i = 0, length = this.length; i < length; i++) 713 if (this[i] == object) return i; 714 return -1; 715 }, 716 717 reverse: function(inline) { 718 return (inline !== false ? this : this.toArray())._reverse(); 719 }, 720 721 reduce: function() { 722 return this.length > 1 ? this : this[0]; 723 }, 724 725 uniq: function(sorted) { 726 return this.inject([], function(array, value, index) { 727 if (0 == index || (sorted ? array.last() != value : !array.include(value))) 728 array.push(value); 729 return array; 730 }); 731 }, 732 733 clone: function() { 734 return [].concat(this); 735 }, 736 737 size: function() { 738 return this.length; 739 }, 740 741 inspect: function() { 742 return '[' + this.map(Object.inspect).join(', ') + ']'; 743 }, 744 745 toJSON: function() { 746 var results = []; 747 this.each(function(object) { 748 var value = Object.toJSON(object); 749 if (value !== undefined) results.push(value); 750 }); 751 return '[' + results.join(', ') + ']'; 752 } 753 }); 754 755 Array.prototype.toArray = Array.prototype.clone; 756 757 function $w(string) { 758 string = string.strip(); 759 return string ? string.split(/\s+/) : []; 760 } 761 762 if (Prototype.Browser.Opera){ 763 Array.prototype.concat = function() { 764 var array = []; 765 for (var i = 0, length = this.length; i < length; i++) array.push(this[i]); 766 for (var i = 0, length = arguments.length; i < length; i++) { 767 if (arguments[i].constructor == Array) { 768 for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++) 769 array.push(arguments[i][j]); 770 } else { 771 array.push(arguments[i]); 772 } 773 } 774 return array; 775 } 776 } 777 var Hash = function(object) { 778 if (object instanceof Hash) this.merge(object); 779 else Object.extend(this, object || {}); 780 }; 781 782 Object.extend(Hash, { 783 toQueryString: function(obj) { 784 var parts = []; 785 parts.add = arguments.callee.addPair; 786 787 this.prototype._each.call(obj, function(pair) { 788 if (!pair.key) return; 789 var value = pair.value; 790 791 if (value && typeof value == 'object') { 792 if (value.constructor == Array) value.each(function(value) { 793 parts.add(pair.key, value); 794 }); 795 return; 796 } 797 parts.add(pair.key, value); 798 }); 799 800 return parts.join('&'); 801 }, 802 803 toJSON: function(object) { 804 var results = []; 805 this.prototype._each.call(object, function(pair) { 806 var value = Object.toJSON(pair.value); 807 if (value !== undefined) results.push(pair.key.toJSON() + ': ' + value); 808 }); 809 return '{' + results.join(', ') + '}'; 810 } 811 }); 812 813 Hash.toQueryString.addPair = function(key, value, prefix) { 814 key = encodeURIComponent(key); 815 if (value === undefined) this.push(key); 816 else this.push(key + '=' + (value == null ? '' : encodeURIComponent(value))); 817 } 818 819 Object.extend(Hash.prototype, Enumerable); 820 Object.extend(Hash.prototype, { 821 _each: function(iterator) { 822 for (var key in this) { 823 var value = this[key]; 824 if (value && value == Hash.prototype[key]) continue; 825 826 var pair = [key, value]; 827 pair.key = key; 828 pair.value = value; 829 iterator(pair); 830 } 831 }, 832 833 keys: function() { 834 return this.pluck('key'); 835 }, 836 837 values: function() { 838 return this.pluck('value'); 839 }, 840 841 merge: function(hash) { 842 return $H(hash).inject(this, function(mergedHash, pair) { 843 mergedHash[pair.key] = pair.value; 844 return mergedHash; 845 }); 846 }, 847 848 remove: function() { 849 var result; 850 for(var i = 0, length = arguments.length; i < length; i++) { 851 var value = this[arguments[i]]; 852 if (value !== undefined){ 853 if (result === undefined) result = value; 854 else { 855 if (result.constructor != Array) result = [result]; 856 result.push(value) 857 } 858 } 859 delete this[arguments[i]]; 860 } 861 return result; 862 }, 863 864 toQueryString: function() { 865 return Hash.toQueryString(this); 866 }, 867 868 inspect: function() { 869 return '#<Hash:{' + this.map(function(pair) { 870 return pair.map(Object.inspect).join(': '); 871 }).join(', ') + '}>'; 872 }, 873 874 toJSON: function() { 875 return Hash.toJSON(this); 876 } 877 }); 878 879 function $H(object) { 880 if (object instanceof Hash) return object; 881 return new Hash(object); 882 }; 883 884 // Safari iterates over shadowed properties 885 if (function() { 886 var i = 0, Test = function(value) { this.key = value }; 887 Test.prototype.key = 'foo'; 888 for (var property in new Test('bar')) i++; 889 return i > 1; 890 }()) Hash.prototype._each = function(iterator) { 891 var cache = []; 892 for (var key in this) { 893 var value = this[key]; 894 if ((value && value == Hash.prototype[key]) || cache.include(key)) continue; 895 cache.push(key); 896 var pair = [key, value]; 897 pair.key = key; 898 pair.value = value; 899 iterator(pair); 900 } 901 }; 902 ObjectRange = Class.create(); 903 Object.extend(ObjectRange.prototype, Enumerable); 904 Object.extend(ObjectRange.prototype, { 905 initialize: function(start, end, exclusive) { 906 this.start = start; 907 this.end = end; 908 this.exclusive = exclusive; 909 }, 910 911 _each: function(iterator) { 912 var value = this.start; 913 while (this.include(value)) { 914 iterator(value); 915 value = value.succ(); 916 } 917 }, 918 919 include: function(value) { 920 if (value < this.start) 921 return false; 922 if (this.exclusive) 923 return value < this.end; 924 return value <= this.end; 925 } 926 }); 927 928 var $R = function(start, end, exclusive) { 929 return new ObjectRange(start, end, exclusive); 930 } 931 932 var Ajax = { 933 getTransport: function() { 934 return Try.these( 935 function() {return new XMLHttpRequest()}, 936 function() {return new ActiveXObject('Msxml2.XMLHTTP')}, 937 function() {return new ActiveXObject('Microsoft.XMLHTTP')} 938 ) || false; 939 }, 940 941 activeRequestCount: 0 942 } 943 944 Ajax.Responders = { 945 responders: [], 946 947 _each: function(iterator) { 948 this.responders._each(iterator); 949 }, 950 951 register: function(responder) { 952 if (!this.include(responder)) 953 this.responders.push(responder); 954 }, 955 956 unregister: function(responder) { 957 this.responders = this.responders.without(responder); 958 }, 959 960 dispatch: function(callback, request, transport, json) { 961 this.each(function(responder) { 962 if (typeof responder[callback] == 'function') { 963 try { 964 responder[callback].apply(responder, [request, transport, json]); 965 } catch (e) {} 966 } 967 }); 968 } 969 }; 970 971 Object.extend(Ajax.Responders, Enumerable); 972 973 Ajax.Responders.register({ 974 onCreate: function() { 975 Ajax.activeRequestCount++; 976 }, 977 onComplete: function() { 978 Ajax.activeRequestCount--; 979 } 980 }); 981 982 Ajax.Base = function() {}; 983 Ajax.Base.prototype = { 984 setOptions: function(options) { 985 this.options = { 986 method: 'post', 987 asynchronous: true, 988 contentType: 'application/x-www-form-urlencoded', 989 encoding: 'UTF-8', 990 parameters: '' 991 } 992 Object.extend(this.options, options || {}); 993 994 this.options.method = this.options.method.toLowerCase(); 995 if (typeof this.options.parameters == 'string') 996 this.options.parameters = this.options.parameters.toQueryParams(); 997 } 998 } 999 1000 Ajax.Request = Class.create(); 1001 Ajax.Request.Events = 1002 ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; 1003 1004 Ajax.Request.prototype = Object.extend(new Ajax.Base(), { 1005 _complete: false, 1006 1007 initialize: function(url, options) { 1008 this.transport = Ajax.getTransport(); 1009 this.setOptions(options); 1010 this.request(url); 1011 }, 1012 1013 request: function(url) { 1014 this.url = url; 1015 this.method = this.options.method; 1016 var params = Object.clone(this.options.parameters); 1017 1018 if (!['get', 'post'].include(this.method)) { 1019 // simulate other verbs over post 1020 params['_method'] = this.method; 1021 this.method = 'post'; 1022 } 1023 1024 this.parameters = params; 1025 1026 if (params = Hash.toQueryString(params)) { 1027 // when GET, append parameters to URL 1028 if (this.method == 'get') 1029 this.url += (this.url.include('?') ? '&' : '?') + params; 1030 else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) 1031 params += '&_='; 1032 } 1033 1034 try { 1035 if (this.options.onCreate) this.options.onCreate(this.transport); 1036 Ajax.Responders.dispatch('onCreate', this, this.transport); 1037 1038 this.transport.open(this.method.toUpperCase(), this.url, 1039 this.options.asynchronous); 1040 1041 if (this.options.asynchronous) 1042 setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10); 1043 1044 this.transport.onreadystatechange = this.onStateChange.bind(this); 1045 this.setRequestHeaders(); 1046 1047 this.body = this.method == 'post' ? (this.options.postBody || params) : null; 1048 this.transport.send(this.body); 1049 1050 /* Force Firefox to handle ready state 4 for synchronous requests */ 1051 if (!this.options.asynchronous && this.transport.overrideMimeType) 1052 this.onStateChange(); 1053 1054 } 1055 catch (e) { 1056 this.dispatchException(e); 1057 } 1058 }, 1059 1060 onStateChange: function() { 1061 var readyState = this.transport.readyState; 1062 if (readyState > 1 && !((readyState == 4) && this._complete)) 1063 this.respondToReadyState(this.transport.readyState); 1064 }, 1065 1066 setRequestHeaders: function() { 1067 var headers = { 1068 'X-Requested-With': 'XMLHttpRequest', 1069 'X-Prototype-Version': Prototype.Version, 1070 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' 1071 }; 1072 1073 if (this.method == 'post') { 1074 headers['Content-type'] = this.options.contentType + 1075 (this.options.encoding ? '; charset=' + this.options.encoding : ''); 1076 1077 /* Force "Connection: close" for older Mozilla browsers to work 1078 * around a bug where XMLHttpRequest sends an incorrect 1079 * Content-length header. See Mozilla Bugzilla #246651. 1080 */ 1081 if (this.transport.overrideMimeType && 1082 (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) 1083 headers['Connection'] = 'close'; 1084 } 1085 1086 // user-defined headers 1087 if (typeof this.options.requestHeaders == 'object') { 1088 var extras = this.options.requestHeaders; 1089 1090 if (typeof extras.push == 'function') 1091 for (var i = 0, length = extras.length; i < length; i += 2) 1092 headers[extras[i]] = extras[i+1]; 1093 else 1094 $H(extras).each(function(pair) { headers[pair.key] = pair.value }); 1095 } 1096 1097 for (var name in headers) 1098 this.transport.setRequestHeader(name, headers[name]); 1099 }, 1100 1101 success: function() { 1102 return !this.transport.status 1103 || (this.transport.status >= 200 && this.transport.status < 300); 1104 }, 1105 1106 respondToReadyState: function(readyState) { 1107 var state = Ajax.Request.Events[readyState]; 1108 var transport = this.transport, json = this.evalJSON(); 1109 1110 if (state == 'Complete') { 1111 try { 1112 this._complete = true; 1113 (this.options['on' + this.transport.status] 1114 || this.options['on' + (this.success() ? 'Success' : 'Failure')] 1115 || Prototype.emptyFunction)(transport, json); 1116 } catch (e) { 1117 this.dispatchException(e); 1118 } 1119 1120 var contentType = this.getHeader('Content-type'); 1121 if (contentType && contentType.strip(). 1122 match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i)) 1123 this.evalResponse(); 1124 } 1125 1126 try { 1127 (this.options['on' + state] || Prototype.emptyFunction)(transport, json); 1128 Ajax.Responders.dispatch('on' + state, this, transport, json); 1129 } catch (e) { 1130 this.dispatchException(e); 1131 } 1132 1133 if (state == 'Complete') { 1134 // avoid memory leak in MSIE: clean up 1135 this.transport.onreadystatechange = Prototype.emptyFunction; 1136 } 1137 }, 1138 1139 getHeader: function(name) { 1140 try { 1141 return this.transport.getResponseHeader(name); 1142 } catch (e) { return null } 1143 }, 1144 1145 evalJSON: function() { 1146 try { 1147 var json = this.getHeader('X-JSON'); 1148 return json ? json.evalJSON() : null; 1149 } catch (e) { return null } 1150 }, 1151 1152 evalResponse: function() { 1153 try { 1154 return eval((this.transport.responseText || '').unfilterJSON()); 1155 } catch (e) { 1156 this.dispatchException(e); 1157 } 1158 }, 1159 1160 dispatchException: function(exception) { 1161 (this.options.onException || Prototype.emptyFunction)(this, exception); 1162 Ajax.Responders.dispatch('onException', this, exception); 1163 } 1164 }); 1165 1166 Ajax.Updater = Class.create(); 1167 1168 Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { 1169 initialize: function(container, url, options) { 1170 this.container = { 1171 success: (container.success || container), 1172 failure: (container.failure || (container.success ? null : container)) 1173 } 1174 1175 this.transport = Ajax.getTransport(); 1176 this.setOptions(options); 1177 1178 var onComplete = this.options.onComplete || Prototype.emptyFunction; 1179 this.options.onComplete = (function(transport, param) { 1180 this.updateContent(); 1181 onComplete(transport, param); 1182 }).bind(this); 1183 1184 this.request(url); 1185 }, 1186 1187 updateContent: function() { 1188 var receiver = this.container[this.success() ? 'success' : 'failure']; 1189 var response = this.transport.responseText; 1190 1191 if (!this.options.evalScripts) response = response.stripScripts(); 1192 1193 if (receiver = $(receiver)) { 1194 if (this.options.insertion) 1195 new this.options.insertion(receiver, response); 1196 else 1197 receiver.update(response); 1198 } 1199 1200 if (this.success()) { 1201 if (this.onComplete) 1202 setTimeout(this.onComplete.bind(this), 10); 1203 } 1204 } 1205 }); 1206 1207 Ajax.PeriodicalUpdater = Class.create(); 1208 Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { 1209 initialize: function(container, url, options) { 1210 this.setOptions(options); 1211 this.onComplete = this.options.onComplete; 1212 1213 this.frequency = (this.options.frequency || 2); 1214 this.decay = (this.options.decay || 1); 1215 1216 this.updater = {}; 1217 this.container = container; 1218 this.url = url; 1219 1220 this.start(); 1221 }, 1222 1223 start: function() { 1224 this.options.onComplete = this.updateComplete.bind(this); 1225 this.onTimerEvent(); 1226 }, 1227 1228 stop: function() { 1229 this.updater.options.onComplete = undefined; 1230 clearTimeout(this.timer); 1231 (this.onComplete || Prototype.emptyFunction).apply(this, arguments); 1232 }, 1233 1234 updateComplete: function(request) { 1235 if (this.options.decay) { 1236 this.decay = (request.responseText == this.lastText ? 1237 this.decay * this.options.decay : 1); 1238 1239 this.lastText = request.responseText; 1240 } 1241 this.timer = setTimeout(this.onTimerEvent.bind(this), 1242 this.decay * this.frequency * 1000); 1243 }, 1244 1245 onTimerEvent: function() { 1246 this.updater = new Ajax.Updater(this.container, this.url, this.options); 1247 } 1248 }); 1249 function $(element) { 1250 if (arguments.length > 1) { 1251 for (var i = 0, elements = [], length = arguments.length; i < length; i++) 1252 elements.push($(arguments[i])); 1253 return elements; 1254 } 1255 if (typeof element == 'string') 1256 element = document.getElementById(element); 1257 return Element.extend(element); 1258 } 1259 1260 if (Prototype.BrowserFeatures.XPath) { 1261 document._getElementsByXPath = function(expression, parentElement) { 1262 var results = []; 1263 var query = document.evaluate(expression, $(parentElement) || document, 1264 null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); 1265 for (var i = 0, length = query.snapshotLength; i < length; i++) 1266 results.push(query.snapshotItem(i)); 1267 return results; 1268 }; 1269 1270 document.getElementsByClassName = function(className, parentElement) { 1271 var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]"; 1272 return document._getElementsByXPath(q, parentElement); 1273 } 1274 1275 } else document.getElementsByClassName = function(className, parentElement) { 1276 var children = ($(parentElement) || document.body).getElementsByTagName('*'); 1277 var elements = [], child, pattern = new RegExp("(^|\\s)" + className + "(\\s|$)"); 1278 for (var i = 0, length = children.length; i < length; i++) { 1279 child = children[i]; 1280 var elementClassName = child.className; 1281 if (elementClassName.length == 0) continue; 1282 if (elementClassName == className || elementClassName.match(pattern)) 1283 elements.push(Element.extend(child)); 1284 } 1285 return elements; 1286 }; 1287 1288 /*--------------------------------------------------------------------------*/ 1289 1290 if (!window.Element) var Element = {}; 1291 1292 Element.extend = function(element) { 1293 var F = Prototype.BrowserFeatures; 1294 if (!element || !element.tagName || element.nodeType == 3 || 1295 element._extended || F.SpecificElementExtensions || element == window) 1296 return element; 1297 1298 var methods = {}, tagName = element.tagName, cache = Element.extend.cache, 1299 T = Element.Methods.ByTag; 1300 1301 // extend methods for all tags (Safari doesn't need this) 1302 if (!F.ElementExtensions) { 1303 Object.extend(methods, Element.Methods), 1304 Object.extend(methods, Element.Methods.Simulated); 1305 } 1306 1307 // extend methods for specific tags 1308 if (T[tagName]) Object.extend(methods, T[tagName]); 1309 1310 for (var property in methods) { 1311 var value = methods[property]; 1312 if (typeof value == 'function' && !(property in element)) 1313 element[property] = cache.findOrStore(value); 1314 } 1315 1316 element._extended = Prototype.emptyFunction; 1317 return element; 1318 }; 1319 1320 Element.extend.cache = { 1321 findOrStore: function(value) { 1322 return this[value] = this[value] || function() { 1323 return value.apply(null, [this].concat($A(arguments))); 1324 } 1325 } 1326 }; 1327 1328 Element.Methods = { 1329 visible: function(element) { 1330 return $(element).style.display != 'none'; 1331 }, 1332 1333 toggle: function(element) { 1334 element = $(element); 1335 Element[Element.visible(element) ? 'hide' : 'show'](element); 1336 return element; 1337 }, 1338 1339 hide: function(element) { 1340 $(element).style.display = 'none'; 1341 return element; 1342 }, 1343 1344 show: function(element) { 1345 $(element).style.display = ''; 1346 return element; 1347 }, 1348 1349 remove: function(element) { 1350 element = $(element); 1351 element.parentNode.removeChild(element); 1352 return element; 1353 }, 1354 1355 update: function(element, html) { 1356 html = typeof html == 'undefined' ? '' : html.toString(); 1357 $(element).innerHTML = html.stripScripts(); 1358 setTimeout(function() {html.evalScripts()}, 10); 1359 return element; 1360 }, 1361 1362 replace: function(element, html) { 1363 element = $(element); 1364 html = typeof html == 'undefined' ? '' : html.toString(); 1365 if (element.outerHTML) { 1366 element.outerHTML = html.stripScripts(); 1367 } else { 1368 var range = element.ownerDocument.createRange(); 1369 range.selectNodeContents(element); 1370 element.parentNode.replaceChild( 1371 range.createContextualFragment(html.stripScripts()), element); 1372 } 1373 setTimeout(function() {html.evalScripts()}, 10); 1374 return element; 1375 }, 1376 1377 inspect: function(element) { 1378 element = $(element); 1379 var result = '<' + element.tagName.toLowerCase(); 1380 $H({'id': 'id', 'className': 'class'}).each(function(pair) { 1381 var property = pair.first(), attribute = pair.last(); 1382 var value = (element[property] || '').toString(); 1383 if (value) result += ' ' + attribute + '=' + value.inspect(true); 1384 }); 1385 return result + '>'; 1386 }, 1387 1388 recursivelyCollect: function(element, property) { 1389 element = $(element); 1390 var elements = []; 1391 while (element = element[property]) 1392 if (element.nodeType == 1) 1393 elements.push(Element.extend(element)); 1394 return elements; 1395 }, 1396 1397 ancestors: function(element) { 1398 return $(element).recursivelyCollect('parentNode'); 1399 }, 1400 1401 descendants: function(element) { 1402 return $A($(element).getElementsByTagName('*')).each(Element.extend); 1403 }, 1404 1405 firstDescendant: function(element) { 1406 element = $(element).firstChild; 1407 while (element && element.nodeType != 1) element = element.nextSibling; 1408 return $(element); 1409 }, 1410 1411 immediateDescendants: function(element) { 1412 if (!(element = $(element).firstChild)) return []; 1413 while (element && element.nodeType != 1) element = element.nextSibling; 1414 if (element) return [element].concat($(element).nextSiblings()); 1415 return []; 1416 }, 1417 1418 previousSiblings: function(element) { 1419 return $(element).recursivelyCollect('previousSibling'); 1420 }, 1421 1422 nextSiblings: function(element) { 1423 return $(element).recursivelyCollect('nextSibling'); 1424 }, 1425 1426 siblings: function(element) { 1427 element = $(element); 1428 return element.previousSiblings().reverse().concat(element.nextSiblings()); 1429 }, 1430 1431 match: function(element, selector) { 1432 if (typeof selector == 'string') 1433 selector = new Selector(selector); 1434 return selector.match($(element)); 1435 }, 1436 1437 up: function(element, expression, index) { 1438 element = $(element); 1439 if (arguments.length == 1) return $(element.parentNode); 1440 var ancestors = element.ancestors(); 1441 return expression ? Selector.findElement(ancestors, expression, index) : 1442 ancestors[index || 0]; 1443 }, 1444 1445 down: function(element, expression, index) { 1446 element = $(element); 1447 if (arguments.length == 1) return element.firstDescendant(); 1448 var descendants = element.descendants(); 1449 return expression ? Selector.findElement(descendants, expression, index) : 1450 descendants[index || 0]; 1451 }, 1452 1453 previous: function(element, expression, index) { 1454 element = $(element); 1455 if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); 1456 var previousSiblings = element.previousSiblings(); 1457 return expression ? Selector.findElement(previousSiblings, expression, index) : 1458 previousSiblings[index || 0]; 1459 }, 1460 1461 next: function(element, expression, index) { 1462 element = $(element); 1463 if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); 1464 var nextSiblings = element.nextSiblings(); 1465 return expression ? Selector.findElement(nextSiblings, expression, index) : 1466 nextSiblings[index || 0]; 1467 }, 1468 1469 getElementsBySelector: function() { 1470 var args = $A(arguments), element = $(args.shift()); 1471 return Selector.findChildElements(element, args); 1472 }, 1473 1474 getElementsByClassName: function(element, className) { 1475 return document.getElementsByClassName(className, element); 1476 }, 1477 1478 readAttribute: function(element, name) { 1479 element = $(element); 1480 if (Prototype.Browser.IE) { 1481 if (!element.attributes) return null; 1482 var t = Element._attributeTranslations; 1483 if (t.values[name]) return t.values[name](element, name); 1484 if (t.names[name]) name = t.names[name]; 1485 var attribute = element.attributes[name]; 1486 return attribute ? attribute.nodeValue : null; 1487 } 1488 return element.getAttribute(name); 1489 }, 1490 1491 getHeight: function(element) { 1492 return $(element).getDimensions().height; 1493 }, 1494 1495 getWidth: function(element) { 1496 return $(element).getDimensions().width; 1497 }, 1498 1499 classNames: function(element) { 1500 return new Element.ClassNames(element); 1501 }, 1502 1503 hasClassName: function(element, className) { 1504 if (!(element = $(element))) return; 1505 var elementClassName = element.className; 1506 if (elementClassName.length == 0) return false; 1507 if (elementClassName == className || 1508 elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) 1509 return true; 1510 return false; 1511 }, 1512 1513 addClassName: function(element, className) { 1514 if (!(element = $(element))) return; 1515 Element.classNames(element).add(className); 1516 return element; 1517 }, 1518 1519 removeClassName: function(element, className) { 1520 if (!(element = $(element))) return; 1521 Element.classNames(element).remove(className); 1522 return element; 1523 }, 1524 1525 toggleClassName: function(element, className) { 1526 if (!(element = $(element))) return; 1527 Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className); 1528 return element; 1529 }, 1530 1531 observe: function() { 1532 Event.observe.apply(Event, arguments); 1533 return $A(arguments).first(); 1534 }, 1535 1536 stopObserving: function() { 1537 Event.stopObserving.apply(Event, arguments); 1538 return $A(arguments).first(); 1539 }, 1540 1541 // removes whitespace-only text node children 1542 cleanWhitespace: function(element) { 1543 element = $(element); 1544 var node = element.firstChild; 1545 while (node) { 1546 var nextNode = node.nextSibling; 1547 if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) 1548 element.removeChild(node); 1549 node = nextNode; 1550 } 1551 return element; 1552 }, 1553 1554 empty: function(element) { 1555 return $(element).innerHTML.blank(); 1556 }, 1557 1558 descendantOf: function(element, ancestor) { 1559 element = $(element), ancestor = $(ancestor); 1560 while (element = element.parentNode) 1561 if (element == ancestor) return true; 1562 return false; 1563 }, 1564 1565 scrollTo: function(element) { 1566 element = $(element); 1567 var pos = Position.cumulativeOffset(element); 1568 window.scrollTo(pos[0], pos[1]); 1569 return element; 1570 }, 1571 1572 getStyle: function(element, style) { 1573 element = $(element); 1574 style = style == 'float' ? 'cssFloat' : style.camelize(); 1575 var value = element.style[style]; 1576 if (!value) { 1577 var css = document.defaultView.getComputedStyle(element, null); 1578 value = css ? css[style] : null; 1579 } 1580 if (style == 'opacity') return value ? parseFloat(value) : 1.0; 1581 return value == 'auto' ? null : value; 1582 }, 1583 1584 getOpacity: function(element) { 1585 return $(element).getStyle('opacity'); 1586 }, 1587 1588 setStyle: function(element, styles, camelized) { 1589 element = $(element); 1590 var elementStyle = element.style; 1591 1592 for (var property in styles) 1593 if (property == 'opacity') element.setOpacity(styles[property]) 1594 else 1595 elementStyle[(property == 'float' || property == 'cssFloat') ? 1596 (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') : 1597 (camelized ? property : property.camelize())] = styles[property]; 1598 1599 return element; 1600 }, 1601 1602 setOpacity: function(element, value) { 1603 element = $(element); 1604 element.style.opacity = (value == 1 || value === '') ? '' : 1605 (value < 0.00001) ? 0 : value; 1606 return element; 1607 }, 1608 1609 getDimensions: function(element) { 1610 element = $(element); 1611 var display = $(element).getStyle('display'); 1612 if (display != 'none' && display != null) // Safari bug 1613 return {width: element.offsetWidth, height: element.offsetHeight}; 1614 1615 // All *Width and *Height properties give 0 on elements with display none, 1616 // so enable the element temporarily 1617 var els = element.style; 1618 var originalVisibility = els.visibility; 1619 var originalPosition = els.position; 1620 var originalDisplay = els.display; 1621 els.visibility = 'hidden'; 1622 els.position = 'absolute'; 1623 els.display = 'block'; 1624 var originalWidth = element.clientWidth; 1625 var originalHeight = element.clientHeight; 1626 els.display = originalDisplay; 1627 els.position = originalPosition; 1628 els.visibility = originalVisibility; 1629 return {width: originalWidth, height: originalHeight}; 1630 }, 1631 1632 makePositioned: function(element) { 1633 element = $(element); 1634 var pos = Element.getStyle(element, 'position'); 1635 if (pos == 'static' || !pos) { 1636 element._madePositioned = true; 1637 element.style.position = 'relative'; 1638 // Opera returns the offset relative to the positioning context, when an 1639 // element is position relative but top and left have not been defined 1640 if (window.opera) { 1641 element.style.top = 0; 1642 element.style.left = 0; 1643 } 1644 } 1645 return element; 1646 }, 1647 1648 undoPositioned: function(element) { 1649 element = $(element); 1650 if (element._madePositioned) { 1651 element._madePositioned = undefined; 1652 element.style.position = 1653 element.style.top = 1654 element.style.left = 1655 element.style.bottom = 1656 element.style.right = ''; 1657 } 1658 return element; 1659 }, 1660 1661 makeClipping: function(element) { 1662 element = $(element); 1663 if (element._overflow) return element; 1664 element._overflow = element.style.overflow || 'auto'; 1665 if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') 1666 element.style.overflow = 'hidden'; 1667 return element; 1668 }, 1669 1670 undoClipping: function(element) { 1671 element = $(element); 1672 if (!element._overflow) return element; 1673 element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; 1674 element._overflow = null; 1675 return element; 1676 } 1677 }; 1678 1679 Object.extend(Element.Methods, { 1680 childOf: Element.Methods.descendantOf, 1681 childElements: Element.Methods.immediateDescendants 1682 }); 1683 1684 if (Prototype.Browser.Opera) { 1685 Element.Methods._getStyle = Element.Methods.getStyle; 1686 Element.Methods.getStyle = function(element, style) { 1687 switch(style) { 1688 case 'left': 1689 case 'top': 1690 case 'right': 1691 case 'bottom': 1692 if (Element._getStyle(element, 'position') == 'static') return null; 1693 default: return Element._getStyle(element, style); 1694 } 1695 }; 1696 } 1697 else if (Prototype.Browser.IE) { 1698 Element.Methods.getStyle = function(element, style) { 1699 element = $(element); 1700 style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); 1701 var value = element.style[style]; 1702 if (!value && element.currentStyle) value = element.currentStyle[style]; 1703 1704 if (style == 'opacity') { 1705 if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) 1706 if (value[1]) return parseFloat(value[1]) / 100; 1707 return 1.0; 1708 } 1709 1710 if (value == 'auto') { 1711 if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) 1712 return element['offset'+style.capitalize()] + 'px'; 1713 return null; 1714 } 1715 return value; 1716 }; 1717 1718 Element.Methods.setOpacity = function(element, value) { 1719 element = $(element); 1720 var filter = element.getStyle('filter'), style = element.style; 1721 if (value == 1 || value === '') { 1722 style.filter = filter.replace(/alpha\([^\)]*\)/gi,''); 1723 return element; 1724 } else if (value < 0.00001) value = 0; 1725 style.filter = filter.replace(/alpha\([^\)]*\)/gi, '') + 1726 'alpha(opacity=' + (value * 100) + ')'; 1727 return element; 1728 }; 1729 1730 // IE is missing .innerHTML support for TABLE-related elements 1731 Element.Methods.update = function(element, html) { 1732 element = $(element); 1733 html = typeof html == 'undefined' ? '' : html.toString(); 1734 var tagName = element.tagName.toUpperCase(); 1735 if (['THEAD','TBODY','TR','TD'].include(tagName)) { 1736 var div = document.createElement('div'); 1737 switch (tagName) { 1738 case 'THEAD': 1739 case 'TBODY': 1740 div.innerHTML = '<table><tbody>' + html.stripScripts() + '</tbody></table>'; 1741 depth = 2; 1742 break; 1743 case 'TR': 1744 div.innerHTML = '<table><tbody><tr>' + html.stripScripts() + '</tr></tbody></table>'; 1745 depth = 3; 1746 break; 1747 case 'TD': 1748 div.innerHTML = '<table><tbody><tr><td>' + html.stripScripts() + '</td></tr></tbody></table>'; 1749 depth = 4; 1750 } 1751 $A(element.childNodes).each(function(node) { element.removeChild(node) }); 1752 depth.times(function() { div = div.firstChild }); 1753 $A(div.childNodes).each(function(node) { element.appendChild(node) }); 1754 } else { 1755 element.innerHTML = html.stripScripts(); 1756 } 1757 setTimeout(function() { html.evalScripts() }, 10); 1758 return element; 1759 } 1760 } 1761 else if (Prototype.Browser.Gecko) { 1762 Element.Methods.setOpacity = function(element, value) { 1763 element = $(element); 1764 element.style.opacity = (value == 1) ? 0.999999 : 1765 (value === '') ? '' : (value < 0.00001) ? 0 : value; 1766 return element; 1767 }; 1768 } 1769 1770 Element._attributeTranslations = { 1771 names: { 1772 colspan: "colSpan", 1773 rowspan: "rowSpan", 1774 valign: "vAlign", 1775 datetime: "dateTime", 1776 accesskey: "accessKey", 1777 tabindex: "tabIndex", 1778 enctype: "encType", 1779 maxlength: "maxLength", 1780 readonly: "readOnly", 1781 longdesc: "longDesc" 1782 }, 1783 values: { 1784 _getAttr: function(element, attribute) { 1785 return element.getAttribute(attribute, 2); 1786 }, 1787 _flag: function(element, attribute) { 1788 return $(element).hasAttribute(attribute) ? attribute : null; 1789 }, 1790 style: function(element) { 1791 return element.style.cssText.toLowerCase(); 1792 }, 1793 title: function(element) { 1794 var node = element.getAttributeNode('title'); 1795 return node.specified ? node.nodeValue : null; 1796 } 1797 } 1798 }; 1799 1800 (function() { 1801 Object.extend(this, { 1802 href: this._getAttr, 1803 src: this._getAttr, 1804 type: this._getAttr, 1805 disabled: this._flag, 1806 checked: this._flag, 1807 readonly: this._flag, 1808 multiple: this._flag 1809 }); 1810 }).call(Element._attributeTranslations.values); 1811 1812 Element.Methods.Simulated = { 1813 hasAttribute: function(element, attribute) { 1814 var t = Element._attributeTranslations, node; 1815 attribute = t.names[attribute] || attribute; 1816 node = $(element).getAttributeNode(attribute); 1817 return node && node.specified; 1818 } 1819 }; 1820 1821 Element.Methods.ByTag = {}; 1822 1823 Object.extend(Element, Element.Methods); 1824 1825 if (!Prototype.BrowserFeatures.ElementExtensions && 1826 document.createElement('div').__proto__) { 1827 window.HTMLElement = {}; 1828 window.HTMLElement.prototype = document.createElement('div').__proto__; 1829 Prototype.BrowserFeatures.ElementExtensions = true; 1830 } 1831 1832 Element.hasAttribute = function(element, attribute) { 1833 if (element.hasAttribute) return element.hasAttribute(attribute); 1834 return Element.Methods.Simulated.hasAttribute(element, attribute); 1835 }; 1836 1837 Element.addMethods = function(methods) { 1838 var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; 1839 1840 if (!methods) { 1841 Object.extend(Form, Form.Methods); 1842 Object.extend(Form.Element, Form.Element.Methods); 1843 Object.extend(Element.Methods.ByTag, { 1844 "FORM": Object.clone(Form.Methods), 1845 "INPUT": Object.clone(Form.Element.Methods), 1846 "SELECT": Object.clone(Form.Element.Methods), 1847 "TEXTAREA": Object.clone(Form.Element.Methods) 1848 }); 1849 } 1850 1851 if (arguments.length == 2) { 1852 var tagName = methods; 1853 methods = arguments[1]; 1854 } 1855 1856 if (!tagName) Object.extend(Element.Methods, methods || {}); 1857 else { 1858 if (tagName.constructor == Array) tagName.each(extend); 1859 else extend(tagName); 1860 } 1861 1862 function extend(tagName) { 1863 tagName = tagName.toUpperCase(); 1864 if (!Element.Methods.ByTag[tagName]) 1865 Element.Methods.ByTag[tagName] = {}; 1866 Object.extend(Element.Methods.ByTag[tagName], methods); 1867 } 1868 1869 function copy(methods, destination, onlyIfAbsent) { 1870 onlyIfAbsent = onlyIfAbsent || false; 1871 var cache = Element.extend.cache; 1872 for (var property in methods) { 1873 var value = methods[property]; 1874 if (!onlyIfAbsent || !(property in destination)) 1875 destination[property] = cache.findOrStore(value); 1876 } 1877 } 1878 1879 function findDOMClass(tagName) { 1880 var klass; 1881 var trans = { 1882 "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", 1883 "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", 1884 "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", 1885 "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", 1886 "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": 1887 "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": 1888 "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": 1889 "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": 1890 "FrameSet", "IFRAME": "IFrame" 1891 }; 1892 if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; 1893 if (window[klass]) return window[klass]; 1894 klass = 'HTML' + tagName + 'Element'; 1895 if (window[klass]) return window[klass]; 1896 klass = 'HTML' + tagName.capitalize() + 'Element'; 1897 if (window[klass]) return window[klass]; 1898 1899 window[klass] = {}; 1900 window[klass].prototype = document.createElement(tagName).__proto__; 1901 return window[klass]; 1902 } 1903 1904 if (F.ElementExtensions) { 1905 copy(Element.Methods, HTMLElement.prototype); 1906 copy(Element.Methods.Simulated, HTMLElement.prototype, true); 1907 } 1908 1909 if (F.SpecificElementExtensions) { 1910 for (var tag in Element.Methods.ByTag) { 1911 var klass = findDOMClass(tag); 1912 if (typeof klass == "undefined") continue; 1913 copy(T[tag], klass.prototype); 1914 } 1915 } 1916 1917 Object.extend(Element, Element.Methods); 1918 delete Element.ByTag; 1919 }; 1920 1921 var Toggle = { display: Element.toggle }; 1922 1923 /*--------------------------------------------------------------------------*/ 1924 1925 Abstract.Insertion = function(adjacency) { 1926 this.adjacency = adjacency; 1927 } 1928 1929 Abstract.Insertion.prototype = { 1930 initialize: function(element, content) { 1931 this.element = $(element); 1932 this.content = content.stripScripts(); 1933 1934 if (this.adjacency && this.element.insertAdjacentHTML) { 1935 try { 1936 this.element.insertAdjacentHTML(this.adjacency, this.content); 1937 } catch (e) { 1938 var tagName = this.element.tagName.toUpperCase(); 1939 if (['TBODY', 'TR'].include(tagName)) { 1940 this.insertContent(this.contentFromAnonymousTable()); 1941 } else { 1942 throw e; 1943 } 1944 } 1945 } else { 1946 this.range = this.element.ownerDocument.createRange(); 1947 if (this.initializeRange) this.initializeRange(); 1948 this.insertContent([this.range.createContextualFragment(this.content)]); 1949 } 1950 1951 setTimeout(function() {content.evalScripts()}, 10); 1952 }, 1953 1954 contentFromAnonymousTable: function() { 1955 var div = document.createElement('div'); 1956 div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>'; 1957 return $A(div.childNodes[0].childNodes[0].childNodes); 1958 } 1959 } 1960 1961 var Insertion = new Object(); 1962 1963 Insertion.Before = Class.create(); 1964 Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), { 1965 initializeRange: function() { 1966 this.range.setStartBefore(this.element); 1967 }, 1968 1969 insertContent: function(fragments) { 1970 fragments.each((function(fragment) { 1971 this.element.parentNode.insertBefore(fragment, this.element); 1972 }).bind(this)); 1973 } 1974 }); 1975 1976 Insertion.Top = Class.create(); 1977 Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), { 1978 initializeRange: function() { 1979 this.range.selectNodeContents(this.element); 1980 this.range.collapse(true); 1981 }, 1982 1983 insertContent: function(fragments) { 1984 fragments.reverse(false).each((function(fragment) { 1985 this.element.insertBefore(fragment, this.element.firstChild); 1986 }).bind(this)); 1987 } 1988 }); 1989 1990 Insertion.Bottom = Class.create(); 1991 Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), { 1992 initializeRange: function() { 1993 this.range.selectNodeContents(this.element); 1994 this.range.collapse(this.element); 1995 }, 1996 1997 insertContent: function(fragments) { 1998 fragments.each((function(fragment) { 1999 this.element.appendChild(fragment); 2000 }).bind(this)); 2001 } 2002 }); 2003 2004 Insertion.After = Class.create(); 2005 Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), { 2006 initializeRange: function() { 2007 this.range.setStartAfter(this.element); 2008 }, 2009 2010 insertContent: function(fragments) { 2011 fragments.each((function(fragment) { 2012 this.element.parentNode.insertBefore(fragment, 2013 this.element.nextSibling); 2014 }).bind(this)); 2015 } 2016 }); 2017 2018 /*--------------------------------------------------------------------------*/ 2019 2020 Element.ClassNames = Class.create(); 2021 Element.ClassNames.prototype = { 2022 initialize: function(element) { 2023 this.element = $(element); 2024 }, 2025 2026 _each: function(iterator) { 2027 this.element.className.split(/\s+/).select(function(name) { 2028 return name.length > 0; 2029 })._each(iterator); 2030 }, 2031 2032 set: function(className) { 2033 this.element.className = className; 2034 }, 2035 2036 add: function(classNameToAdd) { 2037 if (this.include(classNameToAdd)) return; 2038 this.set($A(this).concat(classNameToAdd).join(' ')); 2039 }, 2040 2041 remove: function(classNameToRemove) { 2042 if (!this.include(classNameToRemove)) return; 2043 this.set($A(this).without(classNameToRemove).join(' ')); 2044 }, 2045 2046 toString: function() { 2047 return $A(this).join(' '); 2048 } 2049 }; 2050 2051 Object.extend(Element.ClassNames.prototype, Enumerable); 2052 /* Portions of the Selector class are derived from Jack Slocum’s DomQuery, 2053 * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style 2054 * license. Please see http://www.yui-ext.com/ for more information. */ 2055 2056 var Selector = Class.create(); 2057 2058 Selector.prototype = { 2059 initialize: function(expression) { 2060 this.expression = expression.strip(); 2061 this.compileMatcher(); 2062 }, 2063 2064 compileMatcher: function() { 2065 // Selectors with namespaced attributes can't use the XPath version 2066 if (Prototype.BrowserFeatures.XPath && !(/\[[\w-]*?:/).test(this.expression)) 2067 return this.compileXPathMatcher(); 2068 2069 var e = this.expression, ps = Selector.patterns, h = Selector.handlers, 2070 c = Selector.criteria, le, p, m; 2071 2072 if (Selector._cache[e]) { 2073 this.matcher = Selector._cache[e]; return; 2074 } 2075 this.matcher = ["this.matcher = function(root) {", 2076 "var r = root, h = Selector.handlers, c = false, n;"]; 2077 2078 while (e && le != e && (/\S/).test(e)) { 2079 le = e; 2080 for (var i in ps) { 2081 p = ps[i]; 2082 if (m = e.match(p)) { 2083 this.matcher.push(typeof c[i] == 'function' ? c[i](m) : 2084 new Template(c[i]).evaluate(m)); 2085 e = e.replace(m[0], ''); 2086 break; 2087 } 2088 } 2089 } 2090 2091 this.matcher.push("return h.unique(n);\n}"); 2092 eval(this.matcher.join('\n')); 2093 Selector._cache[this.expression] = this.matcher; 2094 }, 2095 2096 compileXPathMatcher: function() { 2097 var e = this.expression, ps = Selector.patterns, 2098 x = Selector.xpath, le, m; 2099 2100 if (Selector._cache[e]) { 2101 this.xpath = Selector._cache[e]; return; 2102 } 2103 2104 this.matcher = ['.//*']; 2105 while (e && le != e && (/\S/).test(e)) { 2106 le = e; 2107 for (var i in ps) { 2108 if (m = e.match(ps[i])) { 2109 this.matcher.push(typeof x[i] == 'function' ? x[i](m) : 2110 new Template(x[i]).evaluate(m)); 2111 e = e.replace(m[0], ''); 2112 break; 2113 } 2114 } 2115 } 2116 2117 this.xpath = this.matcher.join(''); 2118 Selector._cache[this.expression] = this.xpath; 2119 }, 2120 2121 findElements: function(root) { 2122 root = root || document; 2123 if (this.xpath) return document._getElementsByXPath(this.xpath, root); 2124 return this.matcher(root); 2125 }, 2126 2127 match: function(element) { 2128 return this.findElements(document).include(element); 2129 }, 2130 2131 toString: function() { 2132 return this.expression; 2133 }, 2134 2135 inspect: function() { 2136 return "#<Selector:" + this.expression.inspect() + ">"; 2137 } 2138 }; 2139 2140 Object.extend(Selector, { 2141 _cache: {}, 2142 2143 xpath: { 2144 descendant: "//*", 2145 child: "/*", 2146 adjacent: "/following-sibling::*[1]", 2147 laterSibling: '/following-sibling::*', 2148 tagName: function(m) { 2149 if (m[1] == '*') return ''; 2150 return "[local-name()='" + m[1].toLowerCase() + 2151 "' or local-name()='" + m[1].toUpperCase() + "']"; 2152 }, 2153 className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", 2154 id: "[@id='#{1}']", 2155 attrPresence: "[@#{1}]", 2156 attr: function(m) { 2157 m[3] = m[5] || m[6]; 2158 return new Template(Selector.xpath.operators[m[2]]).evaluate(m); 2159 }, 2160 pseudo: function(m) { 2161 var h = Selector.xpath.pseudos[m[1]]; 2162 if (!h) return ''; 2163 if (typeof h === 'function') return h(m); 2164 return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); 2165 }, 2166 operators: { 2167 '=': "[@#{1}='#{3}']", 2168 '!=': "[@#{1}!='#{3}']", 2169 '^=': "[starts-with(@#{1}, '#{3}')]", 2170 '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", 2171 '*=': "[contains(@#{1}, '#{3}')]", 2172 '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", 2173 '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" 2174 }, 2175 pseudos: { 2176 'first-child': '[not(preceding-sibling::*)]', 2177 'last-child': '[not(following-sibling::*)]', 2178 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', 2179 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]", 2180 'checked': "[@checked]", 2181 'disabled': "[@disabled]", 2182 'enabled': "[not(@disabled)]", 2183 'not': function(m) { 2184 var e = m[6], p = Selector.patterns, 2185 x = Selector.xpath, le, m, v; 2186 2187 var exclusion = []; 2188 while (e && le != e && (/\S/).test(e)) { 2189 le = e; 2190 for (var i in p) { 2191 if (m = e.match(p[i])) { 2192 v = typeof x[i] == 'function' ? x[i](m) : new Template(x[i]).evaluate(m); 2193 exclusion.push("(" + v.substring(1, v.length - 1) + ")"); 2194 e = e.replace(m[0], ''); 2195 break; 2196 } 2197 } 2198 } 2199 return "[not(" + exclusion.join(" and ") + ")]"; 2200 }, 2201 'nth-child': function(m) { 2202 return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m); 2203 }, 2204 'nth-last-child': function(m) { 2205 return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m); 2206 }, 2207 'nth-of-type': function(m) { 2208 return Selector.xpath.pseudos.nth("position() ", m); 2209 }, 2210 'nth-last-of-type': function(m) { 2211 return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m); 2212 }, 2213 'first-of-type': function(m) { 2214 m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m); 2215 }, 2216 'last-of-type': function(m) { 2217 m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m); 2218 }, 2219 'only-of-type': function(m) { 2220 var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m); 2221 }, 2222 nth: function(fragment, m) { 2223 var mm, formula = m[6], predicate; 2224 if (formula == 'even') formula = '2n+0'; 2225 if (formula == 'odd') formula = '2n+1'; 2226 if (mm = formula.match(/^(\d+)$/)) // digit only 2227 return '[' + fragment + "= " + mm[1] + ']'; 2228 if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b 2229 if (mm[1] == "-") mm[1] = -1; 2230 var a = mm[1] ? Number(mm[1]) : 1; 2231 var b = mm[2] ? Number(mm[2]) : 0; 2232 predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " + 2233 "((#{fragment} - #{b}) div #{a} >= 0)]"; 2234 return new Template(predicate).evaluate({ 2235 fragment: fragment, a: a, b: b }); 2236 } 2237 } 2238 } 2239 }, 2240 2241 criteria: { 2242 tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;', 2243 className: 'n = h.className(n, r, "#{1}", c); c = false;', 2244 id: 'n = h.id(n, r, "#{1}", c); c = false;', 2245 attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;', 2246 attr: function(m) { 2247 m[3] = (m[5] || m[6]); 2248 return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m); 2249 }, 2250 pseudo: function(m) { 2251 if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); 2252 return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); 2253 }, 2254 descendant: 'c = "descendant";', 2255 child: 'c = "child";', 2256 adjacent: 'c = "adjacent";', 2257 laterSibling: 'c = "laterSibling";' 2258 }, 2259 2260 patterns: { 2261 // combinators must be listed first 2262 // (and descendant needs to be last combinator) 2263 laterSibling: /^\s*~\s*/, 2264 child: /^\s*>\s*/, 2265 adjacent: /^\s*\+\s*/, 2266 descendant: /^\s/, 2267 2268 // selectors follow 2269 tagName: /^\s*(\*|[\w\-]+)(\b|$)?/, 2270 id: /^#([\w\-\*]+)(\b|$)/, 2271 className: /^\.([\w\-\*]+)(\b|$)/, 2272 pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|\s|(?=:))/, 2273 attrPresence: /^\[([\w]+)\]/, 2274 attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\]]*?)\4|([^'"][^\]]*?)))?\]/ 2275 }, 2276 2277 handlers: { 2278 // UTILITY FUNCTIONS 2279 // joins two collections 2280 concat: function(a, b) { 2281 for (var i = 0, node; node = b[i]; i++) 2282 a.push(node); 2283 return a; 2284 }, 2285 2286 // marks an array of nodes for counting 2287 mark: function(nodes) { 2288 for (var i = 0, node; node = nodes[i]; i++) 2289 node._counted = true; 2290 return nodes; 2291 }, 2292 2293 unmark: function(nodes) { 2294 for (var i = 0, node; node = nodes[i]; i++) 2295 node._counted = undefined; 2296 return nodes; 2297 }, 2298 2299 // mark each child node with its position (for nth calls) 2300 // "ofType" flag indicates whether we're indexing for nth-of-type 2301 // rather than nth-child 2302 index: function(parentNode, reverse, ofType) { 2303 parentNode._counted = true; 2304 if (reverse) { 2305 for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { 2306 node = nodes[i]; 2307 if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++; 2308 } 2309 } else { 2310 for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) 2311 if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++; 2312 } 2313 }, 2314 2315 // filters out duplicates and extends all nodes 2316 unique: function(nodes) { 2317 if (nodes.length == 0) return nodes; 2318 var results = [], n; 2319 for (var i = 0, l = nodes.length; i < l; i++) 2320 if (!(n = nodes[i])._counted) { 2321 n._counted = true; 2322 results.push(Element.extend(n)); 2323 } 2324 return Selector.handlers.unmark(results); 2325 }, 2326 2327 // COMBINATOR FUNCTIONS 2328 descendant: function(nodes) { 2329 var h = Selector.handlers; 2330 for (var i = 0, results = [], node; node = nodes[i]; i++) 2331 h.concat(results, node.getElementsByTagName('*')); 2332 return results; 2333 }, 2334 2335 child: function(nodes) { 2336 var h = Selector.handlers; 2337 for (var i = 0, results = [], node; node = nodes[i]; i++) { 2338 for (var j = 0, children = [], child; child = node.childNodes[j]; j++) 2339 if (child.nodeType == 1 && child.tagName != '!') results.push(child); 2340 } 2341 return results; 2342 }, 2343 2344 adjacent: function(nodes) { 2345 for (var i = 0, results = [], node; node = nodes[i]; i++) { 2346 var next = this.nextElementSibling(node); 2347 if (next) results.push(next); 2348 } 2349 return results; 2350 }, 2351 2352 laterSibling: function(nodes) { 2353 var h = Selector.handlers; 2354 for (var i = 0, results = [], node; node = nodes[i]; i++) 2355 h.concat(results, Element.nextSiblings(node)); 2356 return results; 2357 }, 2358 2359 nextElementSibling: function(node) { 2360 while (node = node.nextSibling) 2361 if (node.nodeType == 1) return node; 2362 return null; 2363 }, 2364 2365 previousElementSibling: function(node) { 2366 while (node = node.previousSibling) 2367 if (node.nodeType == 1) return node; 2368 return null; 2369 }, 2370 2371 // TOKEN FUNCTIONS 2372 tagName: function(nodes, root, tagName, combinator) { 2373 tagName = tagName.toUpperCase(); 2374 var results = [], h = Selector.handlers; 2375 if (nodes) { 2376 if (combinator) { 2377 // fastlane for ordinary descendant combinators 2378 if (combinator == "descendant") { 2379 for (var i = 0, node; node = nodes[i]; i++) 2380 h.concat(results, node.getElementsByTagName(tagName)); 2381 return results; 2382 } else nodes = this[combinator](nodes); 2383 if (tagName == "*") return nodes; 2384 } 2385 for (var i = 0, node; node = nodes[i]; i++) 2386 if (node.tagName.toUpperCase() == tagName) results.push(node); 2387 return results; 2388 } else return root.getElementsByTagName(tagName); 2389 }, 2390 2391 id: function(nodes, root, id, combinator) { 2392 var targetNode = $(id), h = Selector.handlers; 2393 if (!nodes && root == document) return targetNode ? [targetNode] : []; 2394 if (nodes) { 2395 if (combinator) { 2396 if (combinator == 'child') { 2397 for (var i = 0, node; node = nodes[i]; i++) 2398 if (targetNode.parentNode == node) return [targetNode]; 2399 } else if (combinator == 'descendant') { 2400 for (var i = 0, node; node = nodes[i]; i++) 2401 if (Element.descendantOf(targetNode, node)) return [targetNode]; 2402 } else if (combinator == 'adjacent') { 2403 for (var i = 0, node; node = nodes[i]; i++) 2404 if (Selector.handlers.previousElementSibling(targetNode) == node) 2405 return [targetNode]; 2406 } else nodes = h[combinator](nodes); 2407 } 2408 for (var i = 0, node; node = nodes[i]; i++) 2409 if (node == targetNode) return [targetNode]; 2410 return []; 2411 } 2412 return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; 2413 }, 2414 2415 className: function(nodes, root, className, combinator) { 2416 if (nodes && combinator) nodes = this[combinator](nodes); 2417 return Selector.handlers.byClassName(nodes, root, className); 2418 }, 2419 2420 byClassName: function(nodes, root, className) { 2421 if (!nodes) nodes = Selector.handlers.descendant([root]); 2422 var needle = ' ' + className + ' '; 2423 for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { 2424 nodeClassName = node.className; 2425 if (nodeClassName.length == 0) continue; 2426 if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle)) 2427 results.push(node); 2428 } 2429 return results; 2430 }, 2431 2432 attrPresence: function(nodes, root, attr) { 2433 var results = []; 2434 for (var i = 0, node; node = nodes[i]; i++) 2435 if (Element.hasAttribute(node, attr)) results.push(node); 2436 return results; 2437 }, 2438 2439 attr: function(nodes, root, attr, value, operator) { 2440 if (!nodes) nodes = root.getElementsByTagName("*"); 2441 var handler = Selector.operators[operator], results = []; 2442 for (var i = 0, node; node = nodes[i]; i++) { 2443 var nodeValue = Element.readAttribute(node, attr); 2444 if (nodeValue === null) continue; 2445 if (handler(nodeValue, value)) results.push(node); 2446 } 2447 return results; 2448 }, 2449 2450 pseudo: function(nodes, name, value, root, combinator) { 2451 if (nodes && combinator) nodes = this[combinator](nodes); 2452 if (!nodes) nodes = root.getElementsByTagName("*"); 2453 return Selector.pseudos[name](nodes, value, root); 2454 } 2455 }, 2456 2457 pseudos: { 2458 'first-child': function(nodes, value, root) { 2459 for (var i = 0, results = [], node; node = nodes[i]; i++) { 2460 if (Selector.handlers.previousElementSibling(node)) continue; 2461 results.push(node); 2462 } 2463 return results; 2464 }, 2465 'last-child': function(nodes, value, root) { 2466 for (var i = 0, results = [], node; node = nodes[i]; i++) { 2467 if (Selector.handlers.nextElementSibling(node)) continue; 2468 results.push(node); 2469 } 2470 return results; 2471 }, 2472 'only-child': function(nodes, value, root) { 2473 var h = Selector.handlers; 2474 for (var i = 0, results = [], node; node = nodes[i]; i++) 2475 if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) 2476 results.push(node); 2477 return results; 2478 }, 2479 'nth-child': function(nodes, formula, root) { 2480 return Selector.pseudos.nth(nodes, formula, root); 2481 }, 2482 'nth-last-child': function(nodes, formula, root) { 2483 return Selector.pseudos.nth(nodes, formula, root, true); 2484 }, 2485 'nth-of-type': function(nodes, formula, root) { 2486 return Selector.pseudos.nth(nodes, formula, root, false, true); 2487 }, 2488 'nth-last-of-type': function(nodes, formula, root) { 2489 return Selector.pseudos.nth(nodes, formula, root, true, true); 2490 }, 2491 'first-of-type': function(nodes, formula, root) { 2492 return Selector.pseudos.nth(nodes, "1", root, false, true); 2493 }, 2494 'last-of-type': function(nodes, formula, root) { 2495 return Selector.pseudos.nth(nodes, "1", root, true, true); 2496 }, 2497 'only-of-type': function(nodes, formula, root) { 2498 var p = Selector.pseudos; 2499 return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); 2500 }, 2501 2502 // handles the an+b logic 2503 getIndices: function(a, b, total) { 2504 if (a == 0) return b > 0 ? [b] : []; 2505 return $R(1, total).inject([], function(memo, i) { 2506 if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); 2507 return memo; 2508 }); 2509 }, 2510 2511 // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type 2512 nth: function(nodes, formula, root, reverse, ofType) { 2513 if (nodes.length == 0) return []; 2514 if (formula == 'even') formula = '2n+0'; 2515 if (formula == 'odd') formula = '2n+1'; 2516 var h = Selector.handlers, results = [], indexed = [], m; 2517 h.mark(nodes); 2518 for (var i = 0, node; node = nodes[i]; i++) { 2519 if (!node.parentNode._counted) { 2520 h.index(node.parentNode, reverse, ofType); 2521 indexed.push(node.parentNode); 2522 } 2523 } 2524 if (formula.match(/^\d+$/)) { // just a number 2525 formula = Number(formula); 2526 for (var i = 0, node; node = nodes[i]; i++) 2527 if (node.nodeIndex == formula) results.push(node); 2528 } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b 2529 if (m[1] == "-") m[1] = -1; 2530 var a = m[1] ? Number(m[1]) : 1; 2531 var b = m[2] ? Number(m[2]) : 0; 2532 var indices = Selector.pseudos.getIndices(a, b, nodes.length); 2533 for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { 2534 for (var j = 0; j < l; j++) 2535 if (node.nodeIndex == indices[j]) results.push(node); 2536 } 2537 } 2538 h.unmark(nodes); 2539 h.unmark(indexed); 2540 return results; 2541 }, 2542 2543 'empty': function(nodes, value, root) { 2544 for (var i = 0, results = [], node; node = nodes[i]; i++) { 2545 // IE treats comments as element nodes 2546 if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue; 2547 results.push(node); 2548 } 2549 return results; 2550 }, 2551 2552 'not': function(nodes, selector, root) { 2553 var h = Selector.handlers, selectorType, m; 2554 var exclusions = new Selector(selector).findElements(root); 2555 h.mark(exclusions); 2556 for (var i = 0, results = [], node; node = nodes[i]; i++) 2557 if (!node._counted) results.push(node); 2558 h.unmark(exclusions); 2559 return results; 2560 }, 2561 2562 'enabled': function(nodes, value, root) { 2563 for (var i = 0, results = [], node; node = nodes[i]; i++) 2564 if (!node.disabled) results.push(node); 2565 return results; 2566 }, 2567 2568 'disabled': function(nodes, value, root) { 2569 for (var i = 0, results = [], node; node = nodes[i]; i++) 2570 if (node.disabled) results.push(node); 2571 return results; 2572 }, 2573 2574 'checked': function(nodes, value, root) { 2575 for (var i = 0, results = [], node; node = nodes[i]; i++) 2576 if (node.checked) results.push(node); 2577 return results; 2578 } 2579 }, 2580 2581 operators: { 2582 '=': function(nv, v) { return nv == v; }, 2583 '!=': function(nv, v) { return nv != v; }, 2584 '^=': function(nv, v) { return nv.startsWith(v); }, 2585 '$=': function(nv, v) { return nv.endsWith(v); }, 2586 '*=': function(nv, v) { return nv.include(v); }, 2587 '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, 2588 '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); } 2589 }, 2590 2591 matchElements: function(elements, expression) { 2592 var matches = new Selector(expression).findElements(), h = Selector.handlers; 2593 h.mark(matches); 2594 for (var i = 0, results = [], element; element = elements[i]; i++) 2595 if (element._counted) results.push(element); 2596 h.unmark(matches); 2597 return results; 2598 }, 2599 2600 findElement: function(elements, expression, index) { 2601 if (typeof expression == 'number') { 2602 index = expression; expression = false; 2603 } 2604 return Selector.matchElements(elements, expression || '*')[index || 0]; 2605 }, 2606 2607 findChildElements: function(element, expressions) { 2608 var exprs = expressions.join(','), expressions = []; 2609 exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { 2610 expressions.push(m[1].strip()); 2611 }); 2612 var results = [], h = Selector.handlers; 2613 for (var i = 0, l = expressions.length, selector; i < l; i++) { 2614 selector = new Selector(expressions[i].strip()); 2615 h.concat(results, selector.findElements(element)); 2616 } 2617 return (l > 1) ? h.unique(results) : results; 2618 } 2619 }); 2620 2621 function $$() { 2622 return Selector.findChildElements(document, $A(arguments)); 2623 } 2624 var Form = { 2625 reset: function(form) { 2626 $(form).reset(); 2627 return form; 2628 }, 2629 2630 serializeElements: function(elements, getHash) { 2631 var data = elements.inject({}, function(result, element) { 2632 if (!element.disabled && element.name) { 2633 var key = element.name, value = $(element).getValue(); 2634 if (value != null) { 2635 if (key in result) { 2636 if (result[key].constructor != Array) result[key] = [result[key]]; 2637 result[key].push(value); 2638 } 2639 else result[key] = value; 2640 } 2641 } 2642 return result; 2643 }); 2644 2645 return getHash ? data : Hash.toQueryString(data); 2646 } 2647 }; 2648 2649 Form.Methods = { 2650 serialize: function(form, getHash) { 2651 return Form.serializeElements(Form.getElements(form), getHash); 2652 }, 2653 2654 getElements: function(form) { 2655 return $A($(form).getElementsByTagName('*')).inject([], 2656 function(elements, child) { 2657 if (Form.Element.Serializers[child.tagName.toLowerCase()]) 2658 elements.push(Element.extend(child)); 2659 return elements; 2660 } 2661 ); 2662 }, 2663 2664 getInputs: function(form, typeName, name) { 2665 form = $(form); 2666 var inputs = form.getElementsByTagName('input'); 2667 2668 if (!typeName && !name) return $A(inputs).map(Element.extend); 2669 2670 for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { 2671 var input = inputs[i]; 2672 if ((typeName && input.type != typeName) || (name && input.name != name)) 2673 continue; 2674 matchingInputs.push(Element.extend(input)); 2675 } 2676 2677 return matchingInputs; 2678 }, 2679 2680 disable: function(form) { 2681 form = $(form); 2682 Form.getElements(form).invoke('disable'); 2683 return form; 2684 }, 2685 2686 enable: function(form) { 2687 form = $(form); 2688 Form.getElements(form).invoke('enable'); 2689 return form; 2690 }, 2691 2692 findFirstElement: function(form) { 2693 return $(form).getElements().find(function(element) { 2694 return element.type != 'hidden' && !element.disabled && 2695 ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); 2696 }); 2697 }, 2698 2699 focusFirstElement: function(form) { 2700 form = $(form); 2701 form.findFirstElement().activate(); 2702 return form; 2703 }, 2704 2705 request: function(form, options) { 2706 form = $(form), options = Object.clone(options || {}); 2707 2708 var params = options.parameters; 2709 options.parameters = form.serialize(true); 2710 2711 if (params) { 2712 if (typeof params == 'string') params = params.toQueryParams(); 2713 Object.extend(options.parameters, params); 2714 } 2715 2716 if (form.hasAttribute('method') && !options.method) 2717 options.method = form.method; 2718 2719 return new Ajax.Request(form.readAttribute('action'), options); 2720 } 2721 } 2722 2723 /*--------------------------------------------------------------------------*/ 2724 2725 Form.Element = { 2726 focus: function(element) { 2727 $(element).focus(); 2728 return element; 2729 }, 2730 2731 select: function(element) { 2732 $(element).select(); 2733 return element; 2734 } 2735 } 2736 2737 Form.Element.Methods = { 2738 serialize: function(element) { 2739 element = $(element); 2740 if (!element.disabled && element.name) { 2741 var value = element.getValue(); 2742 if (value != undefined) { 2743 var pair = {}; 2744 pair[element.name] = value; 2745 return Hash.toQueryString(pair); 2746 } 2747 } 2748 return ''; 2749 }, 2750 2751 getValue: function(element) { 2752 element = $(element); 2753 var method = element.tagName.toLowerCase(); 2754 return Form.Element.Serializers[method](element); 2755 }, 2756 2757 clear: function(element) { 2758 $(element).value = ''; 2759 return element; 2760 }, 2761 2762 present: function(element) { 2763 return $(element).value != ''; 2764 }, 2765 2766 activate: function(element) { 2767 element = $(element); 2768 try { 2769 element.focus(); 2770 if (element.select && (element.tagName.toLowerCase() != 'input' || 2771 !['button', 'reset', 'submit'].include(element.type))) 2772 element.select(); 2773 } catch (e) {} 2774 return element; 2775 }, 2776 2777 disable: function(element) { 2778 element = $(element); 2779 element.blur(); 2780 element.disabled = true; 2781 return element; 2782 }, 2783 2784 enable: function(element) { 2785 element = $(element); 2786 element.disabled = false; 2787 return element; 2788 } 2789 } 2790 2791 /*--------------------------------------------------------------------------*/ 2792 2793 var Field = Form.Element; 2794 var $F = Form.Element.Methods.getValue; 2795 2796 /*--------------------------------------------------------------------------*/ 2797 2798 Form.Element.Serializers = { 2799 input: function(element) { 2800 switch (element.type.toLowerCase()) { 2801 case 'checkbox': 2802 case 'radio': 2803 return Form.Element.Serializers.inputSelector(element); 2804 default: 2805 return Form.Element.Serializers.textarea(element); 2806 } 2807 }, 2808 2809 inputSelector: function(element) { 2810 return element.checked ? element.value : null; 2811 }, 2812 2813 textarea: function(element) { 2814 return element.value; 2815 }, 2816 2817 select: function(element) { 2818 return this[element.type == 'select-one' ? 2819 'selectOne' : 'selectMany'](element); 2820 }, 2821 2822 selectOne: function(element) { 2823 var index = element.selectedIndex; 2824 return index >= 0 ? this.optionValue(element.options[index]) : null; 2825 }, 2826 2827 selectMany: function(element) { 2828 var values, length = element.length; 2829 if (!length) return null; 2830 2831 for (var i = 0, values = []; i < length; i++) { 2832 var opt = element.options[i]; 2833 if (opt.selected) values.push(this.optionValue(opt)); 2834 } 2835 return values; 2836 }, 2837 2838 optionValue: function(opt) { 2839 // extend element because hasAttribute may not be native 2840 return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; 2841 } 2842 } 2843 2844 /*--------------------------------------------------------------------------*/ 2845 2846 Abstract.TimedObserver = function() {} 2847 Abstract.TimedObserver.prototype = { 2848 initialize: function(element, frequency, callback) { 2849 this.frequency = frequency; 2850 this.element = $(element); 2851 this.callback = callback; 2852 2853 this.lastValue = this.getValue(); 2854 this.registerCallback(); 2855 }, 2856 2857 registerCallback: function() { 2858 setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); 2859 }, 2860 2861 onTimerEvent: function() { 2862 var value = this.getValue(); 2863 var changed = ('string' == typeof this.lastValue && 'string' == typeof value 2864 ? this.lastValue != value : String(this.lastValue) != String(value)); 2865 if (changed) { 2866 this.callback(this.element, value); 2867 this.lastValue = value; 2868 } 2869 } 2870 } 2871 2872 Form.Element.Observer = Class.create(); 2873 Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { 2874 getValue: function() { 2875 return Form.Element.getValue(this.element); 2876 } 2877 }); 2878 2879 Form.Observer = Class.create(); 2880 Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { 2881 getValue: function() { 2882 return Form.serialize(this.element); 2883 } 2884 }); 2885 2886 /*--------------------------------------------------------------------------*/ 2887 2888 Abstract.EventObserver = function() {} 2889 Abstract.EventObserver.prototype = { 2890 initialize: function(element, callback) { 2891 this.element = $(element); 2892 this.callback = callback; 2893 2894 this.lastValue = this.getValue(); 2895 if (this.element.tagName.toLowerCase() == 'form') 2896 this.registerFormCallbacks(); 2897 else 2898 this.registerCallback(this.element); 2899 }, 2900 2901 onElementEvent: function() { 2902 var value = this.getValue(); 2903 if (this.lastValue != value) { 2904 this.callback(this.element, value); 2905 this.lastValue = value; 2906 } 2907 }, 2908 2909 registerFormCallbacks: function() { 2910 Form.getElements(this.element).each(this.registerCallback.bind(this)); 2911 }, 2912 2913 registerCallback: function(element) { 2914 if (element.type) { 2915 switch (element.type.toLowerCase()) { 2916 case 'checkbox': 2917 case 'radio': 2918 Event.observe(element, 'click', this.onElementEvent.bind(this)); 2919 break; 2920 default: 2921 Event.observe(element, 'change', this.onElementEvent.bind(this)); 2922 break; 2923 } 2924 } 2925 } 2926 } 2927 2928 Form.Element.EventObserver = Class.create(); 2929 Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { 2930 getValue: function() { 2931 return Form.Element.getValue(this.element); 2932 } 2933 }); 2934 2935 Form.EventObserver = Class.create(); 2936 Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { 2937 getValue: function() { 2938 return Form.serialize(this.element); 2939 } 2940 }); 2941 if (!window.Event) { 2942 var Event = new Object(); 2943 } 2944 2945 Object.extend(Event, { 2946 KEY_BACKSPACE: 8, 2947 KEY_TAB: 9, 2948 KEY_RETURN: 13, 2949 KEY_ESC: 27, 2950 KEY_LEFT: 37, 2951 KEY_UP: 38, 2952 KEY_RIGHT: 39, 2953 KEY_DOWN: 40, 2954 KEY_DELETE: 46, 2955 KEY_HOME: 36, 2956 KEY_END: 35, 2957 KEY_PAGEUP: 33, 2958 KEY_PAGEDOWN: 34, 2959 2960 element: function(event) { 2961 return $(event.target || event.srcElement); 2962 }, 2963 2964 isLeftClick: function(event) { 2965 return (((event.which) && (event.which == 1)) || 2966 ((event.button) && (event.button == 1))); 2967 }, 2968 2969 pointerX: function(event) { 2970 return event.pageX || (event.clientX + 2971 (document.documentElement.scrollLeft || document.body.scrollLeft)); 2972 }, 2973 2974 pointerY: function(event) { 2975 return event.pageY || (event.clientY + 2976 (document.documentElement.scrollTop || document.body.scrollTop)); 2977 }, 2978 2979 stop: function(event) { 2980 if (event.preventDefault) { 2981 event.preventDefault(); 2982 event.stopPropagation(); 2983 } else { 2984 event.returnValue = false; 2985 event.cancelBubble = true; 2986 } 2987 }, 2988 2989 // find the first node with the given tagName, starting from the 2990 // node the event was triggered on; traverses the DOM upwards 2991 findElement: function(event, tagName) { 2992 var element = Event.element(event); 2993 while (element.parentNode && (!element.tagName || 2994 (element.tagName.toUpperCase() != tagName.toUpperCase()))) 2995 element = element.parentNode; 2996 return element; 2997 }, 2998 2999 observers: false, 3000 3001 _observeAndCache: function(element, name, observer, useCapture) { 3002 if (!this.observers) this.observers = []; 3003 if (element.addEventListener) { 3004 this.observers.push([element, name, observer, useCapture]); 3005 element.addEventListener(name, observer, useCapture); 3006 } else if (element.attachEvent) { 3007 this.observers.push([element, name, observer, useCapture]); 3008 element.attachEvent('on' + name, observer); 3009 } 3010 }, 3011 3012 unloadCache: function() { 3013 if (!Event.observers) return; 3014 for (var i = 0, length = Event.observers.length; i < length; i++) { 3015 Event.stopObserving.apply(this, Event.observers[i]); 3016 Event.observers[i][0] = null; 3017 } 3018 Event.observers = false; 3019 }, 3020 3021 observe: function(element, name, observer, useCapture) { 3022 element = $(element); 3023 useCapture = useCapture || false; 3024 3025 if (name == 'keypress' && 3026 (Prototype.Browser.WebKit || element.attachEvent)) 3027 name = 'keydown'; 3028 3029 Event._observeAndCache(element, name, observer, useCapture); 3030 }, 3031 3032 stopObserving: function(element, name, observer, useCapture) { 3033 element = $(element); 3034 useCapture = useCapture || false; 3035 3036 if (name == 'keypress' && 3037 (Prototype.Browser.WebKit || element.attachEvent)) 3038 name = 'keydown'; 3039 3040 if (element.removeEventListener) { 3041 element.removeEventListener(name, observer, useCapture); 3042 } else if (element.detachEvent) { 3043 try { 3044 element.detachEvent('on' + name, observer); 3045 } catch (e) {} 3046 } 3047 } 3048 }); 3049 3050 /* prevent memory leaks in IE */ 3051 if (Prototype.Browser.IE) 3052 Event.observe(window, 'unload', Event.unloadCache, false); 3053 var Position = { 3054 // set to true if needed, warning: firefox performance problems 3055 // NOT neeeded for page scrolling, only if draggable contained in 3056 // scrollable elements 3057 includeScrollOffsets: false, 3058 3059 // must be called before calling withinIncludingScrolloffset, every time the 3060 // page is scrolled 3061 prepare: function() { 3062 this.deltaX = window.pageXOffset 3063 || document.documentElement.scrollLeft 3064 || document.body.scrollLeft 3065 || 0; 3066 this.deltaY = window.pageYOffset 3067 || document.documentElement.scrollTop 3068 || document.body.scrollTop 3069 || 0; 3070 }, 3071 3072 realOffset: function(element) { 3073 var valueT = 0, valueL = 0; 3074 do { 3075 valueT += element.scrollTop || 0; 3076 valueL += element.scrollLeft || 0; 3077 element = element.parentNode; 3078 } while (element); 3079 return [valueL, valueT]; 3080 }, 3081 3082 cumulativeOffset: function(element) { 3083 var valueT = 0, valueL = 0; 3084 do { 3085 valueT += element.offsetTop || 0; 3086 valueL += element.offsetLeft || 0; 3087 element = element.offsetParent; 3088 } while (element); 3089 return [valueL, valueT]; 3090 }, 3091 3092 positionedOffset: function(element) { 3093 var valueT = 0, valueL = 0; 3094 do { 3095 valueT += element.offsetTop || 0; 3096 valueL += element.offsetLeft || 0; 3097 element = element.offsetParent; 3098 if (element) { 3099 if(element.tagName=='BODY') break; 3100 var p = Element.getStyle(element, 'position'); 3101 if (p == 'relative' || p == 'absolute') break; 3102 } 3103 } while (element); 3104 return [valueL, valueT]; 3105 }, 3106 3107 offsetParent: function(element) { 3108 if (element.offsetParent) return element.offsetParent; 3109 if (element == document.body) return element; 3110 3111 while ((element = element.parentNode) && element != document.body) 3112 if (Element.getStyle(element, 'position') != 'static') 3113 return element; 3114 3115 return document.body; 3116 }, 3117 3118 // caches x/y coordinate pair to use with overlap 3119 within: function(element, x, y) { 3120 if (this.includeScrollOffsets) 3121 return this.withinIncludingScrolloffsets(element, x, y); 3122 this.xcomp = x; 3123 this.ycomp = y; 3124 this.offset = this.cumulativeOffset(element); 3125 3126 return (y >= this.offset[1] && 3127 y < this.offset[1] + element.offsetHeight && 3128 x >= this.offset[0] && 3129 x < this.offset[0] + element.offsetWidth); 3130 }, 3131 3132 withinIncludingScrolloffsets: function(element, x, y) { 3133 var offsetcache = this.realOffset(element); 3134 3135 this.xcomp = x + offsetcache[0] - this.deltaX; 3136 this.ycomp = y + offsetcache[1] - this.deltaY; 3137 this.offset = this.cumulativeOffset(element); 3138 3139 return (this.ycomp >= this.offset[1] && 3140 this.ycomp < this.offset[1] + element.offsetHeight && 3141 this.xcomp >= this.offset[0] && 3142 this.xcomp < this.offset[0] + element.offsetWidth); 3143 }, 3144 3145 // within must be called directly before 3146 overlap: function(mode, element) { 3147 if (!mode) return 0; 3148 if (mode == 'vertical') 3149 return ((this.offset[1] + element.offsetHeight) - this.ycomp) / 3150 element.offsetHeight; 3151 if (mode == 'horizontal') 3152 return ((this.offset[0] + element.offsetWidth) - this.xcomp) / 3153 element.offsetWidth; 3154 }, 3155 3156 page: function(forElement) { 3157 var valueT = 0, valueL = 0; 3158 3159 var element = forElement; 3160 do { 3161 valueT += element.offsetTop || 0; 3162 valueL += element.offsetLeft || 0; 3163 3164 // Safari fix 3165 if (element.offsetParent == document.body) 3166 if (Element.getStyle(element,'position')=='absolute') break; 3167 3168 } while (element = element.offsetParent); 3169 3170 element = forElement; 3171 do { 3172 if (!window.opera || element.tagName=='BODY') { 3173 valueT -= element.scrollTop || 0; 3174 valueL -= element.scrollLeft || 0; 3175 } 3176 } while (element = element.parentNode); 3177 3178 return [valueL, valueT]; 3179 }, 3180 3181 clone: function(source, target) { 3182 var options = Object.extend({ 3183 setLeft: true, 3184 setTop: true, 3185 setWidth: true, 3186 setHeight: true, 3187 offsetTop: 0, 3188 offsetLeft: 0 3189 }, arguments[2] || {}) 3190 3191 // find page position of source 3192 source = $(source); 3193 var p = Position.page(source); 3194 3195 // find coordinate system to use 3196 target = $(target); 3197 var delta = [0, 0]; 3198 var parent = null; 3199 // delta [0,0] will do fine with position: fixed elements, 3200 // position:absolute needs offsetParent deltas 3201 if (Element.getStyle(target,'position') == 'absolute') { 3202 parent = Position.offsetParent(target); 3203 delta = Position.page(parent); 3204 } 3205 3206 // correct by body offsets (fixes Safari) 3207 if (parent == document.body) { 3208 delta[0] -= document.body.offsetLeft; 3209 delta[1] -= document.body.offsetTop; 3210 } 3211 3212 // set position 3213 if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; 3214 if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; 3215 if(options.setWidth) target.style.width = source.offsetWidth + 'px'; 3216 if(options.setHeight) target.style.height = source.offsetHeight + 'px'; 3217 }, 3218 3219 absolutize: function(element) { 3220 element = $(element); 3221 if (element.style.position == 'absolute') return; 3222 Position.prepare(); 3223 3224 var offsets = Position.positionedOffset(element); 3225 var top = offsets[1]; 3226 var left = offsets[0]; 3227 var width = element.clientWidth; 3228 var height = element.clientHeight; 3229 3230 element._originalLeft = left - parseFloat(element.style.left || 0); 3231 element._originalTop = top - parseFloat(element.style.top || 0); 3232 element._originalWidth = element.style.width; 3233 element._originalHeight = element.style.height; 3234 3235 element.style.position = 'absolute'; 3236 element.style.top = top + 'px'; 3237 element.style.left = left + 'px'; 3238 element.style.width = width + 'px'; 3239 element.style.height = height + 'px'; 3240 }, 3241 3242 relativize: function(element) { 3243 element = $(element); 3244 if (element.style.position == 'relative') return; 3245 Position.prepare(); 3246 3247 element.style.position = 'relative'; 3248 var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); 3249 var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); 3250 3251 element.style.top = top + 'px'; 3252 element.style.left = left + 'px'; 3253 element.style.height = element._originalHeight; 3254 element.style.width = element._originalWidth; 3255 } 3256 } 3257 3258 // Safari returns margins on body which is incorrect if the child is absolutely 3259 // positioned. For performance reasons, redefine Position.cumulativeOffset for 3260 // KHTML/WebKit only. 3261 if (Prototype.Browser.WebKit) { 3262 Position.cumulativeOffset = function(element) { 3263 var valueT = 0, valueL = 0; 3264 do { 3265 valueT += element.offsetTop || 0; 3266 valueL += element.offsetLeft || 0; 3267 if (element.offsetParent == document.body) 3268 if (Element.getStyle(element, 'position') == 'absolute') break; 3269 3270 element = element.offsetParent; 3271 } while (element); 3272 3273 return [valueL, valueT]; 3274 } 3275 } 3276 3277 Element.addMethods();
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Thu Nov 29 09:42:17 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |