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