PHP Cross Reference of WordPress Subversion HEAD |
| [ Index ] [ Classes ] [ Functions ] [ Variables ] [ Constants ] |
[Summary view] [Print] [Text view]
1 /* Prototype JavaScript framework, version 1.5.1.1 2 * (c) 2005-2007 Sam Stephenson 3 * 4 * Prototype is freely distributable under the terms of an MIT-style license. 5 * For details, see the Prototype web site: http://www.prototypejs.org/ 6 * 7 /*--------------------------------------------------------------------------*/ 8 9 var Prototype = { 10 Version: '1.5.1.1', 11 12 Browser: { 13 IE: !!(window.attachEvent && !window.opera), 14 Opera: !!window.opera, 15 WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1, 16 Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1 17 }, 18 19 BrowserFeatures: { 20 XPath: !!document.evaluate, 21 ElementExtensions: !!window.HTMLElement, 22 SpecificElementExtensions: 23 (document.createElement('div').__proto__ !== 24 document.createElement('form').__proto__) 25 }, 26 27 ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>', 28 JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, 29 30 emptyFunction: function() { }, 31 K: function(x) { return x } 32 } 33 34 var Class = { 35 create: function() { 36 return function() { 37 this.initialize.apply(this, arguments); 38 } 39 } 40 } 41 42 var Abstract = new Object(); 43 44 Object.extend = function(destination, source) { 45 for (var property in source) { 46 destination[property] = source[property]; 47 } 48 return destination; 49 } 50 51 Object.extend(Object, { 52 inspect: function(object) { 53 try { 54 if (object === undefined) return 'undefined'; 55 if (object === null) return 'null'; 56 return object.inspect ? object.inspect() : object.toString(); 57 } catch (e) { 58 if (e instanceof RangeError) return '...'; 59 throw e; 60 } 61 }, 62 63 toJSON: function(object) { 64 var type = typeof object; 65 switch(type) { 66 case 'undefined': 67 case 'function': 68 case 'unknown': return; 69 case 'boolean': return object.toString(); 70 } 71 if (object === null) return 'null'; 72 if (object.toJSON) return object.toJSON(); 73 if (object.ownerDocument === document) return; 74 var results = []; 75 for (var property in object) { 76 var value = Object.toJSON(object[property]); 77 if (value !== undefined) 78 results.push(property.toJSON() + ': ' + value); 79 } 80 return '{' + results.join(', ') + '}'; 81 }, 82 83 keys: function(object) { 84 var keys = []; 85 for (var property in object) 86 keys.push(property); 87 return keys; 88 }, 89 90 values: function(object) { 91 var values = []; 92 for (var property in object) 93 values.push(object[property]); 94 return values; 95 }, 96 97 clone: function(object) { 98 return Object.extend({}, object); 99 } 100 }); 101 102 Function.prototype.bind = function() { 103 var __method = this, args = $A(arguments), object = args.shift(); 104 return function() { 105 return __method.apply(object, args.concat($A(arguments))); 106 } 107 } 108 109 Function.prototype.bindAsEventListener = function(object) { 110 var __method = this, args = $A(arguments), object = args.shift(); 111 return function(event) { 112 return __method.apply(object, [event || window.event].concat(args)); 113 } 114 } 115 116 Object.extend(Number.prototype, { 117 toColorPart: function() { 118 return this.toPaddedString(2, 16); 119 }, 120 121 succ: function() { 122 return this + 1; 123 }, 124 125 times: function(iterator) { 126 $R(0, this, true).each(iterator); 127 return this; 128 }, 129 130 toPaddedString: function(length, radix) { 131 var string = this.toString(radix || 10); 132 return '0'.times(length - string.length) + string; 133 }, 134 135 toJSON: function() { 136 return isFinite(this) ? this.toString() : 'null'; 137 } 138 }); 139 140 Date.prototype.toJSON = function() { 141 return '"' + this.getFullYear() + '-' + 142 (this.getMonth() + 1).toPaddedString(2) + '-' + 143 this.getDate().toPaddedString(2) + 'T' + 144 this.getHours().toPaddedString(2) + ':' + 145 this.getMinutes().toPaddedString(2) + ':' + 146 this.getSeconds().toPaddedString(2) + '"'; 147 }; 148 149 var Try = { 150 these: function() { 151 var returnValue; 152 153 for (var i = 0, length = arguments.length; i < length; i++) { 154 var lambda = arguments[i]; 155 try { 156 returnValue = lambda(); 157 break; 158 } catch (e) {} 159 } 160 161 return returnValue; 162 } 163 } 164 165 /*--------------------------------------------------------------------------*/ 166 167 var PeriodicalExecuter = Class.create(); 168 PeriodicalExecuter.prototype = { 169 initialize: function(callback, frequency) { 170 this.callback = callback; 171 this.frequency = frequency; 172 this.currentlyExecuting = false; 173 174 this.registerCallback(); 175 }, 176 177 registerCallback: function() { 178 this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); 179 }, 180 181 stop: function() { 182 if (!this.timer) return; 183 clearInterval(this.timer); 184 this.timer = null; 185 }, 186 187 onTimerEvent: function() { 188 if (!this.currentlyExecuting) { 189 try { 190 this.currentlyExecuting = true; 191 this.callback(this); 192 } finally { 193 this.currentlyExecuting = false; 194 } 195 } 196 } 197 } 198 Object.extend(String, { 199 interpret: function(value) { 200 return value == null ? '' : String(value); 201 }, 202 specialChar: { 203 '\b': '\\b', 204 '\t': '\\t', 205 '\n': '\\n', 206 '\f': '\\f', 207 '\r': '\\r', 208 '\\': '\\\\' 209 } 210 }); 211 212 Object.extend(String.prototype, { 213 gsub: function(pattern, replacement) { 214 var result = '', source = this, match; 215 replacement = arguments.callee.prepareReplacement(replacement); 216 217 while (source.length > 0) { 218 if (match = source.match(pattern)) { 219 result += source.slice(0, match.index); 220 result += String.interpret(replacement(match)); 221 source = source.slice(match.index + match[0].length); 222 } else { 223 result += source, source = ''; 224 } 225 } 226 return result; 227 }, 228 229 sub: function(pattern, replacement, count) { 230 replacement = this.gsub.prepareReplacement(replacement); 231 count = count === undefined ? 1 : count; 232 233 return this.gsub(pattern, function(match) { 234 if (--count < 0) return match[0]; 235 return replacement(match); 236 }); 237 }, 238 239 scan: function(pattern, iterator) { 240 this.gsub(pattern, iterator); 241 return this; 242 }, 243 244 truncate: function(length, truncation) { 245 length = length || 30; 246 truncation = truncation === undefined ? '...' : truncation; 247 return this.length > length ? 248 this.slice(0, length - truncation.length) + truncation : this; 249 }, 250 251 strip: function() { 252 return this.replace(/^\s+/, '').replace(/\s+$/, ''); 253 }, 254 255 stripTags: function() { 256 return this.replace(/<\/?[^>]+>/gi, ''); 257 }, 258 259 stripScripts: function() { 260 return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); 261 }, 262 263 extractScripts: function() { 264 var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); 265 var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); 266 return (this.match(matchAll) || []).map(function(scriptTag) { 267 return (scriptTag.match(matchOne) || ['', ''])[1]; 268 }); 269 }, 270 271 evalScripts: function() { 272 return this.extractScripts().map(function(script) { return eval(script) }); 273 }, 274 275 escapeHTML: function() { 276 var self = arguments.callee; 277 self.text.data = this; 278 return self.div.innerHTML; 279 }, 280 281 unescapeHTML: function() { 282 var div = document.createElement('div'); 283 div.innerHTML = this.stripTags(); 284 return div.childNodes[0] ? (div.childNodes.length > 1 ? 285 $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) : 286 div.childNodes[0].nodeValue) : ''; 287 }, 288 289 toQueryParams: function(separator) { 290 var match = this.strip().match(/([^?#]*)(#.*)?$/); 291 if (!match) return {}; 292 293 return match[1].split(separator || '&').inject({}, function(hash, pair) { 294 if ((pair = pair.split('='))[0]) { 295 var key = decodeURIComponent(pair.shift()); 296 var value = pair.length > 1 ? pair.join('=') : pair[0]; 297 if (value != undefined) value = decodeURIComponent(value); 298 299 if (key in hash) { 300 if (hash[key].constructor != Array) hash[key] = [hash[key]]; 301 hash[key].push(value); 302 } 303 else hash[key] = value; 304 } 305 return hash; 306 }); 307 }, 308 309 toArray: function() { 310 return this.split(''); 311 }, 312 313 succ: function() { 314 return this.slice(0, this.length - 1) + 315 String.fromCharCode(this.charCodeAt(this.length - 1) + 1); 316 }, 317 318 times: function(count) { 319 var result = ''; 320 for (var i = 0; i < count; i++) result += this; 321 return result; 322 }, 323 324 camelize: function() { 325 var parts = this.split('-'), len = parts.length; 326 if (len == 1) return parts[0]; 327 328 var camelized = this.charAt(0) == '-' 329 ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) 330 : parts[0]; 331 332 for (var i = 1; i < len; i++) 333 camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); 334 335 return camelized; 336 }, 337 338 capitalize: function() { 339 return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); 340 }, 341 342 underscore: function() { 343 return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); 344 }, 345 346 dasherize: function() { 347 return this.gsub(/_/,'-'); 348 }, 349 350 inspect: function(useDoubleQuotes) { 351 var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) { 352 var character = String.specialChar[match[0]]; 353 return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16); 354 }); 355 if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; 356 return "'" + escapedString.replace(/'/g, '\\\'') + "'"; 357 }, 358 359 toJSON: function() { 360 return this.inspect(true); 361 }, 362 363 unfilterJSON: function(filter) { 364 return this.sub(filter || Prototype.JSONFilter, '#{1}'); 365 }, 366 367 isJSON: function() { 368 var str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); 369 return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); 370 }, 371 372 evalJSON: function(sanitize) { 373 var json = this.unfilterJSON(); 374 try { 375 if (!sanitize || json.isJSON()) return eval('(' + json + ')'); 376 } catch (e) { } 377 throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); 378 }, 379 380 include: function(pattern) { 381 return this.indexOf(pattern) > -1; 382 }, 383 384 startsWith: function(pattern) { 385 return this.indexOf(pattern) === 0; 386 }, 387 388 endsWith: function(pattern) { 389 var d = this.length - pattern.length; 390 return d >= 0 && this.lastIndexOf(pattern) === d; 391 }, 392 393 empty: function() { 394 return this == ''; 395 }, 396 397 blank: function() { 398 return /^\s*$/.test(this); 399 } 400 }); 401 402 if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, { 403 escapeHTML: function() { 404 return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); 405 }, 406 unescapeHTML: function() { 407 return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); 408 } 409 }); 410 411 String.prototype.gsub.prepareReplacement = function(replacement) { 412 if (typeof replacement == 'function') return replacement; 413 var template = new Template(replacement); 414 return function(match) { return template.evaluate(match) }; 415 } 416 417 String.prototype.parseQuery = String.prototype.toQueryParams; 418 419 Object.extend(String.prototype.escapeHTML, { 420 div: document.createElement('div'), 421 text: document.createTextNode('') 422 }); 423 424 with (String.prototype.escapeHTML) div.appendChild(text); 425 426 var Template = Class.create(); 427 Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; 428 Template.prototype = { 429 initialize: function(template, pattern) { 430 this.template = template.toString(); 431 this.pattern = pattern || Template.Pattern; 432 }, 433 434 evaluate: function(object) { 435 return this.template.gsub(this.pattern, function(match) { 436 var before = match[1]; 437 if (before == '\\') return match[2]; 438 return before + String.interpret(object[match[3]]); 439 }); 440 } 441 } 442 443 var $break = {}, $continue = new Error('"throw $continue" is deprecated, use "return" instead'); 444 445 var Enumerable = { 446 each: function(iterator) { 447 var index = 0; 448 try { 449 this._each(function(value) { 450 iterator(value, index++); 451 }); 452 } catch (e) { 453 if (e != $break) throw e; 454 } 455 return this; 456 }, 457 458 eachSlice: function(number, iterator) { 459 var index = -number, slices = [], array = this.toArray(); 460 while ((index += number) < array.length) 461 slices.push(array.slice(index, index+number)); 462 return slices.map(iterator); 463 }, 464 465 all: function(iterator) { 466 var result = true; 467 this.each(function(value, index) { 468 result = result && !!(iterator || Prototype.K)(value, index); 469 if (!result) throw $break; 470 }); 471 return result; 472 }, 473 474 any: function(iterator) { 475 var result = false; 476 this.each(function(value, index) { 477 if (result = !!(iterator || Prototype.K)(value, index)) 478 throw $break; 479 }); 480 return result; 481 }, 482 483 collect: function(iterator) { 484 var results = []; 485 this.each(function(value, index) { 486 results.push((iterator || Prototype.K)(value, index)); 487 }); 488 return results; 489 }, 490 491 detect: function(iterator) { 492 var result; 493 this.each(function(value, index) { 494 if (iterator(value, index)) { 495 result = value; 496 throw $break; 497 } 498 }); 499 return result; 500 }, 501 502 findAll: function(iterator) { 503 var results = []; 504 this.each(function(value, index) { 505 if (iterator(value, index)) 506 results.push(value); 507 }); 508 return results; 509 }, 510 511 grep: function(pattern, iterator) { 512 var results = []; 513 this.each(function(value, index) { 514 var stringValue = value.toString(); 515 if (stringValue.match(pattern)) 516 results.push((iterator || Prototype.K)(value, index)); 517 }) 518 return results; 519 }, 520 521 include: function(object) { 522 var found = false; 523 this.each(function(value) { 524 if (value == object) { 525 found = true; 526 throw $break; 527 } 528 }); 529 return found; 530 }, 531 532 inGroupsOf: function(number, fillWith) { 533 fillWith = fillWith === undefined ? null : fillWith; 534 return this.eachSlice(number, function(slice) { 535 while(slice.length < number) slice.push(fillWith); 536 return slice; 537 }); 538 }, 539 540 inject: function(memo, iterator) { 541 this.each(function(value, index) { 542 memo = iterator(memo, value, index); 543 }); 544 return memo; 545 }, 546 547 invoke: function(method) { 548 var args = $A(arguments).slice(1); 549 return this.map(function(value) { 550 return value[method].apply(value, args); 551 }); 552 }, 553 554 max: function(iterator) { 555 var result; 556 this.each(function(value, index) { 557 value = (iterator || Prototype.K)(value, index); 558 if (result == undefined || value >= result) 559 result = value; 560 }); 561 return result; 562 }, 563 564 min: function(iterator) { 565 var result; 566 this.each(function(value, index) { 567 value = (iterator || Prototype.K)(value, index); 568 if (result == undefined || value < result) 569 result = value; 570 }); 571 return result; 572 }, 573 574 partition: function(iterator) { 575 var trues = [], falses = []; 576 this.each(function(value, index) { 577 ((iterator || Prototype.K)(value, index) ? 578 trues : falses).push(value); 579 }); 580 return [trues, falses]; 581 }, 582 583 pluck: function(property) { 584 var results = []; 585 this.each(function(value, index) { 586 results.push(value[property]); 587 }); 588 return results; 589 }, 590 591 reject: function(iterator) { 592 var results = []; 593 this.each(function(value, index) { 594 if (!iterator(value, index)) 595 results.push(value); 596 }); 597 return results; 598 }, 599 600 sortBy: function(iterator) { 601 return this.map(function(value, index) { 602 return {value: value, criteria: iterator(value, index)}; 603 }).sort(function(left, right) { 604 var a = left.criteria, b = right.criteria; 605 return a < b ? -1 : a > b ? 1 : 0; 606 }).pluck('value'); 607 }, 608 609 toArray: function() { 610 return this.map(); 611 }, 612 613 zip: function() { 614 var iterator = Prototype.K, args = $A(arguments); 615 if (typeof args.last() == 'function') 616 iterator = args.pop(); 617 618 var collections = [this].concat(args).map($A); 619 return this.map(function(value, index) { 620 return iterator(collections.pluck(index)); 621 }); 622 }, 623 624 size: function() { 625 return this.toArray().length; 626 }, 627 628 inspect: function() { 629 return '#<Enumerable:' + this.toArray().inspect() + '>'; 630 } 631 } 632 633 Object.extend(Enumerable, { 634 map: Enumerable.collect, 635 find: Enumerable.detect, 636 select: Enumerable.findAll, 637 member: Enumerable.include, 638 entries: Enumerable.toArray 639 }); 640 var $A = Array.from = function(iterable) { 641 if (!iterable) return []; 642 if (iterable.toArray) { 643 return iterable.toArray(); 644 } else { 645 var results = []; 646 for (var i = 0, length = iterable.length; i < length; i++) 647 results.push(iterable[i]); 648 return results; 649 } 650 } 651 652 if (Prototype.Browser.WebKit) { 653 $A = Array.from = function(iterable) { 654 if (!iterable) return []; 655 if (!(typeof iterable == 'function' && iterable == '[object NodeList]') && 656 iterable.toArray) { 657 return iterable.toArray(); 658 } else { 659 var results = []; 660 for (var i = 0, length = iterable.length; i < length; i++) 661 results.push(iterable[i]); 662 return results; 663 } 664 } 665 } 666 667 Object.extend(Array.prototype, Enumerable); 668 669 if (!Array.prototype._reverse) 670 Array.prototype._reverse = Array.prototype.reverse; 671 672 Object.extend(Array.prototype, { 673 _each: function(iterator) { 674 for (var i = 0, length = this.length; i < length; i++) 675 iterator(this[i]); 676 }, 677 678 clear: function() { 679 this.length = 0; 680 return this; 681 }, 682 683 first: function() { 684 return this[0]; 685 }, 686 687 last: function() { 688 return this[this.length - 1]; 689 }, 690 691 compact: function() { 692 return this.select(function(value) { 693 return value != null; 694 }); 695 }, 696 697 flatten: function() { 698 return this.inject([], function(array, value) { 699 return array.concat(value && value.constructor == Array ? 700 value.flatten() : [value]); 701 }); 702 }, 703 704 without: function() { 705 var values = $A(arguments); 706 return this.select(function(value) { 707 return !values.include(value); 708 }); 709 }, 710 711 indexOf: function(object) { 712 for (var i = 0, length = this.length; i < length; i++) 713 if (this[i] == object) return i; 714 return -1; 715 }, 716 717 reverse: function(inline) { 718 return (inline !== false ? this : this.toArray())._reverse(); 719 }, 720 721 reduce: function() { 722 return this.length > 1 ? this : this[0]; 723 }, 724 725 uniq: function(sorted) { 726 return this.inject([], function(array, value, index) { 727 if (0 == index || (sorted ? array.last() != value : !array.include(value))) 728 array.push(value); 729 return array; 730 }); 731 }, 732 733 clone: function() { 734 return [].concat(this); 735 }, 736 737 size: function() { 738 return this.length; 739 }, 740 741 inspect: function() { 742 return '[' + this.map(Object.inspect).join(', ') + ']'; 743 }, 744 745 toJSON: function() { 746 var results = []; 747 this.each(function(object) { 748 var value = Object.toJSON(object); 749 if (value !== undefined) results.push(value); 750 }); 751 return '[' + results.join(', ') + ']'; 752 } 753 }); 754 755 Array.prototype.toArray = Array.prototype.clone; 756 757 function $w(string) { 758 string = string.strip(); 759 return string ? string.split(/\s+/) : []; 760 } 761 762 if (Prototype.Browser.Opera){ 763 Array.prototype.concat = function() { 764 var array = []; 765 for (var i = 0, length = this.length; i < length; i++) array.push(this[i]); 766 for (var i = 0, length = arguments.length; i < length; i++) { 767 if (arguments[i].constructor == Array) { 768 for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++) 769 array.push(arguments[i][j]); 770 } else { 771 array.push(arguments[i]); 772 } 773 } 774 return array; 775 } 776 } 777 var Hash = function(object) { 778 if (object instanceof Hash) this.merge(object); 779 else Object.extend(this, object || {}); 780 }; 781 782 Object.extend(Hash, { 783 toQueryString: function(obj) { 784 var parts = []; 785 parts.add = arguments.callee.addPair; 786 787 this.prototype._each.call(obj, function(pair) { 788 if (!pair.key) return; 789 var value = pair.value; 790 791 if (value && typeof value == 'object') { 792 if (value.constructor == Array) value.each(function(value) { 793 parts.add(pair.key, value); 794 }); 795 return; 796 } 797 parts.add(pair.key, value); 798 }); 799 800 return parts.join('&'); 801 }, 802 803 toJSON: function(object) { 804 var results = []; 805 this.prototype._each.call(object, function(pair) { 806 var value = Object.toJSON(pair.value); 807 if (value !== undefined) results.push(pair.key.toJSON() + ': ' + value); 808 }); 809 return '{' + results.join(', ') + '}'; 810 } 811 }); 812 813 Hash.toQueryString.addPair = function(key, value, prefix) { 814 key = encodeURIComponent(key); 815 if (value === undefined) this.push(key); 816 else this.push(key + '=' + (value == null ? '' : encodeURIComponent(value))); 817 } 818 819 Object.extend(Hash.prototype, Enumerable); 820 Object.extend(Hash.prototype, { 821 _each: function(iterator) { 822 for (var key in this) { 823 var value = this[key]; 824 if (value && value == Hash.prototype[key]) continue; 825 826 var pair = [key, value]; 827 pair.key = key; 828 pair.value = value; 829 iterator(pair); 830 } 831 }, 832 833 keys: function() { 834 return this.pluck('key'); 835 }, 836 837 values: function() { 838 return this.pluck('value'); 839 }, 840 841 merge: function(hash) { 842 return $H(hash).inject(this, function(mergedHash, pair) { 843 mergedHash[pair.key] = pair.value; 844 return mergedHash; 845 }); 846 }, 847 848 remove: function() { 849 var result; 850 for(var i = 0, length = arguments.length; i < length; i++) { 851 var value = this[arguments[i]]; 852 if (value !== undefined){ 853 if (result === undefined) result = value; 854 else { 855 if (result.constructor != Array) result = [result]; 856 result.push(value) 857 } 858 } 859 delete this[arguments[i]]; 860 } 861 return result; 862 }, 863 864 toQueryString: function() { 865 return Hash.toQueryString(this); 866 }, 867 868 inspect: function() { 869 return '#<Hash:{' + this.map(function(pair) { 870 return pair.map(Object.inspect).join(': '); 871 }).join(', ') + '}>'; 872 }, 873 874 toJSON: function() { 875 return Hash.toJSON(this); 876 } 877 }); 878 879 function $H(object) { 880 if (object instanceof Hash) return object; 881 return new Hash(object); 882 }; 883 884 // Safari iterates over shadowed properties 885 if (function() { 886 var i = 0, Test = function(value) { this.key = value }; 887 Test.prototype.key = 'foo'; 888 for (var property in new Test('bar')) i++; 889 return i > 1; 890 }()) Hash.prototype._each = function(iterator) { 891 var cache = []; 892 for (var key in this) { 893 var value = this[key]; 894 if ((value && value == Hash.prototype[key]) || cache.include(key)) continue; 895 cache.push(key); 896 var pair = [key, value]; 897 pair.key = key; 898 pair.value = value; 899 iterator(pair); 900 } 901 }; 902 ObjectRange = Class.create(); 903 Object.extend(ObjectRange.prototype, Enumerable); 904 Object.extend(ObjectRange.prototype, { 905 initialize: function(start, end, exclusive) { 906 this.start = start; 907 this.end = end; 908 this.exclusive = exclusive; 909 }, 910 911 _each: function(iterator) { 912 var value = this.start; 913 while (this.include(value)) { 914 iterator(value); 915 value = value.succ(); 916 } 917 }, 918 919 include: function(value) { 920 if (value < this.start) 921 return false; 922 if (this.exclusive) 923 return value < this.end; 924 return value <= this.end; 925 } 926 }); 927 928 var $R = function(start, end, exclusive) { 929 return new ObjectRange(start, end, exclusive); 930 } 931 932 var Ajax = { 933 getTransport: function() { 934 return Try.these( 935 function() {return new XMLHttpRequest()}, 936 function() {return new ActiveXObject('Msxml2.XMLHTTP')}, 937 function() {return new ActiveXObject('Microsoft.XMLHTTP')} 938 ) || false; 939 }, 940 941 activeRequestCount: 0 942 } 943 944 Ajax.Responders = { 945 responders: [], 946 947 _each: function(iterator) { 948 this.responders._each(iterator); 949 }, 950 951 register: function(responder) { 952 if (!this.include(responder)) 953 this.responders.push(responder); 954 }, 955 956 unregister: function(responder) { 957 this.responders = this.responders.without(responder); 958 }, 959 960 dispatch: function(callback, request, transport, json) { 961 this.each(function(responder) { 962 if (typeof responder[callback] == 'function') { 963 try { 964 responder[callback].apply(responder, [request, transport, json]); 965 } catch (e) {} 966 } 967 }); 968 } 969 }; 970 971 Object.extend(Ajax.Responders, Enumerable); 972 973 Ajax.Responders.register({ 974 onCreate: function() { 975 Ajax.activeRequestCount++; 976 }, 977 onComplete: function() { 978 Ajax.activeRequestCount--; 979 } 980 }); 981 982 Ajax.Base = function() {}; 983 Ajax.Base.prototype = { 984 setOptions: function(options) { 985 this.options = { 986 method: 'post', 987 asynchronous: true, 988 contentType: 'application/x-www-form-urlencoded', 989 encoding: 'UTF-8', 990 parameters: '' 991 } 992 Object.extend(this.options, options || {}); 993 994 this.options.method = this.options.method.toLowerCase(); 995 if (typeof this.options.parameters == 'string') 996 this.options.parameters = this.options.parameters.toQueryParams(); 997 } 998 } 999 1000 Ajax.Request = Class.create(); 1001 Ajax.Request.Events = 1002 ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; 1003 1004 Ajax.Request.prototype = Object.extend(new Ajax.Base(), { 1005 _complete: false, 1006 1007 initialize: function(url, options) { 1008 this.transport = Ajax.getTransport(); 1009 this.setOptions(options); 1010 this.request(url); 1011 }, 1012 1013 request: function(url) { 1014 this.url = url; 1015 this.method = this.options.method; 1016 var params = Object.clone(this.options.parameters); 1017 1018 if (!['get', 'post'].include(this.method)) { 1019 // simulate other verbs over post 1020 params['_method'] = this.method; 1021 this.method = 'post'; 1022 } 1023 1024 this.parameters = params; 1025 1026 if (params = Hash.toQueryString(params)) { 1027 // when GET, append parameters to URL 1028 if (this.method == 'get') 1029 this.url += (this.url.include('?') ? '&' : '?') + params; 1030 else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) 1031 params += '&_='; 1032 } 1033 1034 try { 1035 if (this.options.onCreate) this.options.onCreate(this.transport); 1036 Ajax.Responders.dispatch('onCreate', this, this.transport); 1037 1038 this.transport.open(this.method.toUpperCase(), this.url, 1039 this.options.asynchronous); 1040 1041 if (this.options.asynchronous) 1042 setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10); 1043 1044 this.transport.onreadystatechange = this.onStateChange.bind(this); 1045 this.setRequestHeaders(); 1046 1047 this.body = this.method == 'post' ? (this.options.postBody || params) : null; 1048 this.transport.send(this.body); 1049 1050 /* Force Firefox to handle ready state 4 for synchronous requests */ 1051 if (!this.options.asynchronous && this.transport.overrideMimeType) 1052 this.onStateChange(); 1053 1054 } 1055 catch (e) { 1056 this.dispatchException(e); 1057 } 1058 }, 1059 1060 onStateChange: function() { 1061 var readyState = this.transport.readyState; 1062 if (readyState > 1 && !((readyState == 4) && this._complete)) 1063 this.respondToReadyState(this.transport.readyState); 1064 }, 1065 1066 setRequestHeaders: function() { 1067 var headers = { 1068 'X-Requested-With': 'XMLHttpRequest', 1069 'X-Prototype-Version': Prototype.Version, 1070 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' 1071 }; 1072 1073 if (this.method == 'post') { 1074 headers['Content-type'] = this.options.contentType + 1075 (this.options.encoding ? '; charset=' + this.options.encoding : ''); 1076 1077 /* Force "Connection: close" for older Mozilla browsers to work 1078 * around a bug where XMLHttpRequest sends an incorrect 1079 * Content-length header. See Mozilla Bugzilla #246651. 1080 */ 1081 if (this.transport.overrideMimeType && 1082 (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) 1083 headers['Connection'] = 'close'; 1084 } 1085 1086 // user-defined headers 1087 if (typeof this.options.requestHeaders == 'object') { 1088 var extras = this.options.requestHeaders; 1089 1090 if (typeof extras.push == 'function') 1091 for (var i = 0, length = extras.length; i < length; i += 2) 1092 headers[extras[i]] = extras[i+1]; 1093 else 1094 $H(extras).each(function(pair) { headers[pair.key] = pair.value }); 1095 } 1096 1097 for (var name in headers) 1098 this.transport.setRequestHeader(name, headers[name]); 1099 }, 1100 1101 success: function() { 1102 return !this.transport.status 1103 || (this.transport.status >= 200 && this.transport.status < 300); 1104 }, 1105 1106 respondToReadyState: function(readyState) { 1107 var state = Ajax.Request.Events[readyState]; 1108 var transport = this.transport, json = this.evalJSON(); 1109 1110 if (state == 'Complete') { 1111 try { 1112 this._complete = true; 1113 (this.options['on' + this.transport.status] 1114 || this.options['on' + (this.success() ? 'Success' : 'Failure')] 1115 || Prototype.emptyFunction)(transport, json); 1116 } catch (e) { 1117 this.dispatchException(e); 1118 } 1119 1120 var contentType = this.getHeader('Content-type'); 1121 if (contentType && contentType.strip(). 1122 match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i)) 1123 this.evalResponse(); 1124 } 1125 1126 try { 1127 (this.options['on' + state] || Prototype.emptyFunction)(transport, json); 1128 Ajax.Responders.dispatch('on' + state, this, transport, json); 1129 } catch (e) { 1130 this.dispatchException(e); 1131 } 1132 1133 if (state == 'Complete') { 1134 // avoid memory leak in MSIE: clean up 1135 this.transport.onreadystatechange = Prototype.emptyFunction; 1136 } 1137 }, 1138 1139 getHeader: function(name) { 1140 try { 1141 return this.transport.getResponseHeader(name); 1142 } catch (e) { return null } 1143 }, 1144 1145 evalJSON: function() { 1146 try { 1147 var json = this.getHeader('X-JSON'); 1148 return json ? json.evalJSON() : null; 1149 } catch (e) { return null } 1150 }, 1151 1152 evalResponse: function() { 1153 try { 1154 return eval((this.transport.responseText || '').unfilterJSON()); 1155 } catch (e) { 1156 this.dispatchException(e); 1157 } 1158 }, 1159 1160 dispatchException: function(exception) { 1161 (this.options.onException || Prototype.emptyFunction)(this, exception); 1162 Ajax.Responders.dispatch('onException', this, exception); 1163 } 1164 }); 1165 1166 Ajax.Updater = Class.create(); 1167 1168 Object.extend(Object.