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