1/* Prototype JavaScript framework, version 1.6.0.2 2 * (c) 2005-2008 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.6.0.2', 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 MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/) 18 }, 19 20 BrowserFeatures: { 21 XPath: !!document.evaluate, 22 ElementExtensions: !!window.HTMLElement, 23 SpecificElementExtensions: 24 document.createElement('div').__proto__ && 25 document.createElement('div').__proto__ !== 26 document.createElement('form').__proto__ 27 }, 28 29 ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>', 30 JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, 31 32 emptyFunction: function() { }, 33 K: function(x) { return x } 34}; 35 36if (Prototype.Browser.MobileSafari) 37 Prototype.BrowserFeatures.SpecificElementExtensions = false; 38 39 40/* Based on Alex Arnell's inheritance implementation. */ 41var Class = { 42 create: function() { 43 var parent = null, properties = $A(arguments); 44 if (Object.isFunction(properties[0])) 45 parent = properties.shift(); 46 47 function klass() { 48 this.initialize.apply(this, arguments); 49 } 50 51 Object.extend(klass, Class.Methods); 52 klass.superclass = parent; 53 klass.subclasses = []; 54 55 if (parent) { 56 var subclass = function() { }; 57 subclass.prototype = parent.prototype; 58 klass.prototype = new subclass; 59 parent.subclasses.push(klass); 60 } 61 62 for (var i = 0; i < properties.length; i++) 63 klass.addMethods(properties[i]); 64 65 if (!klass.prototype.initialize) 66 klass.prototype.initialize = Prototype.emptyFunction; 67 68 klass.prototype.constructor = klass; 69 70 return klass; 71 } 72}; 73 74Class.Methods = { 75 addMethods: function(source) { 76 var ancestor = this.superclass && this.superclass.prototype; 77 var properties = Object.keys(source); 78 79 if (!Object.keys({ toString: true }).length) 80 properties.push("toString", "valueOf"); 81 82 for (var i = 0, length = properties.length; i < length; i++) { 83 var property = properties[i], value = source[property]; 84 if (ancestor && Object.isFunction(value) && 85 value.argumentNames().first() == "$super") { 86 var method = value, value = Object.extend((function(m) { 87 return function() { return ancestor[m].apply(this, arguments) }; 88 })(property).wrap(method), { 89 valueOf: function() { return method }, 90 toString: function() { return method.toString() } 91 }); 92 } 93 this.prototype[property] = value; 94 } 95 96 return this; 97 } 98}; 99 100var Abstract = { }; 101 102Object.extend = function(destination, source) { 103 for (var property in source) 104 destination[property] = source[property]; 105 return destination; 106}; 107 108Object.extend(Object, { 109 inspect: function(object) { 110 try { 111 if (Object.isUndefined(object)) return 'undefined'; 112 if (object === null) return 'null'; 113 return object.inspect ? object.inspect() : String(object); 114 } catch (e) { 115 if (e instanceof RangeError) return '...'; 116 throw e; 117 } 118 }, 119 120 toJSON: function(object) { 121 var type = typeof object; 122 switch (type) { 123 case 'undefined': 124 case 'function': 125 case 'unknown': return; 126 case 'boolean': return object.toString(); 127 } 128 129 if (object === null) return 'null'; 130 if (object.toJSON) return object.toJSON(); 131 if (Object.isElement(object)) return; 132 133 var results = []; 134 for (var property in object) { 135 var value = Object.toJSON(object[property]); 136 if (!Object.isUndefined(value)) 137 results.push(property.toJSON() + ': ' + value); 138 } 139 140 return '{' + results.join(', ') + '}'; 141 }, 142 143 toQueryString: function(object) { 144 return $H(object).toQueryString(); 145 }, 146 147 toHTML: function(object) { 148 return object && object.toHTML ? object.toHTML() : String.interpret(object); 149 }, 150 151 keys: function(object) { 152 var keys = []; 153 for (var property in object) 154 keys.push(property); 155 return keys; 156 }, 157 158 values: function(object) { 159 var values = []; 160 for (var property in object) 161 values.push(object[property]); 162 return values; 163 }, 164 165 clone: function(object) { 166 return Object.extend({ }, object); 167 }, 168 169 isElement: function(object) { 170 return object && object.nodeType == 1; 171 }, 172 173 isArray: function(object) { 174 return object != null && typeof object == "object" && 175 'splice' in object && 'join' in object; 176 }, 177 178 isHash: function(object) { 179 return object instanceof Hash; 180 }, 181 182 isFunction: function(object) { 183 return typeof object == "function"; 184 }, 185 186 isString: function(object) { 187 return typeof object == "string"; 188 }, 189 190 isNumber: function(object) { 191 return typeof object == "number"; 192 }, 193 194 isUndefined: function(object) { 195 return typeof object == "undefined"; 196 } 197}); 198 199Object.extend(Function.prototype, { 200 argumentNames: function() { 201 var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip"); 202 return names.length == 1 && !names[0] ? [] : names; 203 }, 204 205 bind: function() { 206 if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; 207 var __method = this, args = $A(arguments), object = args.shift(); 208 return function() { 209 return __method.apply(object, args.concat($A(arguments))); 210 } 211 }, 212 213 bindAsEventListener: function() { 214 var __method = this, args = $A(arguments), object = args.shift(); 215 return function(event) { 216 return __method.apply(object, [event || window.event].concat(args)); 217 } 218 }, 219 220 curry: function() { 221 if (!arguments.length) return this; 222 var __method = this, args = $A(arguments); 223 return function() { 224 return __method.apply(this, args.concat($A(arguments))); 225 } 226 }, 227 228 delay: function() { 229 var __method = this, args = $A(arguments), timeout = args.shift() * 1000; 230 return window.setTimeout(function() { 231 return __method.apply(__method, args); 232 }, timeout); 233 }, 234 235 wrap: function(wrapper) { 236 var __method = this; 237 return function() { 238 return wrapper.apply(this, [__method.bind(this)].concat($A(arguments))); 239 } 240 }, 241 242 methodize: function() { 243 if (this._methodized) return this._methodized; 244 var __method = this; 245 return this._methodized = function() { 246 return __method.apply(null, [this].concat($A(arguments))); 247 }; 248 } 249}); 250 251Function.prototype.defer = Function.prototype.delay.curry(0.01); 252 253Date.prototype.toJSON = function() { 254 return '"' + this.getUTCFullYear() + '-' + 255 (this.getUTCMonth() + 1).toPaddedString(2) + '-' + 256 this.getUTCDate().toPaddedString(2) + 'T' + 257 this.getUTCHours().toPaddedString(2) + ':' + 258 this.getUTCMinutes().toPaddedString(2) + ':' + 259 this.getUTCSeconds().toPaddedString(2) + 'Z"'; 260}; 261 262var Try = { 263 these: function() { 264 var returnValue; 265 266 for (var i = 0, length = arguments.length; i < length; i++) { 267 var lambda = arguments[i]; 268 try { 269 returnValue = lambda(); 270 break; 271 } catch (e) { } 272 } 273 274 return returnValue; 275 } 276}; 277 278RegExp.prototype.match = RegExp.prototype.test; 279 280RegExp.escape = function(str) { 281 return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); 282}; 283 284/*--------------------------------------------------------------------------*/ 285 286var PeriodicalExecuter = Class.create({ 287 initialize: function(callback, frequency) { 288 this.callback = callback; 289 this.frequency = frequency; 290 this.currentlyExecuting = false; 291 292 this.registerCallback(); 293 }, 294 295 registerCallback: function() { 296 this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); 297 }, 298 299 execute: function() { 300 this.callback(this); 301 }, 302 303 stop: function() { 304 if (!this.timer) return; 305 clearInterval(this.timer); 306 this.timer = null; 307 }, 308 309 onTimerEvent: function() { 310 if (!this.currentlyExecuting) { 311 try { 312 this.currentlyExecuting = true; 313 this.execute(); 314 } finally { 315 this.currentlyExecuting = false; 316 } 317 } 318 } 319}); 320Object.extend(String, { 321 interpret: function(value) { 322 return value == null ? '' : String(value); 323 }, 324 specialChar: { 325 '\b': '\\b', 326 '\t': '\\t', 327 '\n': '\\n', 328 '\f': '\\f', 329 '\r': '\\r', 330 '\\': '\\\\' 331 } 332}); 333 334Object.extend(String.prototype, { 335 gsub: function(pattern, replacement) { 336 var result = '', source = this, match; 337 replacement = arguments.callee.prepareReplacement(replacement); 338 339 while (source.length > 0) { 340 if (match = source.match(pattern)) { 341 result += source.slice(0, match.index); 342 result += String.interpret(replacement(match)); 343 source = source.slice(match.index + match[0].length); 344 } else { 345 result += source, source = ''; 346 } 347 } 348 return result; 349 }, 350 351 sub: function(pattern, replacement, count) { 352 replacement = this.gsub.prepareReplacement(replacement); 353 count = Object.isUndefined(count) ? 1 : count; 354 355 return this.gsub(pattern, function(match) { 356 if (--count < 0) return match[0]; 357 return replacement(match); 358 }); 359 }, 360 361 scan: function(pattern, iterator) { 362 this.gsub(pattern, iterator); 363 return String(this); 364 }, 365 366 truncate: function(length, truncation) { 367 length = length || 30; 368 truncation = Object.isUndefined(truncation) ? '...' : truncation; 369 return this.length > length ? 370 this.slice(0, length - truncation.length) + truncation : String(this); 371 }, 372 373 strip: function() { 374 return this.replace(/^\s+/, '').replace(/\s+$/, ''); 375 }, 376 377 stripTags: function() { 378 return this.replace(/<\/?[^>]+>/gi, ''); 379 }, 380 381 stripScripts: function() { 382 return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); 383 }, 384 385 extractScripts: function() { 386 var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); 387 var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); 388 return (this.match(matchAll) || []).map(function(scriptTag) { 389 return (scriptTag.match(matchOne) || ['', ''])[1]; 390 }); 391 }, 392 393 evalScripts: function() { 394 return this.extractScripts().map(function(script) { return eval(script) }); 395 }, 396 397 escapeHTML: function() { 398 var self = arguments.callee; 399 self.text.data = this; 400 return self.div.innerHTML; 401 }, 402 403 unescapeHTML: function() { 404 var div = new Element('div'); 405 div.innerHTML = this.stripTags(); 406 return div.childNodes[0] ? (div.childNodes.length > 1 ? 407 $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) : 408 div.childNodes[0].nodeValue) : ''; 409 }, 410 411 toQueryParams: function(separator) { 412 var match = this.strip().match(/([^?#]*)(#.*)?$/); 413 if (!match) return { }; 414 415 return match[1].split(separator || '&').inject({ }, function(hash, pair) { 416 if ((pair = pair.split('='))[0]) { 417 var key = decodeURIComponent(pair.shift()); 418 var value = pair.length > 1 ? pair.join('=') : pair[0]; 419 if (value != undefined) value = decodeURIComponent(value); 420 421 if (key in hash) { 422 if (!Object.isArray(hash[key])) hash[key] = [hash[key]]; 423 hash[key].push(value); 424 } 425 else hash[key] = value; 426 } 427 return hash; 428 }); 429 }, 430 431 toArray: function() { 432 return this.split(''); 433 }, 434 435 succ: function() { 436 return this.slice(0, this.length - 1) + 437 String.fromCharCode(this.charCodeAt(this.length - 1) + 1); 438 }, 439 440 times: function(count) { 441 return count < 1 ? '' : new Array(count + 1).join(this); 442 }, 443 444 camelize: function() { 445 var parts = this.split('-'), len = parts.length; 446 if (len == 1) return parts[0]; 447 448 var camelized = this.charAt(0) == '-' 449 ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) 450 : parts[0]; 451 452 for (var i = 1; i < len; i++) 453 camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); 454 455 return camelized; 456 }, 457 458 capitalize: function() { 459 return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); 460 }, 461 462 underscore: function() { 463 return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); 464 }, 465 466 dasherize: function() { 467 return this.gsub(/_/,'-'); 468 }, 469 470 inspect: function(useDoubleQuotes) { 471 var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) { 472 var character = String.specialChar[match[0]]; 473 return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16); 474 }); 475 if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; 476 return "'" + escapedString.replace(/'/g, '\\\'') + "'"; 477 }, 478 479 toJSON: function() { 480 return this.inspect(true); 481 }, 482 483 unfilterJSON: function(filter) { 484 return this.sub(filter || Prototype.JSONFilter, '#{1}'); 485 }, 486 487 isJSON: function() { 488 var str = this; 489 if (str.blank()) return false; 490 str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); 491 return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); 492 }, 493 494 evalJSON: function(sanitize) { 495 var json = this.unfilterJSON(); 496 try { 497 if (!sanitize || json.isJSON()) return eval('(' + json + ')'); 498 } catch (e) { } 499 throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); 500 }, 501 502 include: function(pattern) { 503 return this.indexOf(pattern) > -1; 504 }, 505 506 startsWith: function(pattern) { 507 return this.indexOf(pattern) === 0; 508 }, 509 510 endsWith: function(pattern) { 511 var d = this.length - pattern.length; 512 return d >= 0 && this.lastIndexOf(pattern) === d; 513 }, 514 515 empty: function() { 516 return this == ''; 517 }, 518 519 blank: function() { 520 return /^\s*$/.test(this); 521 }, 522 523 interpolate: function(object, pattern) { 524 return new Template(this, pattern).evaluate(object); 525 } 526}); 527 528if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, { 529 escapeHTML: function() { 530 return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); 531 }, 532 unescapeHTML: function() { 533 return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); 534 } 535}); 536 537String.prototype.gsub.prepareReplacement = function(replacement) { 538 if (Object.isFunction(replacement)) return replacement; 539 var template = new Template(replacement); 540 return function(match) { return template.evaluate(match) }; 541}; 542 543String.prototype.parseQuery = String.prototype.toQueryParams; 544 545Object.extend(String.prototype.escapeHTML, { 546 div: document.createElement('div'), 547 text: document.createTextNode('') 548}); 549 550with (String.prototype.escapeHTML) div.appendChild(text); 551 552var Template = Class.create({ 553 initialize: function(template, pattern) { 554 this.template = template.toString(); 555 this.pattern = pattern || Template.Pattern; 556 }, 557 558 evaluate: function(object) { 559 if (Object.isFunction(object.toTemplateReplacements)) 560 object = object.toTemplateReplacements(); 561 562 return this.template.gsub(this.pattern, function(match) { 563 if (object == null) return ''; 564 565 var before = match[1] || ''; 566 if (before == '\\') return match[2]; 567 568 var ctx = object, expr = match[3]; 569 var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; 570 match = pattern.exec(expr); 571 if (match == null) return before; 572 573 while (match != null) { 574 var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1]; 575 ctx = ctx[comp]; 576 if (null == ctx || '' == match[3]) break; 577 expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); 578 match = pattern.exec(expr); 579 } 580 581 return before + String.interpret(ctx); 582 }); 583 } 584}); 585Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; 586 587var $break = { }; 588 589var Enumerable = { 590 each: function(iterator, context) { 591 var index = 0; 592 iterator = iterator.bind(context); 593 try { 594 this._each(function(value) { 595 iterator(value, index++); 596 }); 597 } catch (e) { 598 if (e != $break) throw e; 599 } 600 return this; 601 }, 602 603 eachSlice: function(number, iterator, context) { 604 iterator = iterator ? iterator.bind(context) : Prototype.K; 605 var index = -number, slices = [], array = this.toArray(); 606 while ((index += number) < array.length) 607 slices.push(array.slice(index, index+number)); 608 return slices.collect(iterator, context); 609 }, 610 611 all: function(iterator, context) { 612 iterator = iterator ? iterator.bind(context) : Prototype.K; 613 var result = true; 614 this.each(function(value, index) { 615 result = result && !!iterator(value, index); 616 if (!result) throw $break; 617 }); 618 return result; 619 }, 620 621 any: function(iterator, context) { 622 iterator = iterator ? iterator.bind(context) : Prototype.K; 623 var result = false; 624 this.each(function(value, index) { 625 if (result = !!iterator(value, index)) 626 throw $break; 627 }); 628 return result; 629 }, 630 631 collect: function(iterator, context) { 632 iterator = iterator ? iterator.bind(context) : Prototype.K; 633 var results = []; 634 this.each(function(value, index) { 635 results.push(iterator(value, index)); 636 }); 637 return results; 638 }, 639 640 detect: function(iterator, context) { 641 iterator = iterator.bind(context); 642 var result; 643 this.each(function(value, index) { 644 if (iterator(value, index)) { 645 result = value; 646 throw $break; 647 } 648 }); 649 return result; 650 }, 651 652 findAll: function(iterator, context) { 653 iterator = iterator.bind(context); 654 var results = []; 655 this.each(function(value, index) { 656 if (iterator(value, index)) 657 results.push(value); 658 }); 659 return results; 660 }, 661 662 grep: function(filter, iterator, context) { 663 iterator = iterator ? iterator.bind(context) : Prototype.K; 664 var results = []; 665 666 if (Object.isString(filter)) 667 filter = new RegExp(filter); 668 669 this.each(function(value, index) { 670 if (filter.match(value)) 671 results.push(iterator(value, index)); 672 }); 673 return results; 674 }, 675 676 include: function(object) { 677 if (Object.isFunction(this.indexOf)) 678 if (this.indexOf(object) != -1) return true; 679 680 var found = false; 681 this.each(function(value) { 682 if (value == object) { 683 found = true; 684 throw $break; 685 } 686 }); 687 return found; 688 }, 689 690 inGroupsOf: function(number, fillWith) { 691 fillWith = Object.isUndefined(fillWith) ? null : fillWith; 692 return this.eachSlice(number, function(slice) { 693 while(slice.length < number) slice.push(fillWith); 694 return slice; 695 }); 696 }, 697 698 inject: function(memo, iterator, context) { 699 iterator = iterator.bind(context); 700 this.each(function(value, index) { 701 memo = iterator(memo, value, index); 702 }); 703 return memo; 704 }, 705 706 invoke: function(method) { 707 var args = $A(arguments).slice(1); 708 return this.map(function(value) { 709 return value[method].apply(value, args); 710 }); 711 }, 712 713 max: function(iterator, context) { 714 iterator = iterator ? iterator.bind(context) : Prototype.K; 715 var result; 716 this.each(function(value, index) { 717 value = iterator(value, index); 718 if (result == null || value >= result) 719 result = value; 720 }); 721 return result; 722 }, 723 724 min: function(iterator, context) { 725 iterator = iterator ? iterator.bind(context) : Prototype.K; 726 var result; 727 this.each(function(value, index) { 728 value = iterator(value, index); 729 if (result == null || value < result) 730 result = value; 731 }); 732 return result; 733 }, 734 735 partition: function(iterator, context) { 736 iterator = iterator ? iterator.bind(context) : Prototype.K; 737 var trues = [], falses = []; 738 this.each(function(value, index) { 739 (iterator(value, index) ? 740 trues : falses).push(value); 741 }); 742 return [trues, falses]; 743 }, 744 745 pluck: function(property) { 746 var results = []; 747 this.each(function(value) { 748 results.push(value[property]); 749 }); 750 return results; 751 }, 752 753 reject: function(iterator, context) { 754 iterator = iterator.bind(context); 755 var results = []; 756 this.each(function(value, index) { 757 if (!iterator(value, index)) 758 results.push(value); 759 }); 760 return results; 761 }, 762 763 sortBy: function(iterator, context) { 764 iterator = iterator.bind(context); 765 return this.map(function(value, index) { 766 return {value: value, criteria: iterator(value, index)}; 767 }).sort(function(left, right) { 768 var a = left.criteria, b = right.criteria; 769 return a < b ? -1 : a > b ? 1 : 0; 770 }).pluck('value'); 771 }, 772 773 toArray: function() { 774 return this.map(); 775 }, 776 777 zip: function() { 778 var iterator = Prototype.K, args = $A(arguments); 779 if (Object.isFunction(args.last())) 780 iterator = args.pop(); 781 782 var collections = [this].concat(args).map($A); 783 return this.map(function(value, index) { 784 return iterator(collections.pluck(index)); 785 }); 786 }, 787 788 size: function() { 789 return this.toArray().length; 790 }, 791 792 inspect: function() { 793 return '#<Enumerable:' + this.toArray().inspect() + '>'; 794 } 795}; 796 797Object.extend(Enumerable, { 798 map: Enumerable.collect, 799 find: Enumerable.detect, 800 select: Enumerable.findAll, 801 filter: Enumerable.findAll, 802 member: Enumerable.include, 803 entries: Enumerable.toArray, 804 every: Enumerable.all, 805 some: Enumerable.any 806}); 807function $A(iterable) { 808 if (!iterable) return []; 809 if (iterable.toArray) return iterable.toArray(); 810 var length = iterable.length || 0, results = new Array(length); 811 while (length--) results[length] = iterable[length]; 812 return results; 813} 814 815if (Prototype.Browser.WebKit) { 816 $A = function(iterable) { 817 if (!iterable) return []; 818 if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') && 819 iterable.toArray) return iterable.toArray(); 820 var length = iterable.length || 0, results = new Array(length); 821 while (length--) results[length] = iterable[length]; 822 return results; 823 }; 824} 825 826Array.from = $A; 827 828Object.extend(Array.prototype, Enumerable); 829 830if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse; 831 832Object.extend(Array.prototype, { 833 _each: function(iterator) { 834 for (var i = 0, length = this.length; i < length; i++) 835 iterator(this[i]); 836 }, 837 838 clear: function() { 839 this.length = 0; 840 return this; 841 }, 842 843 first: function() { 844 return this[0]; 845 }, 846 847 last: function() { 848 return this[this.length - 1]; 849 }, 850 851 compact: function() { 852 return this.select(function(value) { 853 return value != null; 854 }); 855 }, 856 857 flatten: function() { 858 return this.inject([], function(array, value) { 859 return array.concat(Object.isArray(value) ? 860 value.flatten() : [value]); 861 }); 862 }, 863 864 without: function() { 865 var values = $A(arguments); 866 return this.select(function(value) { 867 return !values.include(value); 868 }); 869 }, 870 871 reverse: function(inline) { 872 return (inline !== false ? this : this.toArray())._reverse(); 873 }, 874 875 reduce: function() { 876 return this.length > 1 ? this : this[0]; 877 }, 878 879 uniq: function(sorted) { 880 return this.inject([], function(array, value, index) { 881 if (0 == index || (sorted ? array.last() != value : !array.include(value))) 882 array.push(value); 883 return array; 884 }); 885 }, 886 887 intersect: function(array) { 888 return this.uniq().findAll(function(item) { 889 return array.detect(function(value) { return item === value }); 890 }); 891 }, 892 893 clone: function() { 894 return [].concat(this); 895 }, 896 897 size: function() { 898 return this.length; 899 }, 900 901 inspect: function() { 902 return '[' + this.map(Object.inspect).join(', ') + ']'; 903 }, 904 905 toJSON: function() { 906 var results = []; 907 this.each(function(object) { 908 var value = Object.toJSON(object); 909 if (!Object.isUndefined(value)) results.push(value); 910 }); 911 return '[' + results.join(', ') + ']'; 912 } 913}); 914 915// use native browser JS 1.6 implementation if available 916if (Object.isFunction(Array.prototype.forEach)) 917 Array.prototype._each = Array.prototype.forEach; 918 919if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) { 920 i || (i = 0); 921 var length = this.length; 922 if (i < 0) i = length + i; 923 for (; i < length; i++) 924 if (this[i] === item) return i; 925 return -1; 926}; 927 928if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) { 929 i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; 930 var n = this.slice(0, i).reverse().indexOf(item); 931 return (n < 0) ? n : i - n - 1; 932}; 933 934Array.prototype.toArray = Array.prototype.clone; 935 936function $w(string) { 937 if (!Object.isString(string)) return []; 938 string = string.strip(); 939 return string ? string.split(/\s+/) : []; 940} 941 942if (Prototype.Browser.Opera){ 943 Array.prototype.concat = function() { 944 var array = []; 945 for (var i = 0, length = this.length; i < length; i++) array.push(this[i]); 946 for (var i = 0, length = arguments.length; i < length; i++) { 947 if (Object.isArray(arguments[i])) { 948 for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++) 949 array.push(arguments[i][j]); 950 } else { 951 array.push(arguments[i]); 952 } 953 } 954 return array; 955 }; 956} 957Object.extend(Number.prototype, { 958 toColorPart: function() { 959 return this.toPaddedString(2, 16); 960 }, 961 962 succ: function() { 963 return this + 1; 964 }, 965 966 times: function(iterator) { 967 $R(0, this, true).each(iterator); 968 return this; 969 }, 970 971 toPaddedString: function(length, radix) { 972 var string = this.toString(radix || 10); 973 return '0'.times(length - string.length) + string; 974 }, 975 976 toJSON: function() { 977 return isFinite(this) ? this.toString() : 'null'; 978 } 979}); 980 981$w('abs round ceil floor').each(function(method){ 982 Number.prototype[method] = Math[method].methodize(); 983}); 984function $H(object) { 985 return new Hash(object); 986}; 987 988var Hash = Class.create(Enumerable, (function() { 989 990 function toQueryPair(key, value) { 991 if (Object.isUndefined(value)) return key; 992 return key + '=' + encodeURIComponent(String.interpret(value)); 993 } 994 995 return { 996 initialize: function(object) { 997 this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); 998 }, 999 1000 _each: function(iterator) { 1001 for (var key in this._object) { 1002 var value = this._object[key], pair = [key, value]; 1003 pair.key = key; 1004 pair.value = value; 1005 iterator(pair); 1006 } 1007 }, 1008 1009 set: function(key, value) { 1010 return this._object[key] = value; 1011 }, 1012 1013 get: function(key) { 1014 return this._object[key]; 1015 }, 1016 1017 unset: function(key) { 1018 var value = this._object[key]; 1019 delete this._object[key]; 1020 return value; 1021 }, 1022 1023 toObject: function() { 1024 return Object.clone(this._object); 1025 }, 1026 1027 keys: function() { 1028 return this.pluck('key'); 1029 }, 1030 1031 values: function() { 1032 return this.pluck('value'); 1033 }, 1034 1035 index: function(value) { 1036 var match = this.detect(function(pair) { 1037 return pair.value === value; 1038 }); 1039 return match && match.key; 1040 }, 1041 1042 merge: function(object) { 1043 return this.clone().update(object); 1044 }, 1045 1046 update: function(object) { 1047 return new Hash(object).inject(this, function(result, pair) { 1048 result.set(pair.key, pair.value); 1049 return result; 1050 }); 1051 }, 1052 1053 toQueryString: function() { 1054 return this.map(function(pair) { 1055 var key = encodeURIComponent(pair.key), values = pair.value; 1056 1057 if (values && typeof values == 'object') { 1058 if (Object.isArray(values)) 1059 return values.map(toQueryPair.curry(key)).join('&'); 1060 } 1061 return toQueryPair(key, values); 1062 }).join('&'); 1063 }, 1064 1065 inspect: function() { 1066 return '#<Hash:{' + this.map(function(pair) { 1067 return pair.map(Object.inspect).join(': '); 1068 }).join(', ') + '}>'; 1069 }, 1070 1071 toJSON: function() { 1072 return Object.toJSON(this.toObject()); 1073 }, 1074 1075 clone: function() { 1076 return new Hash(this); 1077 } 1078 } 1079})()); 1080 1081Hash.prototype.toTemplateReplacements = Hash.prototype.toObject; 1082Hash.from = $H; 1083var ObjectRange = Class.create(Enumerable, { 1084 initialize: function(start, end, exclusive) { 1085 this.start = start; 1086 this.end = end; 1087 this.exclusive = exclusive; 1088 }, 1089 1090 _each: function(iterator) { 1091 var value = this.start; 1092 while (this.include(value)) { 1093 iterator(value); 1094 value = value.succ(); 1095 } 1096 }, 1097 1098 include: function(value) { 1099 if (value < this.start) 1100 return false; 1101 if (this.exclusive) 1102 return value < this.end; 1103 return value <= this.end; 1104 } 1105}); 1106 1107var $R = function(start, end, exclusive) { 1108 return new ObjectRange(start, end, exclusive); 1109}; 1110 1111var Ajax = { 1112 getTransport: function() { 1113 return Try.these( 1114 function() {return new XMLHttpRequest()}, 1115 function() {return new ActiveXObject('Msxml2.XMLHTTP')}, 1116 function() {return new ActiveXObject('Microsoft.XMLHTTP')} 1117 ) || false; 1118 }, 1119 1120 activeRequestCount: 0 1121}; 1122 1123Ajax.Responders = { 1124 responders: [], 1125 1126 _each: function(iterator) { 1127 this.responders._each(iterator); 1128 }, 1129 1130 register: function(responder) { 1131 if (!this.include(responder)) 1132 this.responders.push(responder); 1133 }, 1134 1135 unregister: function(responder) { 1136 this.responders = this.responders.without(responder); 1137 }, 1138 1139 dispatch: function(callback, request, transport, json) { 1140 this.each(function(responder) { 1141 if (Object.isFunction(responder[callback])) { 1142 try { 1143 responder[callback].apply(responder, [request, transport, json]); 1144 } catch (e) { } 1145 } 1146 }); 1147 } 1148}; 1149 1150Object.extend(Ajax.Responders, Enumerable); 1151 1152Ajax.Responders.register({ 1153 onCreate: function() { Ajax.activeRequestCount++ }, 1154 onComplete: function() { Ajax.activeRequestCount-- } 1155}); 1156 1157Ajax.Base = Class.create({ 1158 initialize: function(options) { 1159 this.options = { 1160 method: 'post', 1161 asynchronous: true, 1162 contentType: 'application/x-www-form-urlencoded', 1163 encoding: 'UTF-8', 1164 parameters: '', 1165 evalJSON: true, 1166 evalJS: true 1167 }; 1168 Object.extend(this.options, options || { }); 1169 1170 this.options.method = this.options.method.toLowerCase(); 1171 1172 if (Object.isString(this.options.parameters)) 1173 this.options.parameters = this.options.parameters.toQueryParams(); 1174 else if (Object.isHash(this.options.parameters)) 1175 this.options.parameters = this.options.parameters.toObject(); 1176 } 1177}); 1178 1179Ajax.Request = Class.create(Ajax.Base, { 1180 _complete: false, 1181 1182 initialize: function($super, url, options) { 1183 $super(options); 1184 this.transport = Ajax.getTransport(); 1185 this.request(url); 1186 }, 1187 1188 request: function(url) { 1189 this.url = url; 1190 this.method = this.options.method; 1191 var params = Object.clone(this.options.parameters); 1192 1193 if (!['get', 'post'].include(this.method)) { 1194 // simulate other verbs over post 1195 params['_method'] = this.method; 1196 this.method = 'post'; 1197 } 1198 1199 this.parameters = params; 1200 1201 if (params = Object.toQueryString(params)) { 1202 // when GET, append parameters to URL 1203 if (this.method == 'get') 1204 this.url += (this.url.include('?') ? '&' : '?') + params; 1205 else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) 1206 params += '&_='; 1207 } 1208 1209 try { 1210 var response = new Ajax.Response(this); 1211 if (this.options.onCreate) this.options.onCreate(response); 1212 Ajax.Responders.dispatch('onCreate', this, response); 1213 1214 this.transport.open(this.method.toUpperCase(), this.url, 1215 this.options.asynchronous); 1216 1217 if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); 1218 1219 this.transport.onreadystatechange = this.onStateChange.bind(this); 1220 this.setRequestHeaders(); 1221 1222 this.body = this.method == 'post' ? (this.options.postBody || params) : null; 1223 this.transport.send(this.body); 1224 1225 /* Force Firefox to handle ready state 4 for synchronous requests */ 1226 if (!this.options.asynchronous && this.transport.overrideMimeType) 1227 this.onStateChange(); 1228 1229 } 1230 catch (e) { 1231 this.dispatchException(e); 1232 } 1233 }, 1234 1235 onStateChange: function() { 1236 var readyState = this.transport.readyState; 1237 if (readyState > 1 && !((readyState == 4) && this._complete)) 1238 this.respondToReadyState(this.transport.readyState); 1239 }, 1240 1241 setRequestHeaders: function() { 1242 var headers = { 1243 'X-Requested-With': 'XMLHttpRequest', 1244 'X-Prototype-Version': Prototype.Version, 1245 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' 1246 }; 1247 1248 if (this.method == 'post') { 1249 headers['Content-type'] = this.options.contentType + 1250 (this.options.encoding ? '; charset=' + this.options.encoding : ''); 1251 1252 /* Force "Connection: close" for older Mozilla browsers to work 1253 * around a bug where XMLHttpRequest sends an incorrect 1254 * Content-length header. See Mozilla Bugzilla #246651. 1255 */ 1256 if (this.transport.overrideMimeType && 1257 (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) 1258 headers['Connection'] = 'close'; 1259 } 1260 1261 // user-defined headers 1262 if (typeof this.options.requestHeaders == 'object') { 1263 var extras = this.options.requestHeaders; 1264 1265 if (Object.isFunction(extras.push)) 1266 for (var i = 0, length = extras.length; i < length; i += 2) 1267 headers[extras[i]] = extras[i+1]; 1268 else 1269 $H(extras).each(function(pair) { headers[pair.key] = pair.value }); 1270 } 1271 1272 for (var name in headers) 1273 this.transport.setRequestHeader(name, headers[name]); 1274 }, 1275 1276 success: function() { 1277 var status = this.getStatus(); 1278 return !status || (status >= 200 && status < 300); 1279 }, 1280 1281 getStatus: function() { 1282 try { 1283 return this.transport.status || 0; 1284 } catch (e) { return 0 } 1285 }, 1286 1287 respondToReadyState: function(readyState) { 1288 var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this); 1289 1290 if (state == 'Complete') { 1291 try { 1292 this._complete = true; 1293 (this.options['on' + response.status] 1294 || this.options['on' + (this.success() ? 'Success' : 'Failure')] 1295 || Prototype.emptyFunction)(response, response.headerJSON); 1296 } catch (e) { 1297 this.dispatchException(e); 1298 } 1299 1300 var contentType = response.getHeader('Content-type'); 1301 if (this.options.evalJS == 'force' 1302 || (this.options.evalJS && this.isSameOrigin() && contentType 1303 && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))) 1304 this.evalResponse(); 1305 } 1306 1307 try { 1308 (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON); 1309 Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON); 1310 } catch (e) { 1311 this.dispatchException(e); 1312 } 1313 1314 if (state == 'Complete') { 1315 // avoid memory leak in MSIE: clean up 1316 this.transport.onreadystatechange = Prototype.emptyFunction; 1317 } 1318 }, 1319 1320 isSameOrigin: function() { 1321 var m = this.url.match(/^\s*https?:\/\/[^\/]*/); 1322 return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({ 1323 protocol: location.protocol, 1324 domain: document.domain, 1325 port: location.port ? ':' + location.port : '' 1326 })); 1327 }, 1328 1329 getHeader: function(name) { 1330 try { 1331 return this.transport.getResponseHeader(name) || null; 1332 } catch (e) { return null } 1333 }, 1334 1335 evalResponse: function() { 1336 try { 1337 return eval((this.transport.responseText || '').unfilterJSON()); 1338 } catch (e) { 1339 this.dispatchException(e); 1340 } 1341 }, 1342 1343 dispatchException: function(exception) { 1344 (this.options.onException || Prototype.emptyFunction)(this, exception); 1345 Ajax.Responders.dispatch('onException', this, exception); 1346 } 1347}); 1348 1349Ajax.Request.Events = 1350 ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; 1351 1352Ajax.Response = Class.create({ 1353 initialize: function(request){ 1354 this.request = request; 1355 var transport = this.transport = request.transport, 1356 readyState = this.readyState = transport.readyState; 1357 1358 if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { 1359 this.status = this.getStatus(); 1360 this.statusText = this.getStatusText(); 1361 this.responseText = String.interpret(transport.responseText); 1362 this.headerJSON = this._getHeaderJSON(); 1363 } 1364 1365 if(readyState == 4) { 1366 var xml = transport.responseXML; 1367 this.responseXML = Object.isUndefined(xml) ? null : xml; 1368 this.responseJSON = this._getResponseJSON(); 1369 } 1370 }, 1371 1372 status: 0, 1373 statusText: '', 1374 1375 getStatus: Ajax.Request.prototype.getStatus, 1376 1377 getStatusText: function() { 1378 try { 1379 return this.transport.statusText || ''; 1380 } catch (e) { return '' } 1381 }, 1382 1383 getHeader: Ajax.Request.prototype.getHeader, 1384 1385 getAllHeaders: function() { 1386 try { 1387 return this.getAllResponseHeaders(); 1388 } catch (e) { return null } 1389 }, 1390 1391 getResponseHeader: function(name) { 1392 return this.transport.getResponseHeader(name); 1393 }, 1394 1395 getAllResponseHeaders: function() { 1396 return this.transport.getAllResponseHeaders(); 1397 }, 1398 1399 _getHeaderJSON: function() { 1400 var json = this.getHeader('X-JSON'); 1401 if (!json) return null; 1402 json = decodeURIComponent(escape(json)); 1403 try { 1404 return json.evalJSON(this.request.options.sanitizeJSON || 1405 !this.request.isSameOrigin()); 1406 } catch (e) { 1407 this.request.dispatchException(e); 1408 } 1409 }, 1410 1411 _getResponseJSON: function() { 1412 var options = this.request.options; 1413 if (!options.evalJSON || (options.evalJSON != 'force' && 1414 !(this.getHeader('Content-type') || '').include('application/json')) || 1415 this.responseText.blank()) 1416 return null; 1417 try { 1418 return this.responseText.evalJSON(options.sanitizeJSON || 1419 !this.request.isSameOrigin()); 1420 } catch (e) { 1421 this.request.dispatchException(e); 1422 } 1423 } 1424}); 1425 1426Ajax.Updater = Class.create(Ajax.Request, { 1427 initialize: function($super, container, url, options) { 1428 this.container = { 1429 success: (container.success || container), 1430 failure: (container.failure || (container.success ? null : container)) 1431 }; 1432 1433 options = Object.clone(options); 1434 var onComplete = options.onComplete; 1435 options.onComplete = (function(response, json) { 1436 this.updateContent(response.responseText); 1437 if (Object.isFunction(onComplete)) onComplete(response, json); 1438 }).bind(this); 1439 1440 $super(url, options); 1441 }, 1442 1443 updateContent: function(responseText) { 1444 var receiver = this.container[this.success() ? 'success' : 'failure'], 1445 options = this.options; 1446 1447 if (!options.evalScripts) responseText = responseText.stripScripts(); 1448 1449 if (receiver = $(receiver)) { 1450 if (options.insertion) { 1451 if (Object.isString(options.insertion)) { 1452 var insertion = { }; insertion[options.insertion] = responseText; 1453 receiver.insert(insertion); 1454 } 1455 else options.insertion(receiver, responseText); 1456 } 1457 else receiver.update(responseText); 1458 } 1459 } 1460}); 1461 1462Ajax.PeriodicalUpdater = Class.create(Ajax.Base, { 1463 initialize: function($super, container, url, options) { 1464 $super(options); 1465 this.onComplete = this.options.onComplete; 1466 1467 this.frequency = (this.options.frequency || 2); 1468 this.decay = (this.options.decay || 1); 1469 1470 this.updater = { }; 1471 this.container = container; 1472 this.url = url; 1473 1474 this.start(); 1475 }, 1476 1477 start: function() { 1478 this.options.onComplete = this.updateComplete.bind(this); 1479 this.onTimerEvent(); 1480 }, 1481 1482 stop: function() { 1483 this.updater.options.onComplete = undefined; 1484 clearTimeout(this.timer); 1485 (this.onComplete || Prototype.emptyFunction).apply(this, arguments); 1486 }, 1487 1488 updateComplete: function(response) { 1489 if (this.options.decay) { 1490 this.decay = (response.responseText == this.lastText ? 1491 this.decay * this.options.decay : 1); 1492 1493 this.lastText = response.responseText; 1494 } 1495 this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); 1496 }, 1497 1498 onTimerEvent: function() { 1499 this.updater = new Ajax.Updater(this.container, this.url, this.options); 1500 } 1501}); 1502function $(element) { 1503 if (arguments.length > 1) { 1504 for (var i = 0, elements = [], length = arguments.length; i < length; i++) 1505 elements.push($(arguments[i])); 1506 return elements; 1507 } 1508 if (Object.isString(element)) 1509 element = document.getElementById(element); 1510 return Element.extend(element); 1511} 1512 1513if (Prototype.BrowserFeatures.XPath) { 1514 document._getElementsByXPath = function(expression, parentElement) { 1515 var results = []; 1516 var query = document.evaluate(expression, $(parentElement) || document, 1517 null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); 1518 for (var i = 0, length = query.snapshotLength; i < length; i++) 1519 results.push(Element.extend(query.snapshotItem(i))); 1520 return results; 1521 }; 1522} 1523 1524/*--------------------------------------------------------------------------*/ 1525 1526if (!window.Node) var Node = { }; 1527 1528if (!Node.ELEMENT_NODE) { 1529 // DOM level 2 ECMAScript Language Binding 1530 Object.extend(Node, { 1531 ELEMENT_NODE: 1, 1532 ATTRIBUTE_NODE: 2, 1533 TEXT_NODE: 3, 1534 CDATA_SECTION_NODE: 4, 1535 ENTITY_REFERENCE_NODE: 5, 1536 ENTITY_NODE: 6, 1537 PROCESSING_INSTRUCTION_NODE: 7, 1538 COMMENT_NODE: 8, 1539 DOCUMENT_NODE: 9, 1540 DOCUMENT_TYPE_NODE: 10, 1541 DOCUMENT_FRAGMENT_NODE: 11, 1542 NOTATION_NODE: 12 1543 }); 1544} 1545 1546(function() { 1547 var element = this.Element; 1548 this.Element = function(tagName, attributes) { 1549 attributes = attributes || { }; 1550 tagName = tagName.toLowerCase(); 1551 var cache = Element.cache; 1552 if (Prototype.Browser.IE && attributes.name) { 1553 tagName = '<' + tagName + ' name="' + attributes.name + '">'; 1554 delete attributes.name; 1555 return Element.writeAttribute(document.createElement(tagName), attributes); 1556 } 1557 if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); 1558 return Element.writeAttribute(cache[tagName].cloneNode(false), attributes); 1559 }; 1560 Object.extend(this.Element, element || { }); 1561}).call(window); 1562 1563Element.cache = { }; 1564 1565Element.Methods = { 1566 visible: function(element) { 1567 return $(element).style.display != 'none'; 1568 }, 1569 1570 toggle: function(element) { 1571 element = $(element); 1572 Element[Element.visible(element) ? 'hide' : 'show'](element); 1573 return element; 1574 }, 1575 1576 hide: function(element) { 1577 $(element).style.display = 'none'; 1578 return element; 1579 }, 1580 1581 show: function(element) { 1582 $(element).style.display = ''; 1583 return element; 1584 }, 1585 1586 remove: function(element) { 1587 element = $(element); 1588 element.parentNode.removeChild(element); 1589 return element; 1590 }, 1591 1592 update: function(element, content) { 1593 element = $(element); 1594 if (content && content.toElement) content = content.toElement(); 1595 if (Object.isElement(content)) return element.update().insert(content); 1596 content = Object.toHTML(content); 1597 element.innerHTML = content.stripScripts(); 1598 content.evalScripts.bind(content).defer(); 1599 return element; 1600 }, 1601 1602 replace: function(element, content) { 1603 element = $(element); 1604 if (content && content.toElement) content = content.toElement(); 1605 else if (!Object.isElement(content)) { 1606 content = Object.toHTML(content); 1607 var range = element.ownerDocument.createRange(); 1608 range.selectNode(element); 1609 content.evalScripts.bind(content).defer(); 1610 content = range.createContextualFragment(content.stripScripts()); 1611 } 1612 element.parentNode.replaceChild(content, element); 1613 return element; 1614 }, 1615 1616 insert: function(element, insertions) { 1617 element = $(element); 1618 1619 if (Object.isString(insertions) || Object.isNumber(insertions) || 1620 Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML))) 1621 insertions = {bottom:insertions}; 1622 1623 var content, insert, tagName, childNodes; 1624 1625 for (var position in insertions) { 1626 content = insertions[position]; 1627 position = position.toLowerCase(); 1628 insert = Element._insertionTranslations[position]; 1629 1630 if (content && content.toElement) content = content.toElement(); 1631 if (Object.isElement(content)) { 1632 insert(element, content); 1633 continue; 1634 } 1635 1636 content = Object.toHTML(content); 1637 1638 tagName = ((position == 'before' || position == 'after') 1639 ? element.parentNode : element).tagName.toUpperCase(); 1640 1641 childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); 1642 1643 if (position == 'top' || position == 'after') childNodes.reverse(); 1644 childNodes.each(insert.curry(element)); 1645 1646 content.evalScripts.bind(content).defer(); 1647 } 1648 1649 return element; 1650 }, 1651 1652 wrap: function(element, wrapper, attributes) { 1653 element = $(element); 1654 if (Object.isElement(wrapper)) 1655 $(wrapper).writeAttribute(attributes || { }); 1656 else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes); 1657 else wrapper = new Element('div', wrapper); 1658 if (element.parentNode) 1659 element.parentNode.replaceChild(wrapper, element); 1660 wrapper.appendChild(element); 1661 return wrapper; 1662 }, 1663 1664 inspect: function(element) { 1665 element = $(element); 1666 var result = '<' + element.tagName.toLowerCase(); 1667 $H({'id': 'id', 'className': 'class'}).each(function(pair) { 1668 var property = pair.first(), attribute = pair.last(); 1669 var value = (element[property] || '').toString(); 1670 if (value) result += ' ' + attribute + '=' + value.inspect(true); 1671 }); 1672 return result + '>'; 1673 }, 1674 1675 recursivelyCollect: function(element, property) { 1676 element = $(element); 1677 var elements = []; 1678 while (element = element[property]) 1679 if (element.nodeType == 1) 1680 elements.push(Element.extend(element)); 1681 return elements; 1682 }, 1683 1684 ancestors: function(element) { 1685 return $(element).recursivelyCollect('parentNode'); 1686 }, 1687 1688 descendants: function(element) { 1689 return $(element).select("*"); 1690 }, 1691 1692 firstDescendant: function(element) { 1693 element = $(element).firstChild; 1694 while (element && element.nodeType != 1) element = element.nextSibling; 1695 return $(element); 1696 }, 1697 1698 immediateDescendants: function(element) { 1699 if (!(element = $(element).firstChild)) return []; 1700 while (element && element.nodeType != 1) element = element.nextSibling; 1701 if (element) return [element].concat($(element).nextSiblings()); 1702 return []; 1703 }, 1704 1705 previousSiblings: function(element) { 1706 return $(element).recursivelyCollect('previousSibling'); 1707 }, 1708 1709 nextSiblings: function(element) { 1710 return $(element).recursivelyCollect('nextSibling'); 1711 }, 1712 1713 siblings: function(element) { 1714 element = $(element); 1715 return element.previousSiblings().reverse().concat(element.nextSiblings()); 1716 }, 1717 1718 match: function(element, selector) { 1719 if (Object.isString(selector)) 1720 selector = new Selector(selector); 1721 return selector.match($(element)); 1722 }, 1723 1724 up: function(element, expression, index) { 1725 element = $(element); 1726 if (arguments.length == 1) return $(element.parentNode); 1727 var ancestors = element.ancestors(); 1728 return Object.isNumber(expression) ? ancestors[expression] : 1729 Selector.findElement(ancestors, expression, index); 1730 }, 1731 1732 down: function(element, expression, index) { 1733 element = $(element); 1734 if (arguments.length == 1) return element.firstDescendant(); 1735 return Object.isNumber(expression) ? element.descendants()[expression] : 1736 element.select(expression)[index || 0]; 1737 }, 1738 1739 previous: function(element, expression, index) { 1740 element = $(element); 1741 if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); 1742 var previousSiblings = element.previousSiblings(); 1743 return Object.isNumber(expression) ? previousSiblings[expression] : 1744 Selector.findElement(previousSiblings, expression, index); 1745 }, 1746 1747 next: function(element, expression, index) { 1748 element = $(element); 1749 if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); 1750 var nextSiblings = element.nextSiblings(); 1751 return Object.isNumber(expression) ? nextSiblings[expression] : 1752 Selector.findElement(nextSiblings, expression, index); 1753 }, 1754 1755 select: function() { 1756 var args = $A(arguments), element = $(args.shift()); 1757 return Selector.findChildElements(element, args); 1758 }, 1759 1760 adjacent: function() { 1761 var args = $A(arguments), element = $(args.shift()); 1762 return Selector.findChildElements(element.parentNode, args).without(element); 1763 }, 1764 1765 identify: function(element) { 1766 element = $(element); 1767 var id = element.readAttribute('id'), self = arguments.callee; 1768 if (id) return id; 1769 do { id = 'anonymous_element_' + self.counter++ } while ($(id)); 1770 element.writeAttribute('id', id); 1771 return id; 1772 }, 1773 1774 readAttribute: function(element, name) { 1775 element = $(element); 1776 if (Prototype.Browser.IE) { 1777 var t = Element._attributeTranslations.read; 1778 if (t.values[name]) return t.values[name](element, name); 1779 if (t.names[name]) name = t.names[name]; 1780 if (name.include(':')) { 1781 return (!element.attributes || !element.attributes[name]) ? null : 1782 element.attributes[name].value; 1783 } 1784 } 1785 return element.getAttribute(name); 1786 }, 1787 1788 writeAttribute: function(element, name, value) { 1789 element = $(element); 1790 var attributes = { }, t = Element._attributeTranslations.write; 1791 1792 if (typeof name == 'object') attributes = name; 1793 else attributes[name] = Object.isUndefined(value) ? true : value; 1794 1795 for (var attr in attributes) { 1796 name = t.names[attr] || attr; 1797 value = attributes[attr]; 1798 if (t.values[attr]) name = t.values[attr](element, value); 1799 if (value === false || value === null) 1800 element.removeAttribute(name); 1801 else if (value === true) 1802 element.setAttribute(name, name); 1803 else element.setAttribute(name, value); 1804 } 1805 return element; 1806 }, 1807 1808 getHeight: function(element) { 1809 return $(element).getDimensions().height; 1810 }, 1811 1812 getWidth: function(element) { 1813 return $(element).getDimensions().width; 1814 }, 1815 1816 classNames: function(element) { 1817 return new Element.ClassNames(element); 1818 }, 1819 1820 hasClassName: function(element, className) { 1821 if (!(element = $(element))) return; 1822 var elementClassName = element.className; 1823 return (elementClassName.length > 0 && (elementClassName == className || 1824 new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName))); 1825 }, 1826 1827 addClassName: function(element, className) { 1828 if (!(element = $(element))) return; 1829 if (!element.hasClassName(className)) 1830 element.className += (element.className ? ' ' : '') + className; 1831 return element; 1832 }, 1833 1834 removeClassName: function(element, className) { 1835 if (!(element = $(element))) return; 1836 element.className = element.className.replace( 1837 new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip(); 1838 return element; 1839 }, 1840 1841 toggleClassName: function(element, className) { 1842 if (!(element = $(element))) return; 1843 return element[element.hasClassName(className) ? 1844 'removeClassName' : 'addClassName'](className); 1845 }, 1846 1847 // removes whitespace-only text node children 1848 cleanWhitespace: function(element) { 1849 element = $(element); 1850 var node = element.firstChild; 1851 while (node) { 1852 var nextNode = node.nextSibling; 1853 if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) 1854 element.removeChild(node); 1855 node = nextNode; 1856 } 1857 return element; 1858 }, 1859 1860 empty: function(element) { 1861 return $(element).innerHTML.blank(); 1862 }, 1863 1864 descendantOf: function(element, ancestor) { 1865 element = $(element), ancestor = $(ancestor); 1866 var originalAncestor = ancestor; 1867 1868 if (element.compareDocumentPosition) 1869 return (element.compareDocumentPosition(ancestor) & 8) === 8; 1870 1871 if (element.sourceIndex && !Prototype.Browser.Opera) { 1872 var e = element.sourceIndex, a = ancestor.sourceIndex, 1873 nextAncestor = ancestor.nextSibling; 1874 if (!nextAncestor) { 1875 do { ancestor = ancestor.parentNode; } 1876 while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode); 1877 } 1878 if (nextAncestor && nextAncestor.sourceIndex) 1879 return (e > a && e < nextAncestor.sourceIndex); 1880 } 1881 1882 while (element = element.parentNode) 1883 if (element == originalAncestor) return true; 1884 return false; 1885 }, 1886 1887 scrollTo: function(element) { 1888 element = $(element); 1889 var pos = element.cumulativeOffset(); 1890 window.scrollTo(pos[0], pos[1]); 1891 return element; 1892 }, 1893 1894 getStyle: function(element, style) { 1895 element = $(element); 1896 style = style == 'float' ? 'cssFloat' : style.camelize(); 1897 var value = element.style[style]; 1898 if (!value) { 1899 var css = document.defaultView.getComputedStyle(element, null); 1900 value = css ? css[style] : null; 1901 } 1902 if (style == 'opacity') return value ? parseFloat(value) : 1.0; 1903 return value == 'auto' ? null : value; 1904 }, 1905 1906 getOpacity: function(element) { 1907 return $(element).getStyle('opacity'); 1908 }, 1909 1910 setStyle: function(element, styles) { 1911 element = $(element); 1912 var elementStyle = element.style, match; 1913 if (Object.isString(styles)) { 1914 element.style.cssText += ';' + styles; 1915 return styles.include('opacity') ? 1916 element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element; 1917 } 1918 for (var property in styles) 1919 if (property == 'opacity') element.setOpacity(styles[property]); 1920 else 1921 elementStyle[(property == 'float' || property == 'cssFloat') ? 1922 (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') : 1923 property] = styles[property]; 1924 1925 return element; 1926 }, 1927 1928 setOpacity: function(element, value) { 1929 element = $(element); 1930 element.style.opacity = (value == 1 || value === '') ? '' : 1931 (value < 0.00001) ? 0 : value; 1932 return element; 1933 }, 1934 1935 getDimensions: function(element) { 1936 element = $(element); 1937 var display = $(element).getStyle('display'); 1938 if (display != 'none' && display != null) // Safari bug 1939 return {width: element.offsetWidth, height: element.offsetHeight}; 1940 1941 // All *Width and *Height properties give 0 on elements with display none, 1942 // so enable the element temporarily 1943 var els = element.style; 1944 var originalVisibility = els.visibility; 1945 var originalPosition = els.position; 1946 var originalDisplay = els.display; 1947 els.visibility = 'hidden'; 1948 els.position = 'absolute'; 1949 els.display = 'block'; 1950 var originalWidth = element.clientWidth; 1951 var originalHeight = element.clientHeight; 1952 els.display = originalDisplay; 1953 els.position = originalPosition; 1954 els.visibility = originalVisibility; 1955 return {width: originalWidth, height: originalHeight}; 1956 }, 1957 1958 makePositioned: function(element) { 1959 element = $(element); 1960 var pos = Element.getStyle(element, 'position'); 1961 if (pos == 'static' || !pos) { 1962 element._madePositioned = true; 1963 element.style.position = 'relative'; 1964 // Opera returns the offset relative to the positioning context, when an 1965 // element is position relative but top and left have not been defined 1966 if (window.opera) { 1967 element.style.top = 0; 1968 element.style.left = 0; 1969 } 1970 } 1971 return element; 1972 }, 1973 1974 undoPositioned: function(element) { 1975 element = $(element); 1976 if (element._madePositioned) { 1977 element._madePositioned = undefined; 1978 element.style.position = 1979 element.style.top = 1980 element.style.left = 1981 element.style.bottom = 1982 element.style.right = ''; 1983 } 1984 return element; 1985 }, 1986 1987 makeClipping: function(element) { 1988 element = $(element); 1989 if (element._overflow) return element; 1990 element._overflow = Element.getStyle(element, 'overflow') || 'auto'; 1991 if (element._overflow !== 'hidden') 1992 element.style.overflow = 'hidden'; 1993 return element; 1994 }, 1995 1996 undoClipping: function(element) { 1997 element = $(element); 1998 if (!element._overflow) return element; 1999 element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; 2000 element._overflow = null; 2001 return element; 2002 }, 2003 2004 cumulativeOffset: function(element) { 2005 var valueT = 0, valueL = 0; 2006 do { 2007 valueT += element.offsetTop || 0; 2008 valueL += element.offsetLeft || 0; 2009 element = element.offsetParent; 2010 } while (element); 2011 return Element._returnOffset(valueL, valueT); 2012 }, 2013 2014 positionedOffset: function(element) { 2015 var valueT = 0, valueL = 0; 2016 do { 2017 valueT += element.offsetTop || 0; 2018 valueL += element.offsetLeft || 0; 2019 element = element.offsetParent; 2020 if (element) { 2021 if (element.tagName == 'BODY') break; 2022 var p = Element.getStyle(element, 'position'); 2023 if (p !== 'static') break; 2024 } 2025 } while (element); 2026 return Element._returnOffset(valueL, valueT); 2027 }, 2028 2029 absolutize: function(element) { 2030 element = $(element); 2031 if (element.getStyle('position') == 'absolute') return; 2032 // Position.prepare(); // To be done manually by Scripty when it needs it. 2033 2034 var offsets = element.positionedOffset(); 2035 var top = offsets[1]; 2036 var left = offsets[0]; 2037 var width = element.clientWidth; 2038 var height = element.clientHeight; 2039 2040 element._originalLeft = left - parseFloat(element.style.left || 0); 2041 element._originalTop = top - parseFloat(element.style.top || 0); 2042 element._originalWidth = element.style.width; 2043 element._originalHeight = element.style.height; 2044 2045 element.style.position = 'absolute'; 2046 element.style.top = top + 'px'; 2047 element.style.left = left + 'px'; 2048 element.style.width = width + 'px'; 2049 element.style.height = height + 'px'; 2050 return element; 2051 }, 2052 2053 relativize: function(element) { 2054 element = $(element); 2055 if (element.getStyle('position') == 'relative') return; 2056 // Position.prepare(); // To be done manually by Scripty when it needs it. 2057 2058 element.style.position = 'relative'; 2059 var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); 2060 var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); 2061 2062 element.style.top = top + 'px'; 2063 element.style.left = left + 'px'; 2064 element.style.height = element._originalHeight; 2065 element.style.width = element._originalWidth; 2066 return element; 2067 }, 2068 2069 cumulativeScrollOffset: function(element) { 2070 var valueT = 0, valueL = 0; 2071 do { 2072 valueT += element.scrollTop || 0; 2073 valueL += element.scrollLeft || 0; 2074 element = element.parentNode; 2075 } while (element); 2076 return Element._returnOffset(valueL, valueT); 2077 }, 2078 2079 getOffsetParent: function(element) { 2080 if (element.offsetParent) return $(element.offsetParent); 2081 if (element == document.body) return $(element); 2082 2083 while ((element = element.parentNode) && element != document.body) 2084 if (Element.getStyle(element, 'position') != 'static') 2085 return $(element); 2086 2087 return $(document.body); 2088 }, 2089 2090 viewportOffset: function(forElement) { 2091 var valueT = 0, valueL = 0; 2092 2093 var element = forElement; 2094 do { 2095 valueT += element.offsetTop || 0; 2096 valueL += element.offsetLeft || 0; 2097 2098 // Safari fix 2099 if (element.offsetParent == document.body && 2100 Element.getStyle(element, 'position') == 'absolute') break; 2101 2102 } while (element = element.offsetParent); 2103 2104 element = forElement; 2105 do { 2106 if (!Prototype.Browser.Opera || element.tagName == 'BODY') { 2107 valueT -= element.scrollTop || 0; 2108 valueL -= element.scrollLeft || 0; 2109 } 2110 } while (element = element.parentNode); 2111 2112 return Element._returnOffset(valueL, valueT); 2113 }, 2114 2115 clonePosition: function(element, source) { 2116 var options = Object.extend({ 2117 setLeft: true, 2118 setTop: true, 2119 setWidth: true, 2120 setHeight: true, 2121 offsetTop: 0, 2122 offsetLeft: 0 2123 }, arguments[2] || { }); 2124 2125 // find page position of source 2126 source = $(source); 2127 var p = source.viewportOffset(); 2128 2129 // find coordinate system to use 2130 element = $(element); 2131 var delta = [0, 0]; 2132 var parent = null; 2133 // delta [0,0] will do fine with position: fixed elements, 2134 // position:absolute needs offsetParent deltas 2135 if (Element.getStyle(element, 'position') == 'absolute') { 2136 parent = element.getOffsetParent(); 2137 delta = parent.viewportOffset(); 2138 } 2139 2140 // correct by body offsets (fixes Safari) 2141 if (parent == document.body) { 2142 delta[0] -= document.body.offsetLeft; 2143 delta[1] -= document.body.offsetTop; 2144 } 2145 2146 // set position 2147 if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; 2148 if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; 2149 if (options.setWidth) element.style.width = source.offsetWidth + 'px'; 2150 if (options.setHeight) element.style.height = source.offsetHeight + 'px'; 2151 return element; 2152 } 2153}; 2154 2155Element.Methods.identify.counter = 1; 2156 2157Object.extend(Element.Methods, { 2158 getElementsBySelector: Element.Methods.select, 2159 childElements: Element.Methods.immediateDescendants 2160}); 2161 2162Element._attributeTranslations = { 2163 write: { 2164 names: { 2165 className: 'class', 2166 htmlFor: 'for' 2167 }, 2168 values: { } 2169 } 2170}; 2171 2172if (Prototype.Browser.Opera) { 2173 Element.Methods.getStyle = Element.Methods.getStyle.wrap( 2174 function(proceed, element, style) { 2175 switch (style) { 2176 case 'left': case 'top': case 'right': case 'bottom': 2177 if (proceed(element, 'position') === 'static') return null; 2178 case 'height': case 'width': 2179 // returns '0px' for hidden elements; we want it to return null 2180 if (!Element.visible(element)) return null; 2181 2182 // returns the border-box dimensions rather than the content-box 2183 // dimensions, so we subtract padding and borders from the value 2184 var dim = parseInt(proceed(element, style), 10); 2185 2186 if (dim !== element['offset' + style.capitalize()]) 2187 return dim + 'px'; 2188 2189 var properties; 2190 if (style === 'height') { 2191 properties = ['border-top-width', 'padding-top', 2192 'padding-bottom', 'border-bottom-width']; 2193 } 2194 else { 2195 properties = ['border-left-width', 'padding-left', 2196 'padding-right', 'border-right-width']; 2197 } 2198 return properties.inject(dim, function(memo, property) { 2199 var val = proceed(element, property); 2200 return val === null ? memo : memo - parseInt(val, 10); 2201 }) + 'px'; 2202 default: return proceed(element, style); 2203 } 2204 } 2205 ); 2206 2207 Element.Methods.readAttribute = Element.Methods.readAttribute.wrap( 2208 function(proceed, element, attribute) { 2209 if (attribute === 'title') return element.title; 2210 return proceed(element, attribute); 2211 } 2212 ); 2213} 2214 2215else if (Prototype.Browser.IE) { 2216 // IE doesn't report offsets correctly for static elements, so we change them 2217 // to "relative" to get the values, then change them back. 2218 Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( 2219 function(proceed, element) { 2220 element = $(element); 2221 var position = element.getStyle('position'); 2222 if (position !== 'static') return proceed(element); 2223 element.setStyle({ position: 'relative' }); 2224 var value = proceed(element); 2225 element.setStyle({ position: position }); 2226 return value; 2227 } 2228 ); 2229 2230 $w('positionedOffset viewportOffset').each(function(method) { 2231 Element.Methods[method] = Element.Methods[method].wrap( 2232 function(proceed, element) { 2233 element = $(element); 2234 var position = element.getStyle('position'); 2235 if (position !== 'static') return proceed(element); 2236 // Trigger hasLayout on the offset parent so that IE6 reports 2237 // accurate offsetTop and offsetLeft values for position: fixed. 2238 var offsetParent = element.getOffsetParent(); 2239 if (offsetParent && offsetParent.getStyle('position') === 'fixed') 2240 offsetParent.setStyle({ zoom: 1 }); 2241 element.setStyle({ position: 'relative' }); 2242 var value = proceed(element); 2243 element.setStyle({ position: position }); 2244 return value; 2245 } 2246 ); 2247 }); 2248 2249 Element.Methods.getStyle = function(element, style) { 2250 element = $(element); 2251 style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); 2252 var value = element.style[style]; 2253 if (!value && element.currentStyle) value = element.currentStyle[style]; 2254 2255 if (style == 'opacity') { 2256 if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) 2257 if (value[1]) return parseFloat(value[1]) / 100; 2258 return 1.0; 2259 } 2260 2261 if (value == 'auto') { 2262 if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) 2263 return element['offset' + style.capitalize()] + 'px'; 2264 return null; 2265 } 2266 return value; 2267 }; 2268 2269 Element.Methods.setOpacity = function(element, value) { 2270 function stripAlpha(filter){ 2271 return filter.replace(/alpha\([^\)]*\)/gi,''); 2272 } 2273 element = $(element); 2274 var currentStyle = element.currentStyle; 2275 if ((currentStyle && !currentStyle.hasLayout) || 2276 (!currentStyle && element.style.zoom == 'normal')) 2277 element.style.zoom = 1; 2278 2279 var filter = element.getStyle('filter'), style = element.style; 2280 if (value == 1 || value === '') { 2281 (filter = stripAlpha(filter)) ? 2282 style.filter = filter : style.removeAttribute('filter'); 2283 return element; 2284 } else if (value < 0.00001) value = 0; 2285 style.filter = stripAlpha(filter) + 2286 'alpha(opacity=' + (value * 100) + ')'; 2287 return element; 2288 }; 2289 2290 Element._attributeTranslations = { 2291 read: { 2292 names: { 2293 'class': 'className', 2294 'for': 'htmlFor' 2295 }, 2296 values: { 2297 _getAttr: function(element, attribute) { 2298 return element.getAttribute(attribute, 2); 2299 }, 2300 _getAttrNode: function(element, attribute) { 2301 var node = element.getAttributeNode(attribute); 2302 return node ? node.value : ""; 2303 }, 2304 _getEv: function(element, attribute) { 2305 attribute = element.getAttribute(attribute); 2306 return attribute ? attribute.toString().slice(23, -2) : null; 2307 }, 2308 _flag: function(element, attribute) { 2309 return $(element).hasAttribute(attribute) ? attribute : null; 2310 }, 2311 style: function(element) { 2312 return element.style.cssText.toLowerCase(); 2313 }, 2314 title: function(element) { 2315 return element.title; 2316 } 2317 } 2318 } 2319 }; 2320 2321 Element._attributeTranslations.write = { 2322 names: Object.extend({ 2323 cellpadding: 'cellPadding', 2324 cellspacing: 'cellSpacing' 2325 }, Element._attributeTranslations.read.names), 2326 values: { 2327 checked: function(element, value) { 2328 element.checked = !!value; 2329 }, 2330 2331 style: function(element, value) { 2332 element.style.cssText = value ? value : ''; 2333 } 2334 } 2335 }; 2336 2337 Element._attributeTranslations.has = {}; 2338 2339 $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + 2340 'encType maxLength readOnly longDesc').each(function(attr) { 2341 Element._attributeTranslations.write.names[attr.toLowerCase()] = attr; 2342 Element._attributeTranslations.has[attr.toLowerCase()] = attr; 2343 }); 2344 2345 (function(v) { 2346 Object.extend(v, { 2347 href: v._getAttr, 2348 src: v._getAttr, 2349 type: v._getAttr, 2350 action: v._getAttrNode, 2351 disabled: v._flag, 2352 checked: v._flag, 2353 readonly: v._flag, 2354 multiple: v._flag, 2355 onload: v._getEv, 2356 onunload: v._getEv, 2357 onclick: v._getEv, 2358 ondblclick: v._getEv, 2359 onmousedown: v._getEv, 2360 onmouseup: v._getEv, 2361 onmouseover: v._getEv, 2362 onmousemove: v._getEv, 2363 onmouseout: v._getEv, 2364 onfocus: v._getEv, 2365 onblur: v._getEv, 2366 onkeypress: v._getEv, 2367 onkeydown: v._getEv, 2368 onkeyup: v._getEv, 2369 onsubmit: v._getEv, 2370 onreset: v._getEv, 2371 onselect: v._getEv, 2372 onchange: v._getEv 2373 }); 2374 })(Element._attributeTranslations.read.values); 2375} 2376 2377else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { 2378 Element.Methods.setOpacity = function(element, value) { 2379 element = $(element); 2380 element.style.opacity = (value == 1) ? 0.999999 : 2381 (value === '') ? '' : (value < 0.00001) ? 0 : value; 2382 return element; 2383 }; 2384} 2385 2386else if (Prototype.Browser.WebKit) { 2387 Element.Methods.setOpacity = function(element, value) { 2388 element = $(element); 2389 element.style.opacity = (value == 1 || value === '') ? '' : 2390 (value < 0.00001) ? 0 : value; 2391 2392 if (value == 1) 2393 if(element.tagName == 'IMG' && element.width) { 2394 element.width++; element.width--; 2395 } else try { 2396 var n = document.createTextNode(' '); 2397 element.appendChild(n); 2398 element.removeChild(n); 2399 } catch (e) { } 2400 2401 return element; 2402 }; 2403 2404 // Safari returns margins on body which is incorrect if the child is absolutely 2405 // positioned. For performance reasons, redefine Element#cumulativeOffset for 2406 // KHTML/WebKit only. 2407 Element.Methods.cumulativeOffset = function(element) { 2408 var valueT = 0, valueL = 0; 2409 do { 2410 valueT += element.offsetTop || 0; 2411 valueL += element.offsetLeft || 0; 2412 if (element.offsetParent == document.body) 2413 if (Element.getStyle(element, 'position') == 'absolute') break; 2414 2415 element = element.offsetParent; 2416 } while (element); 2417 2418 return Element._returnOffset(valueL, valueT); 2419 }; 2420} 2421 2422if (Prototype.Browser.IE || Prototype.Browser.Opera) { 2423 // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements 2424 Element.Methods.update = function(element, content) { 2425 element = $(element); 2426 2427 if (content && content.toElement) content = content.toElement(); 2428 if (Object.isElement(content)) return element.update().insert(content); 2429 2430 content = Object.toHTML(content); 2431 var tagName = element.tagName.toUpperCase(); 2432 2433 if (tagName in Element._insertionTranslations.tags) { 2434 $A(element.childNodes).each(function(node) { element.removeChild(node) }); 2435 Element._getContentFromAnonymousElement(tagName, content.stripScripts()) 2436 .each(function(node) { element.appendChild(node) }); 2437 } 2438 else element.innerHTML = content.stripScripts(); 2439 2440 content.evalScripts.bind(content).defer(); 2441 return element; 2442 }; 2443} 2444 2445if ('outerHTML' in document.createElement('div')) { 2446 Element.Methods.replace = function(element, content) { 2447 element = $(element); 2448 2449 if (content && content.toElement) content = content.toElement(); 2450 if (Object.isElement(content)) { 2451 element.parentNode.replaceChild(content, element); 2452 return element; 2453 } 2454 2455 content = Object.toHTML(content); 2456 var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); 2457 2458 if (Element._insertionTranslations.tags[tagName]) { 2459 var nextSibling = element.next(); 2460 var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); 2461 parent.removeChild(element); 2462 if (nextSibling) 2463 fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); 2464 else 2465 fragments.each(function(node) { parent.appendChild(node) }); 2466 } 2467 else element.outerHTML = content.stripScripts(); 2468 2469 content.evalScripts.bind(content).defer(); 2470 return element; 2471 }; 2472} 2473 2474Element._returnOffset = function(l, t) { 2475 var result = [l, t]; 2476 result.left = l; 2477 result.top = t; 2478 return result; 2479}; 2480 2481Element._getContentFromAnonymousElement = function(tagName, html) { 2482 var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; 2483 if (t) { 2484 div.innerHTML = t[0] + html + t[1]; 2485 t[2].times(function() { div = div.firstChild }); 2486 } else div.innerHTML = html; 2487 return $A(div.childNodes); 2488}; 2489 2490Element._insertionTranslations = { 2491 before: function(element, node) { 2492 element.parentNode.insertBefore(node, element); 2493 }, 2494 top: function(element, node) { 2495 element.insertBefore(node, element.firstChild); 2496 }, 2497 bottom: function(element, node) { 2498 element.appendChild(node); 2499 }, 2500 after: function(element, node) { 2501 element.parentNode.insertBefore(node, element.nextSibling); 2502 }, 2503 tags: { 2504 TABLE: ['<table>', '</table>', 1], 2505 TBODY: ['<table><tbody>', '</tbody></table>', 2], 2506 TR: ['<table><tbody><tr>', '</tr></tbody></table>', 3], 2507 TD: ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4], 2508 SELECT: ['<select>', '</select>', 1] 2509 } 2510}; 2511 2512(function() { 2513 Object.extend(this.tags, { 2514 THEAD: this.tags.TBODY, 2515 TFOOT: this.tags.TBODY, 2516 TH: this.tags.TD 2517 }); 2518}).call(Element._insertionTranslations); 2519 2520Element.Methods.Simulated = { 2521 hasAttribute: function(element, attribute) { 2522 attribute = Element._attributeTranslations.has[attribute] || attribute; 2523 var node = $(element).getAttributeNode(attribute); 2524 return node && node.specified; 2525 } 2526}; 2527 2528Element.Methods.ByTag = { }; 2529 2530Object.extend(Element, Element.Methods); 2531 2532if (!Prototype.BrowserFeatures.ElementExtensions && 2533 document.createElement('div').__proto__) { 2534 window.HTMLElement = { }; 2535 window.HTMLElement.prototype = document.createElement('div').__proto__; 2536 Prototype.BrowserFeatures.ElementExtensions = true; 2537} 2538 2539Element.extend = (function() { 2540 if (Prototype.BrowserFeatures.SpecificElementExtensions) 2541 return Prototype.K; 2542 2543 var Methods = { }, ByTag = Element.Methods.ByTag; 2544 2545 var extend = Object.extend(function(element) { 2546 if (!element || element._extendedByPrototype || 2547 element.nodeType != 1 || element == window) return element; 2548 2549 var methods = Object.clone(Methods), 2550 tagName = element.tagName, property, value; 2551 2552 // extend methods for specific tags 2553 if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); 2554 2555 for (property in methods) { 2556 value = methods[property]; 2557 if (Object.isFunction(value) && !(property in element)) 2558 element[property] = value.methodize(); 2559 } 2560 2561 element._extendedByPrototype = Prototype.emptyFunction; 2562 return element; 2563 2564 }, { 2565 refresh: function() { 2566 // extend methods for all tags (Safari doesn't need this) 2567 if (!Prototype.BrowserFeatures.ElementExtensions) { 2568 Object.extend(Methods, Element.Methods); 2569 Object.extend(Methods, Element.Methods.Simulated); 2570 } 2571 } 2572 }); 2573 2574 extend.refresh(); 2575 return extend; 2576})(); 2577 2578Element.hasAttribute = function(element, attribute) { 2579 if (element.hasAttribute) return element.hasAttribute(attribute); 2580 return Element.Methods.Simulated.hasAttribute(element, attribute); 2581}; 2582 2583Element.addMethods = function(methods) { 2584 var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; 2585 2586 if (!methods) { 2587 Object.extend(Form, Form.Methods); 2588 Object.extend(Form.Element, Form.Element.Methods); 2589 Object.extend(Element.Methods.ByTag, { 2590 "FORM": Object.clone(Form.Methods), 2591 "INPUT": Object.clone(Form.Element.Methods), 2592 "SELECT": Object.clone(Form.Element.Methods), 2593 "TEXTAREA": Object.clone(Form.Element.Methods) 2594 }); 2595 } 2596 2597 if (arguments.length == 2) { 2598 var tagName = methods; 2599 methods = arguments[1]; 2600 } 2601 2602 if (!tagName) Object.extend(Element.Methods, methods || { }); 2603 else { 2604 if (Object.isArray(tagName)) tagName.each(extend); 2605 else extend(tagName); 2606 } 2607 2608 function extend(tagName) { 2609 tagName = tagName.toUpperCase(); 2610 if (!Element.Methods.ByTag[tagName]) 2611 Element.Methods.ByTag[tagName] = { }; 2612 Object.extend(Element.Methods.ByTag[tagName], methods); 2613 } 2614 2615 function copy(methods, destination, onlyIfAbsent) { 2616 onlyIfAbsent = onlyIfAbsent || false; 2617 for (var property in methods) { 2618 var value = methods[property]; 2619 if (!Object.isFunction(value)) continue; 2620 if (!onlyIfAbsent || !(property in destination)) 2621 destination[property] = value.methodize(); 2622 } 2623 } 2624 2625 function findDOMClass(tagName) { 2626 var klass; 2627 var trans = { 2628 "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", 2629 "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", 2630 "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", 2631 "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", 2632 "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": 2633 "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": 2634 "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": 2635 "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": 2636 "FrameSet", "IFRAME": "IFrame" 2637 }; 2638 if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; 2639 if (window[klass]) return window[klass]; 2640 klass = 'HTML' + tagName + 'Element'; 2641 if (window[klass]) return window[klass]; 2642 klass = 'HTML' + tagName.capitalize() + 'Element'; 2643 if (window[klass]) return window[klass]; 2644 2645 window[klass] = { }; 2646 window[klass].prototype = document.createElement(tagName).__proto__; 2647 return window[klass]; 2648 } 2649 2650 if (F.ElementExtensions) { 2651 copy(Element.Methods, HTMLElement.prototype); 2652 copy(Element.Methods.Simulated, HTMLElement.prototype, true); 2653 } 2654 2655 if (F.SpecificElementExtensions) { 2656 for (var tag in Element.Methods.ByTag) { 2657 var klass = findDOMClass(tag); 2658 if (Object.isUndefined(klass)) continue; 2659 copy(T[tag], klass.prototype); 2660 } 2661 } 2662 2663 Object.extend(Element, Element.Methods); 2664 delete Element.ByTag; 2665 2666 if (Element.extend.refresh) Element.extend.refresh(); 2667 Element.cache = { }; 2668}; 2669 2670document.viewport = { 2671 getDimensions: function() { 2672 var dimensions = { }; 2673 var B = Prototype.Browser; 2674 $w('width height').each(function(d) { 2675 var D = d.capitalize(); 2676 dimensions[d] = (B.WebKit && !document.evaluate) ? self['inner' + D] : 2677 (B.Opera) ? document.body['client' + D] : document.documentElement['client' + D]; 2678 }); 2679 return dimensions; 2680 }, 2681 2682 getWidth: function() { 2683 return this.getDimensions().width; 2684 }, 2685 2686 getHeight: function() { 2687 return this.getDimensions().height; 2688 }, 2689 2690 getScrollOffsets: function() { 2691 return Element._returnOffset( 2692 window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, 2693 window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); 2694 } 2695}; 2696/* Portions of the Selector class are derived from Jack Slocum’s DomQuery, 2697 * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style 2698 * license. Please see http://www.yui-ext.com/ for more information. */ 2699 2700var Selector = Class.create({ 2701 initialize: function(expression) { 2702 this.expression = expression.strip(); 2703 this.compileMatcher(); 2704 }, 2705 2706 shouldUseXPath: function() { 2707 if (!Prototype.BrowserFeatures.XPath) return false; 2708 2709 var e = this.expression; 2710 2711 // Safari 3 chokes on :*-of-type and :empty 2712 if (Prototype.Browser.WebKit && 2713 (e.include("-of-type") || e.include(":empty"))) 2714 return false; 2715 2716 // XPath can't do namespaced attributes, nor can it read 2717 // the "checked" property from DOM nodes 2718 if ((/(\[[\w-]*?:|:checked)/).test(this.expression)) 2719 return false; 2720 2721 return true; 2722 }, 2723 2724 compileMatcher: function() { 2725 if (this.shouldUseXPath()) 2726 return this.compileXPathMatcher(); 2727 2728 var e = this.expression, ps = Selector.patterns, h = Selector.handlers, 2729 c = Selector.criteria, le, p, m; 2730 2731 if (Selector._cache[e]) { 2732 this.matcher = Selector._cache[e]; 2733 return; 2734 } 2735 2736 this.matcher = ["this.matcher = function(root) {", 2737 "var r = root, h = Selector.handlers, c = false, n;"]; 2738 2739 while (e && le != e && (/\S/).test(e)) { 2740 le = e; 2741 for (var i in ps) { 2742 p = ps[i]; 2743 if (m = e.match(p)) { 2744 this.matcher.push(Object.isFunction(c[i]) ? c[i](m) : 2745 new Template(c[i]).evaluate(m)); 2746 e = e.replace(m[0], ''); 2747 break; 2748 } 2749 } 2750 } 2751 2752 this.matcher.push("return h.unique(n);\n}"); 2753 eval(this.matcher.join('\n')); 2754 Selector._cache[this.expression] = this.matcher; 2755 }, 2756 2757 compileXPathMatcher: function() { 2758 var e = this.expression, ps = Selector.patterns, 2759 x = Selector.xpath, le, m; 2760 2761 if (Selector._cache[e]) { 2762 this.xpath = Selector._cache[e]; return; 2763 } 2764 2765 this.matcher = ['.//*']; 2766 while (e && le != e && (/\S/).test(e)) { 2767 le = e; 2768 for (var i in ps) { 2769 if (m = e.match(ps[i])) { 2770 this.matcher.push(Object.isFunction(x[i]) ? x[i](m) : 2771 new Template(x[i]).evaluate(m)); 2772 e = e.replace(m[0], ''); 2773 break; 2774 } 2775 } 2776 } 2777 2778 this.xpath = this.matcher.join(''); 2779 Selector._cache[this.expression] = this.xpath; 2780 }, 2781 2782 findElements: function(root) { 2783 root = root || document; 2784 if (this.xpath) return document._getElementsByXPath(this.xpath, root); 2785 return this.matcher(root); 2786 }, 2787 2788 match: function(element) { 2789 this.tokens = []; 2790 2791 var e = this.expression, ps = Selector.patterns, as = Selector.assertions; 2792 var le, p, m; 2793 2794 while (e && le !== e && (/\S/).test(e)) { 2795 le = e; 2796 for (var i in ps) { 2797 p = ps[i]; 2798 if (m = e.match(p)) { 2799 // use the Selector.assertions methods unless the selector 2800 // is too complex. 2801 if (as[i]) { 2802 this.tokens.push([i, Object.clone(m)]); 2803 e = e.replace(m[0], ''); 2804 } else { 2805 // reluctantly do a document-wide search 2806 // and look for a match in the array 2807 return this.findElements(document).include(element); 2808 } 2809 } 2810 } 2811 } 2812 2813 var match = true, name, matches; 2814 for (var i = 0, token; token = this.tokens[i]; i++) { 2815 name = token[0], matches = token[1]; 2816 if (!Selector.assertions[name](element, matches)) { 2817 match = false; break; 2818 } 2819 } 2820 2821 return match; 2822 }, 2823 2824 toString: function() { 2825 return this.expression; 2826 }, 2827 2828 inspect: function() { 2829 return "#<Selector:" + this.expression.inspect() + ">"; 2830 } 2831}); 2832 2833Object.extend(Selector, { 2834 _cache: { }, 2835 2836 xpath: { 2837 descendant: "//*", 2838 child: "/*", 2839 adjacent: "/following-sibling::*[1]", 2840 laterSibling: '/following-sibling::*', 2841 tagName: function(m) { 2842 if (m[1] == '*') return ''; 2843 return "[local-name()='" + m[1].toLowerCase() + 2844 "' or local-name()='" + m[1].toUpperCase() + "']"; 2845 }, 2846 className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", 2847 id: "[@id='#{1}']", 2848 attrPresence: function(m) { 2849 m[1] = m[1].toLowerCase(); 2850 return new Template("[@#{1}]").evaluate(m); 2851 }, 2852 attr: function(m) { 2853 m[1] = m[1].toLowerCase(); 2854 m[3] = m[5] || m[6]; 2855 return new Template(Selector.xpath.operators[m[2]]).evaluate(m); 2856 }, 2857 pseudo: function(m) { 2858 var h = Selector.xpath.pseudos[m[1]]; 2859 if (!h) return ''; 2860 if (Object.isFunction(h)) return h(m); 2861 return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); 2862 }, 2863 operators: { 2864 '=': "[@#{1}='#{3}']", 2865 '!=': "[@#{1}!='#{3}']", 2866 '^=': "[starts-with(@#{1}, '#{3}')]", 2867 '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", 2868 '*=': "[contains(@#{1}, '#{3}')]", 2869 '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", 2870 '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" 2871 }, 2872 pseudos: { 2873 'first-child': '[not(preceding-sibling::*)]', 2874 'last-child': '[not(following-sibling::*)]', 2875 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', 2876 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]", 2877 'checked': "[@checked]", 2878 'disabled': "[@disabled]", 2879 'enabled': "[not(@disabled)]", 2880 'not': function(m) { 2881 var e = m[6], p = Selector.patterns, 2882 x = Selector.xpath, le, v; 2883 2884 var exclusion = []; 2885 while (e && le != e && (/\S/).test(e)) { 2886 le = e; 2887 for (var i in p) { 2888 if (m = e.match(p[i])) { 2889 v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m); 2890 exclusion.push("(" + v.substring(1, v.length - 1) + ")"); 2891 e = e.replace(m[0], ''); 2892 break; 2893 } 2894 } 2895 } 2896 return "[not(" + exclusion.join(" and ") + ")]"; 2897 }, 2898 'nth-child': function(m) { 2899 return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m); 2900 }, 2901 'nth-last-child': function(m) { 2902 return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m); 2903 }, 2904 'nth-of-type': function(m) { 2905 return Selector.xpath.pseudos.nth("position() ", m); 2906 }, 2907 'nth-last-of-type': function(m) { 2908 return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m); 2909 }, 2910 'first-of-type': function(m) { 2911 m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m); 2912 }, 2913 'last-of-type': function(m) { 2914 m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m); 2915 }, 2916 'only-of-type': function(m) { 2917 var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m); 2918 }, 2919 nth: function(fragment, m) { 2920 var mm, formula = m[6], predicate; 2921 if (formula == 'even') formula = '2n+0'; 2922 if (formula == 'odd') formula = '2n+1'; 2923 if (mm = formula.match(/^(\d+)$/)) // digit only 2924 return '[' + fragment + "= " + mm[1] + ']'; 2925 if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b 2926 if (mm[1] == "-") mm[1] = -1; 2927 var a = mm[1] ? Number(mm[1]) : 1; 2928 var b = mm[2] ? Number(mm[2]) : 0; 2929 predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " + 2930 "((#{fragment} - #{b}) div #{a} >= 0)]"; 2931 return new Template(predicate).evaluate({ 2932 fragment: fragment, a: a, b: b }); 2933 } 2934 } 2935 } 2936 }, 2937 2938 criteria: { 2939 tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;', 2940 className: 'n = h.className(n, r, "#{1}", c); c = false;', 2941 id: 'n = h.id(n, r, "#{1}", c); c = false;', 2942 attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;', 2943 attr: function(m) { 2944 m[3] = (m[5] || m[6]); 2945 return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m); 2946 }, 2947 pseudo: function(m) { 2948 if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); 2949 return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); 2950 }, 2951 descendant: 'c = "descendant";', 2952 child: 'c = "child";', 2953 adjacent: 'c = "adjacent";', 2954 laterSibling: 'c = "laterSibling";' 2955 }, 2956 2957 patterns: { 2958 // combinators must be listed first 2959 // (and descendant needs to be last combinator) 2960 laterSibling: /^\s*~\s*/, 2961 child: /^\s*>\s*/, 2962 adjacent: /^\s*\+\s*/, 2963 descendant: /^\s/, 2964 2965 // selectors follow 2966 tagName: /^\s*(\*|[\w\-]+)(\b|$)?/, 2967 id: /^#([\w\-\*]+)(\b|$)/, 2968 className: /^\.([\w\-\*]+)(\b|$)/, 2969 pseudo: 2970/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/, 2971 attrPresence: /^\[([\w]+)\]/, 2972 attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ 2973 }, 2974 2975 // for Selector.match and Element#match 2976 assertions: { 2977 tagName: function(element, matches) { 2978 return matches[1].toUpperCase() == element.tagName.toUpperCase(); 2979 }, 2980 2981 className: function(element, matches) { 2982 return Element.hasClassName(element, matches[1]); 2983 }, 2984 2985 id: function(element, matches) { 2986 return element.id === matches[1]; 2987 }, 2988 2989 attrPresence: function(element, matches) { 2990 return Element.hasAttribute(element, matches[1]); 2991 }, 2992 2993 attr: function(element, matches) { 2994 var nodeValue = Element.readAttribute(element, matches[1]); 2995 return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]); 2996 } 2997 }, 2998 2999 handlers: { 3000 // UTILITY FUNCTIONS 3001 // joins two collections 3002 concat: function(a, b) { 3003 for (var i = 0, node; node = b[i]; i++) 3004 a.push(node); 3005 return a; 3006 }, 3007 3008 // marks an array of nodes for counting 3009 mark: function(nodes) { 3010 var _true = Prototype.emptyFunction; 3011 for (var i = 0, node; node = nodes[i]; i++) 3012 node._countedByPrototype = _true; 3013 return nodes; 3014 }, 3015 3016 unmark: function(nodes) { 3017 for (var i = 0, node; node = nodes[i]; i++) 3018 node._countedByPrototype = undefined; 3019 return nodes; 3020 }, 3021 3022 // mark each child node with its position (for nth calls) 3023 // "ofType" flag indicates whether we're indexing for nth-of-type 3024 // rather than nth-child 3025 index: function(parentNode, reverse, ofType) { 3026 parentNode._countedByPrototype = Prototype.emptyFunction; 3027 if (reverse) { 3028 for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { 3029 var node = nodes[i]; 3030 if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; 3031 } 3032 } else { 3033 for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) 3034 if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; 3035 } 3036 }, 3037 3038 // filters out duplicates and extends all nodes 3039 unique: function(nodes) { 3040 if (nodes.length == 0) return nodes; 3041 var results = [], n; 3042 for (var i = 0, l = nodes.length; i < l; i++) 3043 if (!(n = nodes[i])._countedByPrototype) { 3044 n._countedByPrototype = Prototype.emptyFunction; 3045 results.push(Element.extend(n)); 3046 } 3047 return Selector.handlers.unmark(results); 3048 }, 3049 3050 // COMBINATOR FUNCTIONS 3051 descendant: function(nodes) { 3052 var h = Selector.handlers; 3053 for (var i = 0, results = [], node; node = nodes[i]; i++) 3054 h.concat(results, node.getElementsByTagName('*')); 3055 return results; 3056 }, 3057 3058 child: function(nodes) { 3059 var h = Selector.handlers; 3060 for (var i = 0, results = [], node; node = nodes[i]; i++) { 3061 for (var j = 0, child; child = node.childNodes[j]; j++) 3062 if (child.nodeType == 1 && child.tagName != '!') results.push(child); 3063 } 3064 return results; 3065 }, 3066 3067 adjacent: function(nodes) { 3068 for (var i = 0, results = [], node; node = nodes[i]; i++) { 3069 var next = this.nextElementSibling(node); 3070 if (next) results.push(next); 3071 } 3072 return results; 3073 }, 3074 3075 laterSibling: function(nodes) { 3076 var h = Selector.handlers; 3077 for (var i = 0, results = [], node; node = nodes[i]; i++) 3078 h.concat(results, Element.nextSiblings(node)); 3079 return results; 3080 }, 3081 3082 nextElementSibling: function(node) { 3083 while (node = node.nextSibling) 3084 if (node.nodeType == 1) return node; 3085 return null; 3086 }, 3087 3088 previousElementSibling: function(node) { 3089 while (node = node.previousSibling) 3090 if (node.nodeType == 1) return node; 3091 return null; 3092 }, 3093 3094 // TOKEN FUNCTIONS 3095 tagName: function(nodes, root, tagName, combinator) { 3096 var uTagName = tagName.toUpperCase(); 3097 var results = [], h = Selector.handlers; 3098 if (nodes) { 3099 if (combinator) { 3100 // fastlane for ordinary descendant combinators 3101 if (combinator == "descendant") { 3102 for (var i = 0, node; node = nodes[i]; i++) 3103 h.concat(results, node.getElementsByTagName(tagName)); 3104 return results; 3105 } else nodes = this[combinator](nodes); 3106 if (tagName == "*") return nodes; 3107 } 3108 for (var i = 0, node; node = nodes[i]; i++) 3109 if (node.tagName.toUpperCase() === uTagName) results.push(node); 3110 return results; 3111 } else return root.getElementsByTagName(tagName); 3112 }, 3113 3114 id: function(nodes, root, id, combinator) { 3115 var targetNode = $(id), h = Selector.handlers; 3116 if (!targetNode) return []; 3117 if (!nodes && root == document) return [targetNode]; 3118 if (nodes) { 3119 if (combinator) { 3120 if (combinator == 'child') { 3121 for (var i = 0, node; node = nodes[i]; i++) 3122 if (targetNode.parentNode == node) return [targetNode]; 3123 } else if (combinator == 'descendant') { 3124 for (var i = 0, node; node = nodes[i]; i++) 3125 if (Element.descendantOf(targetNode, node)) return [targetNode]; 3126 } else if (combinator == 'adjacent') { 3127 for (var i = 0, node; node = nodes[i]; i++) 3128 if (Selector.handlers.previousElementSibling(targetNode) == node) 3129 return [targetNode]; 3130 } else nodes = h[combinator](nodes); 3131 } 3132 for (var i = 0, node; node = nodes[i]; i++) 3133 if (node == targetNode) return [targetNode]; 3134 return []; 3135 } 3136 return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; 3137 }, 3138 3139 className: function(nodes, root, className, combinator) { 3140 if (nodes && combinator) nodes = this[combinator](nodes); 3141 return Selector.handlers.byClassName(nodes, root, className); 3142 }, 3143 3144 byClassName: function(nodes, root, className) { 3145 if (!nodes) nodes = Selector.handlers.descendant([root]); 3146 var needle = ' ' + className + ' '; 3147 for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { 3148 nodeClassName = node.className; 3149 if (nodeClassName.length == 0) continue; 3150 if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle)) 3151 results.push(node); 3152 } 3153 return results; 3154 }, 3155 3156 attrPresence: function(nodes, root, attr, combinator) { 3157 if (!nodes) nodes = root.getElementsByTagName("*"); 3158 if (nodes && combinator) nodes = this[combinator](nodes); 3159 var results = []; 3160 for (var i = 0, node; node = nodes[i]; i++) 3161 if (Element.hasAttribute(node, attr)) results.push(node); 3162 return results; 3163 }, 3164 3165 attr: function(nodes, root, attr, value, operator, combinator) { 3166 if (!nodes) nodes = root.getElementsByTagName("*"); 3167 if (nodes && combinator) nodes = this[combinator](nodes); 3168 var handler = Selector.operators[operator], results = []; 3169 for (var i = 0, node; node = nodes[i]; i++) { 3170 var nodeValue = Element.readAttribute(node, attr); 3171 if (nodeValue === null) continue; 3172 if (handler(nodeValue, value)) results.push(node); 3173 } 3174 return results; 3175 }, 3176 3177 pseudo: function(nodes, name, value, root, combinator) { 3178 if (nodes && combinator) nodes = this[combinator](nodes); 3179 if (!nodes) nodes = root.getElementsByTagName("*"); 3180 return Selector.pseudos[name](nodes, value, root); 3181 } 3182 }, 3183 3184 pseudos: { 3185 'first-child': function(nodes, value, root) { 3186 for (var i = 0, results = [], node; node = nodes[i]; i++) { 3187 if (Selector.handlers.previousElementSibling(node)) continue; 3188 results.push(node); 3189 } 3190 return results; 3191 }, 3192 'last-child': function(nodes, value, root) { 3193 for (var i = 0, results = [], node; node = nodes[i]; i++) { 3194 if (Selector.handlers.nextElementSibling(node)) continue; 3195 results.push(node); 3196 } 3197 return results; 3198 }, 3199 'only-child': function(nodes, value, root) { 3200 var h = Selector.handlers; 3201 for (var i = 0, results = [], node; node = nodes[i]; i++) 3202 if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) 3203 results.push(node); 3204 return results; 3205 }, 3206 'nth-child': function(nodes, formula, root) { 3207 return Selector.pseudos.nth(nodes, formula, root); 3208 }, 3209 'nth-last-child': function(nodes, formula, root) { 3210 return Selector.pseudos.nth(nodes, formula, root, true); 3211 }, 3212 'nth-of-type': function(nodes, formula, root) { 3213 return Selector.pseudos.nth(nodes, formula, root, false, true); 3214 }, 3215 'nth-last-of-type': function(nodes, formula, root) { 3216 return Selector.pseudos.nth(nodes, formula, root, true, true); 3217 }, 3218 'first-of-type': function(nodes, formula, root) { 3219 return Selector.pseudos.nth(nodes, "1", root, false, true); 3220 }, 3221 'last-of-type': function(nodes, formula, root) { 3222 return Selector.pseudos.nth(nodes, "1", root, true, true); 3223 }, 3224 'only-of-type': function(nodes, formula, root) { 3225 var p = Selector.pseudos; 3226 return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); 3227 }, 3228 3229 // handles the an+b logic 3230 getIndices: function(a, b, total) { 3231 if (a == 0) return b > 0 ? [b] : []; 3232 return $R(1, total).inject([], function(memo, i) { 3233 if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); 3234 return memo; 3235 }); 3236 }, 3237 3238 // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type 3239 nth: function(nodes, formula, root, reverse, ofType) { 3240 if (nodes.length == 0) return []; 3241 if (formula == 'even') formula = '2n+0'; 3242 if (formula == 'odd') formula = '2n+1'; 3243 var h = Selector.handlers, results = [], indexed = [], m; 3244 h.mark(nodes); 3245 for (var i = 0, node; node = nodes[i]; i++) { 3246 if (!node.parentNode._countedByPrototype) { 3247 h.index(node.parentNode, reverse, ofType); 3248 indexed.push(node.parentNode); 3249 } 3250 } 3251 if (formula.match(/^\d+$/)) { // just a number 3252 formula = Number(formula); 3253 for (var i = 0, node; node = nodes[i]; i++) 3254 if (node.nodeIndex == formula) results.push(node); 3255 } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b 3256 if (m[1] == "-") m[1] = -1; 3257 var a = m[1] ? Number(m[1]) : 1; 3258 var b = m[2] ? Number(m[2]) : 0; 3259 var indices = Selector.pseudos.getIndices(a, b, nodes.length); 3260 for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { 3261 for (var j = 0; j < l; j++) 3262 if (node.nodeIndex == indices[j]) results.push(node); 3263 } 3264 } 3265 h.unmark(nodes); 3266 h.unmark(indexed); 3267 return results; 3268 }, 3269 3270 'empty': function(nodes, value, root) { 3271 for (var i = 0, results = [], node; node = nodes[i]; i++) { 3272 // IE treats comments as element nodes 3273 if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue; 3274 results.push(node); 3275 } 3276 return results; 3277 }, 3278 3279 'not': function(nodes, selector, root) { 3280 var h = Selector.handlers, selectorType, m; 3281 var exclusions = new Selector(selector).findElements(root); 3282 h.mark(exclusions); 3283 for (var i = 0, results = [], node; node = nodes[i]; i++) 3284 if (!node._countedByPrototype) results.push(node); 3285 h.unmark(exclusions); 3286 return results; 3287 }, 3288 3289 'enabled': function(nodes, value, root) { 3290 for (var i = 0, results = [], node; node = nodes[i]; i++) 3291 if (!node.disabled) results.push(node); 3292 return results; 3293 }, 3294 3295 'disabled': function(nodes, value, root) { 3296 for (var i = 0, results = [], node; node = nodes[i]; i++) 3297 if (node.disabled) results.push(node); 3298 return results; 3299 }, 3300 3301 'checked': function(nodes, value, root) { 3302 for (var i = 0, results = [], node; node = nodes[i]; i++) 3303 if (node.checked) results.push(node); 3304 return results; 3305 } 3306 }, 3307 3308 operators: { 3309 '=': function(nv, v) { return nv == v; }, 3310 '!=': function(nv, v) { return nv != v; }, 3311 '^=': function(nv, v) { return nv.startsWith(v); }, 3312 '$=': function(nv, v) { return nv.endsWith(v); }, 3313 '*=': function(nv, v) { return nv.include(v); }, 3314 '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, 3315 '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); } 3316 }, 3317 3318 split: function(expression) { 3319 var expressions = []; 3320 expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { 3321 expressions.push(m[1].strip()); 3322 }); 3323 return expressions; 3324 }, 3325 3326 matchElements: function(elements, expression) { 3327 var matches = $$(expression), h = Selector.handlers; 3328 h.mark(matches); 3329 for (var i = 0, results = [], element; element = elements[i]; i++) 3330 if (element._countedByPrototype) results.push(element); 3331 h.unmark(matches); 3332 return results; 3333 }, 3334 3335 findElement: function(elements, expression, index) { 3336 if (Object.isNumber(expression)) { 3337 index = expression; expression = false; 3338 } 3339 return Selector.matchElements(elements, expression || '*')[index || 0]; 3340 }, 3341 3342 findChildElements: function(element, expressions) { 3343 expressions = Selector.split(expressions.join(',')); 3344 var results = [], h = Selector.handlers; 3345 for (var i = 0, l = expressions.length, selector; i < l; i++) { 3346 selector = new Selector(expressions[i].strip()); 3347 h.concat(results, selector.findElements(element)); 3348 } 3349 return (l > 1) ? h.unique(results) : results; 3350 } 3351}); 3352 3353if (Prototype.Browser.IE) { 3354 Object.extend(Selector.handlers, { 3355 // IE returns comment nodes on getElementsByTagName("*"). 3356 // Filter them out. 3357 concat: function(a, b) { 3358 for (var i = 0, node; node = b[i]; i++) 3359 if (node.tagName !== "!") a.push(node); 3360 return a; 3361 }, 3362 3363 // IE improperly serializes _countedByPrototype in (inner|outer)HTML. 3364 unmark: function(nodes) { 3365 for (var i = 0, node; node = nodes[i]; i++) 3366 node.removeAttribute('_countedByPrototype'); 3367 return nodes; 3368 } 3369 }); 3370} 3371 3372function $$() { 3373 return Selector.findChildElements(document, $A(arguments)); 3374} 3375var Form = { 3376 reset: function(form) { 3377 $(form).reset(); 3378 return form; 3379 }, 3380 3381 serializeElements: function(elements, options) { 3382 if (typeof options != 'object') options = { hash: !!options }; 3383 else if (Object.isUndefined(options.hash)) options.hash = true; 3384 var key, value, submitted = false, submit = options.submit; 3385 3386 var data = elements.inject({ }, function(result, element) { 3387 if (!element.disabled && element.name) { 3388 key = element.name; value = $(element).getValue(); 3389 if (value != null && (element.type != 'submit' || (!submitted && 3390 submit !== false && (!submit || key == submit) && (submitted = true)))) { 3391 if (key in result) { 3392 // a key is already present; construct an array of values 3393 if (!Object.isArray(result[key])) result[key] = [result[key]]; 3394 result[key].push(value); 3395 } 3396 else result[key] = value; 3397 } 3398 } 3399 return result; 3400 }); 3401 3402 return options.hash ? data : Object.toQueryString(data); 3403 } 3404}; 3405 3406Form.Methods = { 3407 serialize: function(form, options) { 3408 return Form.serializeElements(Form.getElements(form), options); 3409 }, 3410 3411 getElements: function(form) { 3412 return $A($(form).getElementsByTagName('*')).inject([], 3413 function(elements, child) { 3414 if (Form.Element.Serializers[child.tagName.toLowerCase()]) 3415 elements.push(Element.extend(child)); 3416 return elements; 3417 } 3418 ); 3419 }, 3420 3421 getInputs: function(form, typeName, name) { 3422 form = $(form); 3423 var inputs = form.getElementsByTagName('input'); 3424 3425 if (!typeName && !name) return $A(inputs).map(Element.extend); 3426 3427 for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { 3428 var input = inputs[i]; 3429 if ((typeName && input.type != typeName) || (name && input.name != name)) 3430 continue; 3431 matchingInputs.push(Element.extend(input)); 3432 } 3433 3434 return matchingInputs; 3435 }, 3436 3437 disable: function(form) { 3438 form = $(form); 3439 Form.getElements(form).invoke('disable'); 3440 return form; 3441 }, 3442 3443 enable: function(form) { 3444 form = $(form); 3445 Form.getElements(form).invoke('enable'); 3446 return form; 3447 }, 3448 3449 findFirstElement: function(form) { 3450 var elements = $(form).getElements().findAll(function(element) { 3451 return 'hidden' != element.type && !element.disabled; 3452 }); 3453 var firstByIndex = elements.findAll(function(element) { 3454 return element.hasAttribute('tabIndex') && element.tabIndex >= 0; 3455 }).sortBy(function(element) { return element.tabIndex }).first(); 3456 3457 return firstByIndex ? firstByIndex : elements.find(function(element) { 3458 return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); 3459 }); 3460 }, 3461 3462 focusFirstElement: function(form) { 3463 form = $(form); 3464 form.findFirstElement().activate(); 3465 return form; 3466 }, 3467 3468 request: function(form, options) { 3469 form = $(form), options = Object.clone(options || { }); 3470 3471 var params = options.parameters, action = form.readAttribute('action') || ''; 3472 if (action.blank()) action = window.location.href; 3473 options.parameters = form.serialize(true); 3474 3475 if (params) { 3476 if (Object.isString(params)) params = params.toQueryParams(); 3477 Object.extend(options.parameters, params); 3478 } 3479 3480 if (form.hasAttribute('method') && !options.method) 3481 options.method = form.method; 3482 3483 return new Ajax.Request(action, options); 3484 } 3485}; 3486 3487/*--------------------------------------------------------------------------*/ 3488 3489Form.Element = { 3490 focus: function(element) { 3491 $(element).focus(); 3492 return element; 3493 }, 3494 3495 select: function(element) { 3496 $(element).select(); 3497 return element; 3498 } 3499}; 3500 3501Form.Element.Methods = { 3502 serialize: function(element) { 3503 element = $(element); 3504 if (!element.disabled && element.name) { 3505 var value = element.getValue(); 3506 if (value != undefined) { 3507 var pair = { }; 3508 pair[element.name] = value; 3509 return Object.toQueryString(pair); 3510 } 3511 } 3512 return ''; 3513 }, 3514 3515 getValue: function(element) { 3516 element = $(element); 3517 var method = element.tagName.toLowerCase(); 3518 return Form.Element.Serializers[method](element); 3519 }, 3520 3521 setValue: function(element, value) { 3522 element = $(element); 3523 var method = element.tagName.toLowerCase(); 3524 Form.Element.Serializers[method](element, value); 3525 return element; 3526 }, 3527 3528 clear: function(element) { 3529 $(element).value = ''; 3530 return element; 3531 }, 3532 3533 present: function(element) { 3534 return $(element).value != ''; 3535 }, 3536 3537 activate: function(element) { 3538 element = $(element); 3539 try { 3540 element.focus(); 3541 if (element.select && (element.tagName.toLowerCase() != 'input' || 3542 !['button', 'reset', 'submit'].include(element.type))) 3543 element.select(); 3544 } catch (e) { } 3545 return element; 3546 }, 3547 3548 disable: function(element) { 3549 element = $(element); 3550 element.blur(); 3551 element.disabled = true; 3552 return element; 3553 }, 3554 3555 enable: function(element) { 3556 element = $(element); 3557 element.disabled = false; 3558 return element; 3559 } 3560}; 3561 3562/*--------------------------------------------------------------------------*/ 3563 3564var Field = Form.Element; 3565var $F = Form.Element.Methods.getValue; 3566 3567/*--------------------------------------------------------------------------*/ 3568 3569Form.Element.Serializers = { 3570 input: function(element, value) { 3571 switch (element.type.toLowerCase()) { 3572 case 'checkbox': 3573 case 'radio': 3574 return Form.Element.Serializers.inputSelector(element, value); 3575 default: 3576 return Form.Element.Serializers.textarea(element, value); 3577 } 3578 }, 3579 3580 inputSelector: function(element, value) { 3581 if (Object.isUndefined(value)) return element.checked ? element.value : null; 3582 else element.checked = !!value; 3583 }, 3584 3585 textarea: function(element, value) { 3586 if (Object.isUndefined(value)) return element.value; 3587 else element.value = value; 3588 }, 3589 3590 select: function(element, index) { 3591 if (Object.isUndefined(index)) 3592 return this[element.type == 'select-one' ? 3593 'selectOne' : 'selectMany'](element); 3594 else { 3595 var opt, value, single = !Object.isArray(index); 3596 for (var i = 0, length = element.length; i < length; i++) { 3597 opt = element.options[i]; 3598 value = this.optionValue(opt); 3599 if (single) { 3600 if (value == index) { 3601 opt.selected = true; 3602 return; 3603 } 3604 } 3605 else opt.selected = index.include(value); 3606 } 3607 } 3608 }, 3609 3610 selectOne: function(element) { 3611 var index = element.selectedIndex; 3612 return index >= 0 ? this.optionValue(element.options[index]) : null; 3613 }, 3614 3615 selectMany: function(element) { 3616 var values, length = element.length; 3617 if (!length) return null; 3618 3619 for (var i = 0, values = []; i < length; i++) { 3620 var opt = element.options[i]; 3621 if (opt.selected) values.push(this.optionValue(opt)); 3622 } 3623 return values; 3624 }, 3625 3626 optionValue: function(opt) { 3627 // extend element because hasAttribute may not be native 3628 return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; 3629 } 3630}; 3631 3632/*--------------------------------------------------------------------------*/ 3633 3634Abstract.TimedObserver = Class.create(PeriodicalExecuter, { 3635 initialize: function($super, element, frequency, callback) { 3636 $super(callback, frequency); 3637 this.element = $(element); 3638 this.lastValue = this.getValue(); 3639 }, 3640 3641 execute: function() { 3642 var value = this.getValue(); 3643 if (Object.isString(this.lastValue) && Object.isString(value) ? 3644 this.lastValue != value : String(this.lastValue) != String(value)) { 3645 this.callback(this.element, value); 3646 this.lastValue = value; 3647 } 3648 } 3649}); 3650 3651Form.Element.Observer = Class.create(Abstract.TimedObserver, { 3652 getValue: function() { 3653 return Form.Element.getValue(this.element); 3654 } 3655}); 3656 3657Form.Observer = Class.create(Abstract.TimedObserver, { 3658 getValue: function() { 3659 return Form.serialize(this.element); 3660 } 3661}); 3662 3663/*--------------------------------------------------------------------------*/ 3664 3665Abstract.EventObserver = Class.create({ 3666 initialize: function(element, callback) { 3667 this.element = $(element); 3668 this.callback = callback; 3669 3670 this.lastValue = this.getValue(); 3671 if (this.element.tagName.toLowerCase() == 'form') 3672 this.registerFormCallbacks(); 3673 else 3674 this.registerCallback(this.element); 3675 }, 3676 3677 onElementEvent: function() { 3678 var value = this.getValue(); 3679 if (this.lastValue != value) { 3680 this.callback(this.element, value); 3681 this.lastValue = value; 3682 } 3683 }, 3684 3685 registerFormCallbacks: function() { 3686 Form.getElements(this.element).each(this.registerCallback, this); 3687 }, 3688 3689 registerCallback: function(element) { 3690 if (element.type) { 3691 switch (element.type.toLowerCase()) { 3692 case 'checkbox': 3693 case 'radio': 3694 Event.observe(element, 'click', this.onElementEvent.bind(this)); 3695 break; 3696 default: 3697 Event.observe(element, 'change', this.onElementEvent.bind(this)); 3698 break; 3699 } 3700 } 3701 } 3702}); 3703 3704Form.Element.EventObserver = Class.create(Abstract.EventObserver, { 3705 getValue: function() { 3706 return Form.Element.getValue(this.element); 3707 } 3708}); 3709 3710Form.EventObserver = Class.create(Abstract.EventObserver, { 3711 getValue: function() { 3712 return Form.serialize(this.element); 3713 } 3714}); 3715if (!window.Event) var Event = { }; 3716 3717Object.extend(Event, { 3718 KEY_BACKSPACE: 8, 3719 KEY_TAB: 9, 3720 KEY_RETURN: 13, 3721 KEY_ESC: 27, 3722 KEY_LEFT: 37, 3723 KEY_UP: 38, 3724 KEY_RIGHT: 39, 3725 KEY_DOWN: 40, 3726 KEY_DELETE: 46, 3727 KEY_HOME: 36, 3728 KEY_END: 35, 3729 KEY_PAGEUP: 33, 3730 KEY_PAGEDOWN: 34, 3731 KEY_INSERT: 45, 3732 3733 cache: { }, 3734 3735 relatedTarget: function(event) { 3736 var element; 3737 switch(event.type) { 3738 case 'mouseover': element = event.fromElement; break; 3739 case 'mouseout': element = event.toElement; break; 3740 default: return null; 3741 } 3742 return Element.extend(element); 3743 } 3744}); 3745 3746Event.Methods = (function() { 3747 var isButton; 3748 3749 if (Prototype.Browser.IE) { 3750 var buttonMap = { 0: 1, 1: 4, 2: 2 }; 3751 isButton = function(event, code) { 3752 return event.button == buttonMap[code]; 3753 }; 3754 3755 } else if (Prototype.Browser.WebKit) { 3756 isButton = function(event, code) { 3757 switch (code) { 3758 case 0: return event.which == 1 && !event.metaKey; 3759 case 1: return event.which == 1 && event.metaKey; 3760 default: return false; 3761 } 3762 }; 3763 3764 } else { 3765 isButton = function(event, code) { 3766 return event.which ? (event.which === code + 1) : (event.button === code); 3767 }; 3768 } 3769 3770 return { 3771 isLeftClick: function(event) { return isButton(event, 0) }, 3772 isMiddleClick: function(event) { return isButton(event, 1) }, 3773 isRightClick: function(event) { return isButton(event, 2) }, 3774 3775 element: function(event) { 3776 var node = Event.extend(event).target; 3777 return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node); 3778 }, 3779 3780 findElement: function(event, expression) { 3781 var element = Event.element(event); 3782 if (!expression) return element; 3783 var elements = [element].concat(element.ancestors()); 3784 return Selector.findElement(elements, expression, 0); 3785 }, 3786 3787 pointer: function(event) { 3788 return { 3789 x: event.pageX || (event.clientX + 3790 (document.documentElement.scrollLeft || document.body.scrollLeft)), 3791 y: event.pageY || (event.clientY + 3792 (document.documentElement.scrollTop || document.body.scrollTop)) 3793 }; 3794 }, 3795 3796 pointerX: function(event) { return Event.pointer(event).x }, 3797 pointerY: function(event) { return Event.pointer(event).y }, 3798 3799 stop: function(event) { 3800 Event.extend(event); 3801 event.preventDefault(); 3802 event.stopPropagation(); 3803 event.stopped = true; 3804 } 3805 }; 3806})(); 3807 3808Event.extend = (function() { 3809 var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { 3810 m[name] = Event.Methods[name].methodize(); 3811 return m; 3812 }); 3813 3814 if (Prototype.Browser.IE) { 3815 Object.extend(methods, { 3816 stopPropagation: function() { this.cancelBubble = true }, 3817 preventDefault: function() { this.returnValue = false }, 3818 inspect: function() { return "[object Event]" } 3819 }); 3820 3821 return function(event) { 3822 if (!event) return false; 3823 if (event._extendedByPrototype) return event; 3824 3825 event._extendedByPrototype = Prototype.emptyFunction; 3826 var pointer = Event.pointer(event); 3827 Object.extend(event, { 3828 target: event.srcElement, 3829 relatedTarget: Event.relatedTarget(event), 3830 pageX: pointer.x, 3831 pageY: pointer.y 3832 }); 3833 return Object.extend(event, methods); 3834 }; 3835 3836 } else { 3837 Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__; 3838 Object.extend(Event.prototype, methods); 3839 return Prototype.K; 3840 } 3841})(); 3842 3843Object.extend(Event, (function() { 3844 var cache = Event.cache; 3845 3846 function getEventID(element) { 3847 if (element._prototypeEventID) return element._prototypeEventID[0]; 3848 arguments.callee.id = arguments.callee.id || 1; 3849 return element._prototypeEventID = [++arguments.callee.id]; 3850 } 3851 3852 function getDOMEventName(eventName) { 3853 if (eventName && eventName.include(':')) return "dataavailable"; 3854 return eventName; 3855 } 3856 3857 function getCacheForID(id) { 3858 return cache[id] = cache[id] || { }; 3859 } 3860 3861 function getWrappersForEventName(id, eventName) { 3862 var c = getCacheForID(id); 3863 return c[eventName] = c[eventName] || []; 3864 } 3865 3866 function createWrapper(element, eventName, handler) { 3867 var id = getEventID(element); 3868 var c = getWrappersForEventName(id, eventName); 3869 if (c.pluck("handler").include(handler)) return false; 3870 3871 var wrapper = function(event) { 3872 if (!Event || !Event.extend || 3873 (event.eventName && event.eventName != eventName)) 3874 return false; 3875 3876 Event.extend(event); 3877 handler.call(element, event); 3878 }; 3879 3880 wrapper.handler = handler; 3881 c.push(wrapper); 3882 return wrapper; 3883 } 3884 3885 function findWrapper(id, eventName, handler) { 3886 var c = getWrappersForEventName(id, eventName); 3887 return c.find(function(wrapper) { return wrapper.handler == handler }); 3888 } 3889 3890 function destroyWrapper(id, eventName, handler) { 3891 var c = getCacheForID(id); 3892 if (!c[eventName]) return false; 3893 c[eventName] = c[eventName].without(findWrapper(id, eventName, handler)); 3894 } 3895 3896 function destroyCache() { 3897 for (var id in cache) 3898 for (var eventName in cache[id]) 3899 cache[id][eventName] = null; 3900 } 3901 3902 if (window.attachEvent) { 3903 window.attachEvent("onunload", destroyCache); 3904 } 3905 3906 return { 3907 observe: function(element, eventName, handler) { 3908 element = $(element); 3909 var name = getDOMEventName(eventName); 3910 3911 var wrapper = createWrapper(element, eventName, handler); 3912 if (!wrapper) return element; 3913 3914 if (element.addEventListener) { 3915 element.addEventListener(name, wrapper, false); 3916 } else { 3917 element.attachEvent("on" + name, wrapper); 3918 } 3919 3920 return element; 3921 }, 3922 3923 stopObserving: function(element, eventName, handler) { 3924 element = $(element); 3925 var id = getEventID(element), name = getDOMEventName(eventName); 3926 3927 if (!handler && eventName) { 3928 getWrappersForEventName(id, eventName).each(function(wrapper) { 3929 element.stopObserving(eventName, wrapper.handler); 3930 }); 3931 return element; 3932 3933 } else if (!eventName) { 3934 Object.keys(getCacheForID(id)).each(function(eventName) { 3935 element.stopObserving(eventName); 3936 }); 3937 return element; 3938 } 3939 3940 var wrapper = findWrapper(id, eventName, handler); 3941 if (!wrapper) return element; 3942 3943 if (element.removeEventListener) { 3944 element.removeEventListener(name, wrapper, false); 3945 } else { 3946 element.detachEvent("on" + name, wrapper); 3947 } 3948 3949 destroyWrapper(id, eventName, handler); 3950 3951 return element; 3952 }, 3953 3954 fire: function(element, eventName, memo) { 3955 element = $(element); 3956 if (element == document && document.createEvent && !element.dispatchEvent) 3957 element = document.documentElement; 3958 3959 var event; 3960 if (document.createEvent) { 3961 event = document.createEvent("HTMLEvents"); 3962 event.initEvent("dataavailable", true, true); 3963 } else { 3964 event = document.createEventObject(); 3965 event.eventType = "ondataavailable"; 3966 } 3967 3968 event.eventName = eventName; 3969 event.memo = memo || { }; 3970 3971 if (document.createEvent) { 3972 element.dispatchEvent(event); 3973 } else { 3974 element.fireEvent(event.eventType, event); 3975 } 3976 3977 return Event.extend(event); 3978 } 3979 }; 3980})()); 3981 3982Object.extend(Event, Event.Methods); 3983 3984Element.addMethods({ 3985 fire: Event.fire, 3986 observe: Event.observe, 3987 stopObserving: Event.stopObserving 3988}); 3989 3990Object.extend(document, { 3991 fire: Element.Methods.fire.methodize(), 3992 observe: Element.Methods.observe.methodize(), 3993 stopObserving: Element.Methods.stopObserving.methodize(), 3994 loaded: false 3995}); 3996 3997(function() { 3998 /* Support for the DOMContentLoaded event is based on work by Dan Webb, 3999 Matthias Miller, Dean Edwards and John Resig. */ 4000 4001 var timer; 4002 4003 function fireContentLoadedEvent() { 4004 if (document.loaded) return; 4005 if (timer) window.clearInterval(timer); 4006 document.fire("dom:loaded"); 4007 document.loaded = true; 4008 } 4009 4010 if (document.addEventListener) { 4011 if (Prototype.Browser.WebKit) { 4012 timer = window.setInterval(function() { 4013 if (/loaded|complete/.test(document.readyState)) 4014 fireContentLoadedEvent(); 4015 }, 0); 4016 4017 Event.observe(window, "load", fireContentLoadedEvent); 4018 4019 } else { 4020 document.addEventListener("DOMContentLoaded", 4021 fireContentLoadedEvent, false); 4022 } 4023 4024 } else { 4025 document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>"); 4026 $("__onDOMContentLoaded").onreadystatechange = function() { 4027 if (this.readyState == "complete") { 4028 this.onreadystatechange = null; 4029 fireContentLoadedEvent(); 4030 } 4031 }; 4032 } 4033})(); 4034/*------------------------------- DEPRECATED -------------------------------*/ 4035 4036Hash.toQueryString = Object.toQueryString; 4037 4038var Toggle = { display: Element.toggle }; 4039 4040Element.Methods.childOf = Element.Methods.descendantOf; 4041 4042var Insertion = { 4043 Before: function(element, content) { 4044 return Element.insert(element, {before:content}); 4045 }, 4046 4047 Top: function(element, content) { 4048 return Element.insert(element, {top:content}); 4049 }, 4050 4051 Bottom: function(element, content) { 4052 return Element.insert(element, {bottom:content}); 4053 }, 4054 4055 After: function(element, content) { 4056 return Element.insert(element, {after:content}); 4057 } 4058}; 4059 4060var $continue = new Error('"throw $continue" is deprecated, use "return" instead'); 4061 4062// This should be moved to script.aculo.us; notice the deprecated methods 4063// further below, that map to the newer Element methods. 4064var Position = { 4065 // set to true if needed, warning: firefox performance problems 4066 // NOT neeeded for page scrolling, only if draggable contained in 4067 // scrollable elements 4068 includeScrollOffsets: false, 4069 4070 // must be called before calling withinIncludingScrolloffset, every time the 4071 // page is scrolled 4072 prepare: function() { 4073 this.deltaX = window.pageXOffset 4074 || document.documentElement.scrollLeft 4075 || document.body.scrollLeft 4076 || 0; 4077 this.deltaY = window.pageYOffset 4078 || document.documentElement.scrollTop 4079 || document.body.scrollTop 4080 || 0; 4081 }, 4082 4083 // caches x/y coordinate pair to use with overlap 4084 within: function(element, x, y) { 4085 if (this.includeScrollOffsets) 4086 return this.withinIncludingScrolloffsets(element, x, y); 4087 this.xcomp = x; 4088 this.ycomp = y; 4089 this.offset = Element.cumulativeOffset(element); 4090 4091 return (y >= this.offset[1] && 4092 y < this.offset[1] + element.offsetHeight && 4093 x >= this.offset[0] && 4094 x < this.offset[0] + element.offsetWidth); 4095 }, 4096 4097 withinIncludingScrolloffsets: function(element, x, y) { 4098 var offsetcache = Element.cumulativeScrollOffset(element); 4099 4100 this.xcomp = x + offsetcache[0] - this.deltaX; 4101 this.ycomp = y + offsetcache[1] - this.deltaY; 4102 this.offset = Element.cumulativeOffset(element); 4103 4104 return (this.ycomp >= this.offset[1] && 4105 this.ycomp < this.offset[1] + element.offsetHeight && 4106 this.xcomp >= this.offset[0] && 4107 this.xcomp < this.offset[0] + element.offsetWidth); 4108 }, 4109 4110 // within must be called directly before 4111 overlap: function(mode, element) { 4112 if (!mode) return 0; 4113 if (mode == 'vertical') 4114 return ((this.offset[1] + element.offsetHeight) - this.ycomp) / 4115 element.offsetHeight; 4116 if (mode == 'horizontal') 4117 return ((this.offset[0] + element.offsetWidth) - this.xcomp) / 4118 element.offsetWidth; 4119 }, 4120 4121 // Deprecation layer -- use newer Element methods now (1.5.2). 4122 4123 cumulativeOffset: Element.Methods.cumulativeOffset, 4124 4125 positionedOffset: Element.Methods.positionedOffset, 4126 4127 absolutize: function(element) { 4128 Position.prepare(); 4129 return Element.absolutize(element); 4130 }, 4131 4132 relativize: function(element) { 4133 Position.prepare(); 4134 return Element.relativize(element); 4135 }, 4136 4137 realOffset: Element.Methods.cumulativeScrollOffset, 4138 4139 offsetParent: Element.Methods.getOffsetParent, 4140 4141 page: Element.Methods.viewportOffset, 4142 4143 clone: function(source, target, options) { 4144 options = options || { }; 4145 return Element.clonePosition(target, source, options); 4146 } 4147}; 4148 4149/*--------------------------------------------------------------------------*/ 4150 4151if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){ 4152 function iter(name) { 4153 return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]"; 4154 } 4155 4156 instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ? 4157 function(element, className) { 4158 className = className.toString().strip(); 4159 var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className); 4160 return cond ? document._getElementsByXPath('.//*' + cond, element) : []; 4161 } : function(element, className) { 4162 className = className.toString().strip(); 4163 var elements = [], classNames = (/\s/.test(className) ? $w(className) : null); 4164 if (!classNames && !className) return elements; 4165 4166 var nodes = $(element).getElementsByTagName('*'); 4167 className = ' ' + className + ' '; 4168 4169 for (var i = 0, child, cn; child = nodes[i]; i++) { 4170 if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) || 4171 (classNames && classNames.all(function(name) { 4172 return !name.toString().blank() && cn.include(' ' + name + ' '); 4173 })))) 4174 elements.push(Element.extend(child)); 4175 } 4176 return elements; 4177 }; 4178 4179 return function(className, parentElement) { 4180 return $(parentElement || document.body).getElementsByClassName(className); 4181 }; 4182}(Element.Methods); 4183 4184/*--------------------------------------------------------------------------*/ 4185 4186Element.ClassNames = Class.create(); 4187Element.ClassNames.prototype = { 4188 initialize: function(element) { 4189 this.element = $(element); 4190 }, 4191 4192 _each: function(iterator) { 4193 this.element.className.split(/\s+/).select(function(name) { 4194 return name.length > 0; 4195 })._each(iterator); 4196 }, 4197 4198 set: function(className) { 4199 this.element.className = className; 4200 }, 4201 4202 add: function(classNameToAdd) { 4203 if (this.include(classNameToAdd)) return; 4204 this.set($A(this).concat(classNameToAdd).join(' ')); 4205 }, 4206 4207 remove: function(classNameToRemove) { 4208 if (!this.include(classNameToRemove)) return; 4209 this.set($A(this).without(classNameToRemove).join(' ')); 4210 }, 4211 4212 toString: function() { 4213 return $A(this).join(' '); 4214 } 4215}; 4216 4217Object.extend(Element.ClassNames.prototype, Enumerable); 4218 4219/*--------------------------------------------------------------------------*/ 4220 4221Element.addMethods();