/testing/selenium-core/lib/prototype.js
JavaScript | 2006 lines | 1775 code | 206 blank | 25 comment | 199 complexity | 94aac37d1eb793c17674e1963d3fca0d MD5 | raw file
Large files files are truncated, but you can click here to view the full file
1/* Prototype JavaScript framework, version 1.5.0_rc0 2 * (c) 2005 Sam Stephenson <sam@conio.net> 3 * 4 * Prototype is freely distributable under the terms of an MIT-style license. 5 * For details, see the Prototype web site: http://prototype.conio.net/ 6 * 7/*--------------------------------------------------------------------------*/ 8 9var Prototype = { 10 Version: '1.5.0_rc0', 11 ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)', 12 13 emptyFunction: function() {}, 14 K: function(x) {return x} 15} 16 17var Class = { 18 create: function() { 19 return function() { 20 this.initialize.apply(this, arguments); 21 } 22 } 23} 24 25var Abstract = new Object(); 26 27Object.extend = function(destination, source) { 28 for (var property in source) { 29 destination[property] = source[property]; 30 } 31 return destination; 32} 33 34Object.inspect = function(object) { 35 try { 36 if (object == undefined) return 'undefined'; 37 if (object == null) return 'null'; 38 return object.inspect ? object.inspect() : object.toString(); 39 } catch (e) { 40 if (e instanceof RangeError) return '...'; 41 throw e; 42 } 43} 44 45Function.prototype.bind = function() { 46 var __method = this, args = $A(arguments), object = args.shift(); 47 return function() { 48 return __method.apply(object, args.concat($A(arguments))); 49 } 50} 51 52Function.prototype.bindAsEventListener = function(object) { 53 var __method = this; 54 return function(event) { 55 return __method.call(object, event || window.event); 56 } 57} 58 59Object.extend(Number.prototype, { 60 toColorPart: function() { 61 var digits = this.toString(16); 62 if (this < 16) return '0' + digits; 63 return digits; 64 }, 65 66 succ: function() { 67 return this + 1; 68 }, 69 70 times: function(iterator) { 71 $R(0, this, true).each(iterator); 72 return this; 73 } 74}); 75 76var Try = { 77 these: function() { 78 var returnValue; 79 80 for (var i = 0; i < arguments.length; i++) { 81 var lambda = arguments[i]; 82 try { 83 returnValue = lambda(); 84 break; 85 } catch (e) {} 86 } 87 88 return returnValue; 89 } 90} 91 92/*--------------------------------------------------------------------------*/ 93 94var PeriodicalExecuter = Class.create(); 95PeriodicalExecuter.prototype = { 96 initialize: function(callback, frequency) { 97 this.callback = callback; 98 this.frequency = frequency; 99 this.currentlyExecuting = false; 100 101 this.registerCallback(); 102 }, 103 104 registerCallback: function() { 105 setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); 106 }, 107 108 onTimerEvent: function() { 109 if (!this.currentlyExecuting) { 110 try { 111 this.currentlyExecuting = true; 112 this.callback(); 113 } finally { 114 this.currentlyExecuting = false; 115 } 116 } 117 } 118} 119Object.extend(String.prototype, { 120 gsub: function(pattern, replacement) { 121 var result = '', source = this, match; 122 replacement = arguments.callee.prepareReplacement(replacement); 123 124 while (source.length > 0) { 125 if (match = source.match(pattern)) { 126 result += source.slice(0, match.index); 127 result += (replacement(match) || '').toString(); 128 source = source.slice(match.index + match[0].length); 129 } else { 130 result += source, source = ''; 131 } 132 } 133 return result; 134 }, 135 136 sub: function(pattern, replacement, count) { 137 replacement = this.gsub.prepareReplacement(replacement); 138 count = count === undefined ? 1 : count; 139 140 return this.gsub(pattern, function(match) { 141 if (--count < 0) return match[0]; 142 return replacement(match); 143 }); 144 }, 145 146 scan: function(pattern, iterator) { 147 this.gsub(pattern, iterator); 148 return this; 149 }, 150 151 truncate: function(length, truncation) { 152 length = length || 30; 153 truncation = truncation === undefined ? '...' : truncation; 154 return this.length > length ? 155 this.slice(0, length - truncation.length) + truncation : this; 156 }, 157 158 strip: function() { 159 return this.replace(/^\s+/, '').replace(/\s+$/, ''); 160 }, 161 162 stripTags: function() { 163 return this.replace(/<\/?[^>]+>/gi, ''); 164 }, 165 166 stripScripts: function() { 167 return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); 168 }, 169 170 extractScripts: function() { 171 var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); 172 var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); 173 return (this.match(matchAll) || []).map(function(scriptTag) { 174 return (scriptTag.match(matchOne) || ['', ''])[1]; 175 }); 176 }, 177 178 evalScripts: function() { 179 return this.extractScripts().map(function(script) { return eval(script) }); 180 }, 181 182 escapeHTML: function() { 183 var div = document.createElement('div'); 184 var text = document.createTextNode(this); 185 div.appendChild(text); 186 return div.innerHTML; 187 }, 188 189 unescapeHTML: function() { 190 var div = document.createElement('div'); 191 div.innerHTML = this.stripTags(); 192 return div.childNodes[0] ? div.childNodes[0].nodeValue : ''; 193 }, 194 195 toQueryParams: function() { 196 var pairs = this.match(/^\??(.*)$/)[1].split('&'); 197 return pairs.inject({}, function(params, pairString) { 198 var pair = pairString.split('='); 199 params[pair[0]] = pair[1]; 200 return params; 201 }); 202 }, 203 204 toArray: function() { 205 return this.split(''); 206 }, 207 208 camelize: function() { 209 var oStringList = this.split('-'); 210 if (oStringList.length == 1) return oStringList[0]; 211 212 var camelizedString = this.indexOf('-') == 0 213 ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1) 214 : oStringList[0]; 215 216 for (var i = 1, len = oStringList.length; i < len; i++) { 217 var s = oStringList[i]; 218 camelizedString += s.charAt(0).toUpperCase() + s.substring(1); 219 } 220 221 return camelizedString; 222 }, 223 224 inspect: function() { 225 return "'" + this.replace(/\\/g, '\\\\').replace(/'/g, '\\\'') + "'"; 226 } 227}); 228 229String.prototype.gsub.prepareReplacement = function(replacement) { 230 if (typeof replacement == 'function') return replacement; 231 var template = new Template(replacement); 232 return function(match) { return template.evaluate(match) }; 233} 234 235String.prototype.parseQuery = String.prototype.toQueryParams; 236 237var Template = Class.create(); 238Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; 239Template.prototype = { 240 initialize: function(template, pattern) { 241 this.template = template.toString(); 242 this.pattern = pattern || Template.Pattern; 243 }, 244 245 evaluate: function(object) { 246 return this.template.gsub(this.pattern, function(match) { 247 var before = match[1]; 248 if (before == '\\') return match[2]; 249 return before + (object[match[3]] || '').toString(); 250 }); 251 } 252} 253 254var $break = new Object(); 255var $continue = new Object(); 256 257var Enumerable = { 258 each: function(iterator) { 259 var index = 0; 260 try { 261 this._each(function(value) { 262 try { 263 iterator(value, index++); 264 } catch (e) { 265 if (e != $continue) throw e; 266 } 267 }); 268 } catch (e) { 269 if (e != $break) throw e; 270 } 271 }, 272 273 all: function(iterator) { 274 var result = true; 275 this.each(function(value, index) { 276 result = result && !!(iterator || Prototype.K)(value, index); 277 if (!result) throw $break; 278 }); 279 return result; 280 }, 281 282 any: function(iterator) { 283 var result = true; 284 this.each(function(value, index) { 285 if (result = !!(iterator || Prototype.K)(value, index)) 286 throw $break; 287 }); 288 return result; 289 }, 290 291 collect: function(iterator) { 292 var results = []; 293 this.each(function(value, index) { 294 results.push(iterator(value, index)); 295 }); 296 return results; 297 }, 298 299 detect: function (iterator) { 300 var result; 301 this.each(function(value, index) { 302 if (iterator(value, index)) { 303 result = value; 304 throw $break; 305 } 306 }); 307 return result; 308 }, 309 310 findAll: function(iterator) { 311 var results = []; 312 this.each(function(value, index) { 313 if (iterator(value, index)) 314 results.push(value); 315 }); 316 return results; 317 }, 318 319 grep: function(pattern, iterator) { 320 var results = []; 321 this.each(function(value, index) { 322 var stringValue = value.toString(); 323 if (stringValue.match(pattern)) 324 results.push((iterator || Prototype.K)(value, index)); 325 }) 326 return results; 327 }, 328 329 include: function(object) { 330 var found = false; 331 this.each(function(value) { 332 if (value == object) { 333 found = true; 334 throw $break; 335 } 336 }); 337 return found; 338 }, 339 340 inject: function(memo, iterator) { 341 this.each(function(value, index) { 342 memo = iterator(memo, value, index); 343 }); 344 return memo; 345 }, 346 347 invoke: function(method) { 348 var args = $A(arguments).slice(1); 349 return this.collect(function(value) { 350 return value[method].apply(value, args); 351 }); 352 }, 353 354 max: function(iterator) { 355 var result; 356 this.each(function(value, index) { 357 value = (iterator || Prototype.K)(value, index); 358 if (result == undefined || value >= result) 359 result = value; 360 }); 361 return result; 362 }, 363 364 min: function(iterator) { 365 var result; 366 this.each(function(value, index) { 367 value = (iterator || Prototype.K)(value, index); 368 if (result == undefined || value < result) 369 result = value; 370 }); 371 return result; 372 }, 373 374 partition: function(iterator) { 375 var trues = [], falses = []; 376 this.each(function(value, index) { 377 ((iterator || Prototype.K)(value, index) ? 378 trues : falses).push(value); 379 }); 380 return [trues, falses]; 381 }, 382 383 pluck: function(property) { 384 var results = []; 385 this.each(function(value, index) { 386 results.push(value[property]); 387 }); 388 return results; 389 }, 390 391 reject: function(iterator) { 392 var results = []; 393 this.each(function(value, index) { 394 if (!iterator(value, index)) 395 results.push(value); 396 }); 397 return results; 398 }, 399 400 sortBy: function(iterator) { 401 return this.collect(function(value, index) { 402 return {value: value, criteria: iterator(value, index)}; 403 }).sort(function(left, right) { 404 var a = left.criteria, b = right.criteria; 405 return a < b ? -1 : a > b ? 1 : 0; 406 }).pluck('value'); 407 }, 408 409 toArray: function() { 410 return this.collect(Prototype.K); 411 }, 412 413 zip: function() { 414 var iterator = Prototype.K, args = $A(arguments); 415 if (typeof args.last() == 'function') 416 iterator = args.pop(); 417 418 var collections = [this].concat(args).map($A); 419 return this.map(function(value, index) { 420 return iterator(collections.pluck(index)); 421 }); 422 }, 423 424 inspect: function() { 425 return '#<Enumerable:' + this.toArray().inspect() + '>'; 426 } 427} 428 429Object.extend(Enumerable, { 430 map: Enumerable.collect, 431 find: Enumerable.detect, 432 select: Enumerable.findAll, 433 member: Enumerable.include, 434 entries: Enumerable.toArray 435}); 436var $A = Array.from = function(iterable) { 437 if (!iterable) return []; 438 if (iterable.toArray) { 439 return iterable.toArray(); 440 } else { 441 var results = []; 442 for (var i = 0; i < iterable.length; i++) 443 results.push(iterable[i]); 444 return results; 445 } 446} 447 448Object.extend(Array.prototype, Enumerable); 449 450if (!Array.prototype._reverse) 451 Array.prototype._reverse = Array.prototype.reverse; 452 453Object.extend(Array.prototype, { 454 _each: function(iterator) { 455 for (var i = 0; i < this.length; i++) 456 iterator(this[i]); 457 }, 458 459 clear: function() { 460 this.length = 0; 461 return this; 462 }, 463 464 first: function() { 465 return this[0]; 466 }, 467 468 last: function() { 469 return this[this.length - 1]; 470 }, 471 472 compact: function() { 473 return this.select(function(value) { 474 return value != undefined || value != null; 475 }); 476 }, 477 478 flatten: function() { 479 return this.inject([], function(array, value) { 480 return array.concat(value && value.constructor == Array ? 481 value.flatten() : [value]); 482 }); 483 }, 484 485 without: function() { 486 var values = $A(arguments); 487 return this.select(function(value) { 488 return !values.include(value); 489 }); 490 }, 491 492 indexOf: function(object) { 493 for (var i = 0; i < this.length; i++) 494 if (this[i] == object) return i; 495 return -1; 496 }, 497 498 reverse: function(inline) { 499 return (inline !== false ? this : this.toArray())._reverse(); 500 }, 501 502 inspect: function() { 503 return '[' + this.map(Object.inspect).join(', ') + ']'; 504 } 505}); 506var Hash = { 507 _each: function(iterator) { 508 for (var key in this) { 509 var value = this[key]; 510 if (typeof value == 'function') continue; 511 512 var pair = [key, value]; 513 pair.key = key; 514 pair.value = value; 515 iterator(pair); 516 } 517 }, 518 519 keys: function() { 520 return this.pluck('key'); 521 }, 522 523 values: function() { 524 return this.pluck('value'); 525 }, 526 527 merge: function(hash) { 528 return $H(hash).inject($H(this), function(mergedHash, pair) { 529 mergedHash[pair.key] = pair.value; 530 return mergedHash; 531 }); 532 }, 533 534 toQueryString: function() { 535 return this.map(function(pair) { 536 return pair.map(encodeURIComponent).join('='); 537 }).join('&'); 538 }, 539 540 inspect: function() { 541 return '#<Hash:{' + this.map(function(pair) { 542 return pair.map(Object.inspect).join(': '); 543 }).join(', ') + '}>'; 544 } 545} 546 547function $H(object) { 548 var hash = Object.extend({}, object || {}); 549 Object.extend(hash, Enumerable); 550 Object.extend(hash, Hash); 551 return hash; 552} 553ObjectRange = Class.create(); 554Object.extend(ObjectRange.prototype, Enumerable); 555Object.extend(ObjectRange.prototype, { 556 initialize: function(start, end, exclusive) { 557 this.start = start; 558 this.end = end; 559 this.exclusive = exclusive; 560 }, 561 562 _each: function(iterator) { 563 var value = this.start; 564 do { 565 iterator(value); 566 value = value.succ(); 567 } while (this.include(value)); 568 }, 569 570 include: function(value) { 571 if (value < this.start) 572 return false; 573 if (this.exclusive) 574 return value < this.end; 575 return value <= this.end; 576 } 577}); 578 579var $R = function(start, end, exclusive) { 580 return new ObjectRange(start, end, exclusive); 581} 582 583var Ajax = { 584 getTransport: function() { 585 return Try.these( 586 function() {return new XMLHttpRequest()}, 587 function() {return new ActiveXObject('Msxml2.XMLHTTP')}, 588 function() {return new ActiveXObject('Microsoft.XMLHTTP')} 589 ) || false; 590 }, 591 592 activeRequestCount: 0 593} 594 595Ajax.Responders = { 596 responders: [], 597 598 _each: function(iterator) { 599 this.responders._each(iterator); 600 }, 601 602 register: function(responderToAdd) { 603 if (!this.include(responderToAdd)) 604 this.responders.push(responderToAdd); 605 }, 606 607 unregister: function(responderToRemove) { 608 this.responders = this.responders.without(responderToRemove); 609 }, 610 611 dispatch: function(callback, request, transport, json) { 612 this.each(function(responder) { 613 if (responder[callback] && typeof responder[callback] == 'function') { 614 try { 615 responder[callback].apply(responder, [request, transport, json]); 616 } catch (e) {} 617 } 618 }); 619 } 620}; 621 622Object.extend(Ajax.Responders, Enumerable); 623 624Ajax.Responders.register({ 625 onCreate: function() { 626 Ajax.activeRequestCount++; 627 }, 628 629 onComplete: function() { 630 Ajax.activeRequestCount--; 631 } 632}); 633 634Ajax.Base = function() {}; 635Ajax.Base.prototype = { 636 setOptions: function(options) { 637 this.options = { 638 method: 'post', 639 asynchronous: true, 640 contentType: 'application/x-www-form-urlencoded', 641 parameters: '' 642 } 643 Object.extend(this.options, options || {}); 644 }, 645 646 responseIsSuccess: function() { 647 return this.transport.status == undefined 648 || this.transport.status == 0 649 || (this.transport.status >= 200 && this.transport.status < 300); 650 }, 651 652 responseIsFailure: function() { 653 return !this.responseIsSuccess(); 654 } 655} 656 657Ajax.Request = Class.create(); 658Ajax.Request.Events = 659 ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; 660 661Ajax.Request.prototype = Object.extend(new Ajax.Base(), { 662 initialize: function(url, options) { 663 this.transport = Ajax.getTransport(); 664 this.setOptions(options); 665 this.request(url); 666 }, 667 668 request: function(url) { 669 var parameters = this.options.parameters || ''; 670 if (parameters.length > 0) parameters += '&_='; 671 672 try { 673 this.url = url; 674 if (this.options.method == 'get' && parameters.length > 0) 675 this.url += (this.url.match(/\?/) ? '&' : '?') + parameters; 676 677 Ajax.Responders.dispatch('onCreate', this, this.transport); 678 679 this.transport.open(this.options.method, this.url, 680 this.options.asynchronous); 681 682 if (this.options.asynchronous) { 683 this.transport.onreadystatechange = this.onStateChange.bind(this); 684 setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10); 685 } 686 687 this.setRequestHeaders(); 688 689 var body = this.options.postBody ? this.options.postBody : parameters; 690 this.transport.send(this.options.method == 'post' ? body : null); 691 692 } catch (e) { 693 this.dispatchException(e); 694 } 695 }, 696 697 setRequestHeaders: function() { 698 var requestHeaders = 699 ['X-Requested-With', 'XMLHttpRequest', 700 'X-Prototype-Version', Prototype.Version, 701 'Accept', 'text/javascript, text/html, application/xml, text/xml, */*']; 702 703 if (this.options.method == 'post') { 704 requestHeaders.push('Content-type', this.options.contentType); 705 706 /* Force "Connection: close" for Mozilla browsers to work around 707 * a bug where XMLHttpReqeuest sends an incorrect Content-length 708 * header. See Mozilla Bugzilla #246651. 709 */ 710 if (this.transport.overrideMimeType) 711 requestHeaders.push('Connection', 'close'); 712 } 713 714 if (this.options.requestHeaders) 715 requestHeaders.push.apply(requestHeaders, this.options.requestHeaders); 716 717 for (var i = 0; i < requestHeaders.length; i += 2) 718 this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]); 719 }, 720 721 onStateChange: function() { 722 var readyState = this.transport.readyState; 723 if (readyState != 1) 724 this.respondToReadyState(this.transport.readyState); 725 }, 726 727 header: function(name) { 728 try { 729 return this.transport.getResponseHeader(name); 730 } catch (e) {} 731 }, 732 733 evalJSON: function() { 734 try { 735 return eval('(' + this.header('X-JSON') + ')'); 736 } catch (e) {} 737 }, 738 739 evalResponse: function() { 740 try { 741 return eval(this.transport.responseText); 742 } catch (e) { 743 this.dispatchException(e); 744 } 745 }, 746 747 respondToReadyState: function(readyState) { 748 var event = Ajax.Request.Events[readyState]; 749 var transport = this.transport, json = this.evalJSON(); 750 751 if (event == 'Complete') { 752 try { 753 (this.options['on' + this.transport.status] 754 || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] 755 || Prototype.emptyFunction)(transport, json); 756 } catch (e) { 757 this.dispatchException(e); 758 } 759 760 if ((this.header('Content-type') || '').match(/^text\/javascript/i)) 761 this.evalResponse(); 762 } 763 764 try { 765 (this.options['on' + event] || Prototype.emptyFunction)(transport, json); 766 Ajax.Responders.dispatch('on' + event, this, transport, json); 767 } catch (e) { 768 this.dispatchException(e); 769 } 770 771 /* Avoid memory leak in MSIE: clean up the oncomplete event handler */ 772 if (event == 'Complete') 773 this.transport.onreadystatechange = Prototype.emptyFunction; 774 }, 775 776 dispatchException: function(exception) { 777 (this.options.onException || Prototype.emptyFunction)(this, exception); 778 Ajax.Responders.dispatch('onException', this, exception); 779 } 780}); 781 782Ajax.Updater = Class.create(); 783 784Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { 785 initialize: function(container, url, options) { 786 this.containers = { 787 success: container.success ? $(container.success) : $(container), 788 failure: container.failure ? $(container.failure) : 789 (container.success ? null : $(container)) 790 } 791 792 this.transport = Ajax.getTransport(); 793 this.setOptions(options); 794 795 var onComplete = this.options.onComplete || Prototype.emptyFunction; 796 this.options.onComplete = (function(transport, object) { 797 this.updateContent(); 798 onComplete(transport, object); 799 }).bind(this); 800 801 this.request(url); 802 }, 803 804 updateContent: function() { 805 var receiver = this.responseIsSuccess() ? 806 this.containers.success : this.containers.failure; 807 var response = this.transport.responseText; 808 809 if (!this.options.evalScripts) 810 response = response.stripScripts(); 811 812 if (receiver) { 813 if (this.options.insertion) { 814 new this.options.insertion(receiver, response); 815 } else { 816 Element.update(receiver, response); 817 } 818 } 819 820 if (this.responseIsSuccess()) { 821 if (this.onComplete) 822 setTimeout(this.onComplete.bind(this), 10); 823 } 824 } 825}); 826 827Ajax.PeriodicalUpdater = Class.create(); 828Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { 829 initialize: function(container, url, options) { 830 this.setOptions(options); 831 this.onComplete = this.options.onComplete; 832 833 this.frequency = (this.options.frequency || 2); 834 this.decay = (this.options.decay || 1); 835 836 this.updater = {}; 837 this.container = container; 838 this.url = url; 839 840 this.start(); 841 }, 842 843 start: function() { 844 this.options.onComplete = this.updateComplete.bind(this); 845 this.onTimerEvent(); 846 }, 847 848 stop: function() { 849 this.updater.onComplete = undefined; 850 clearTimeout(this.timer); 851 (this.onComplete || Prototype.emptyFunction).apply(this, arguments); 852 }, 853 854 updateComplete: function(request) { 855 if (this.options.decay) { 856 this.decay = (request.responseText == this.lastText ? 857 this.decay * this.options.decay : 1); 858 859 this.lastText = request.responseText; 860 } 861 this.timer = setTimeout(this.onTimerEvent.bind(this), 862 this.decay * this.frequency * 1000); 863 }, 864 865 onTimerEvent: function() { 866 this.updater = new Ajax.Updater(this.container, this.url, this.options); 867 } 868}); 869function $() { 870 var results = [], element; 871 for (var i = 0; i < arguments.length; i++) { 872 element = arguments[i]; 873 if (typeof element == 'string') 874 element = document.getElementById(element); 875 results.push(Element.extend(element)); 876 } 877 return results.length < 2 ? results[0] : results; 878} 879 880document.getElementsByClassName = function(className, parentElement) { 881 var children = ($(parentElement) || document.body).getElementsByTagName('*'); 882 return $A(children).inject([], function(elements, child) { 883 if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) 884 elements.push(Element.extend(child)); 885 return elements; 886 }); 887} 888 889/*--------------------------------------------------------------------------*/ 890 891if (!window.Element) 892 var Element = new Object(); 893 894Element.extend = function(element) { 895 if (!element) return; 896 if (_nativeExtensions) return element; 897 898 if (!element._extended && element.tagName && element != window) { 899 var methods = Element.Methods, cache = Element.extend.cache; 900 for (property in methods) { 901 var value = methods[property]; 902 if (typeof value == 'function') 903 element[property] = cache.findOrStore(value); 904 } 905 } 906 907 element._extended = true; 908 return element; 909} 910 911Element.extend.cache = { 912 findOrStore: function(value) { 913 return this[value] = this[value] || function() { 914 return value.apply(null, [this].concat($A(arguments))); 915 } 916 } 917} 918 919Element.Methods = { 920 visible: function(element) { 921 return $(element).style.display != 'none'; 922 }, 923 924 toggle: function() { 925 for (var i = 0; i < arguments.length; i++) { 926 var element = $(arguments[i]); 927 Element[Element.visible(element) ? 'hide' : 'show'](element); 928 } 929 }, 930 931 hide: function() { 932 for (var i = 0; i < arguments.length; i++) { 933 var element = $(arguments[i]); 934 element.style.display = 'none'; 935 } 936 }, 937 938 show: function() { 939 for (var i = 0; i < arguments.length; i++) { 940 var element = $(arguments[i]); 941 element.style.display = ''; 942 } 943 }, 944 945 remove: function(element) { 946 element = $(element); 947 element.parentNode.removeChild(element); 948 }, 949 950 update: function(element, html) { 951 $(element).innerHTML = html.stripScripts(); 952 setTimeout(function() {html.evalScripts()}, 10); 953 }, 954 955 replace: function(element, html) { 956 element = $(element); 957 if (element.outerHTML) { 958 element.outerHTML = html.stripScripts(); 959 } else { 960 var range = element.ownerDocument.createRange(); 961 range.selectNodeContents(element); 962 element.parentNode.replaceChild( 963 range.createContextualFragment(html.stripScripts()), element); 964 } 965 setTimeout(function() {html.evalScripts()}, 10); 966 }, 967 968 getHeight: function(element) { 969 element = $(element); 970 return element.offsetHeight; 971 }, 972 973 classNames: function(element) { 974 return new Element.ClassNames(element); 975 }, 976 977 hasClassName: function(element, className) { 978 if (!(element = $(element))) return; 979 return Element.classNames(element).include(className); 980 }, 981 982 addClassName: function(element, className) { 983 if (!(element = $(element))) return; 984 return Element.classNames(element).add(className); 985 }, 986 987 removeClassName: function(element, className) { 988 if (!(element = $(element))) return; 989 return Element.classNames(element).remove(className); 990 }, 991 992 // removes whitespace-only text node children 993 cleanWhitespace: function(element) { 994 element = $(element); 995 for (var i = 0; i < element.childNodes.length; i++) { 996 var node = element.childNodes[i]; 997 if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) 998 Element.remove(node); 999 } 1000 }, 1001 1002 empty: function(element) { 1003 return $(element).innerHTML.match(/^\s*$/); 1004 }, 1005 1006 childOf: function(element, ancestor) { 1007 element = $(element), ancestor = $(ancestor); 1008 while (element = element.parentNode) 1009 if (element == ancestor) return true; 1010 return false; 1011 }, 1012 1013 scrollTo: function(element) { 1014 element = $(element); 1015 var x = element.x ? element.x : element.offsetLeft, 1016 y = element.y ? element.y : element.offsetTop; 1017 window.scrollTo(x, y); 1018 }, 1019 1020 getStyle: function(element, style) { 1021 element = $(element); 1022 var value = element.style[style.camelize()]; 1023 if (!value) { 1024 if (document.defaultView && document.defaultView.getComputedStyle) { 1025 var css = document.defaultView.getComputedStyle(element, null); 1026 value = css ? css.getPropertyValue(style) : null; 1027 } else if (element.currentStyle) { 1028 value = element.currentStyle[style.camelize()]; 1029 } 1030 } 1031 1032 if (window.opera && ['left', 'top', 'right', 'bottom'].include(style)) 1033 if (Element.getStyle(element, 'position') == 'static') value = 'auto'; 1034 1035 return value == 'auto' ? null : value; 1036 }, 1037 1038 setStyle: function(element, style) { 1039 element = $(element); 1040 for (var name in style) 1041 element.style[name.camelize()] = style[name]; 1042 }, 1043 1044 getDimensions: function(element) { 1045 element = $(element); 1046 if (Element.getStyle(element, 'display') != 'none') 1047 return {width: element.offsetWidth, height: element.offsetHeight}; 1048 1049 // All *Width and *Height properties give 0 on elements with display none, 1050 // so enable the element temporarily 1051 var els = element.style; 1052 var originalVisibility = els.visibility; 1053 var originalPosition = els.position; 1054 els.visibility = 'hidden'; 1055 els.position = 'absolute'; 1056 els.display = ''; 1057 var originalWidth = element.clientWidth; 1058 var originalHeight = element.clientHeight; 1059 els.display = 'none'; 1060 els.position = originalPosition; 1061 els.visibility = originalVisibility; 1062 return {width: originalWidth, height: originalHeight}; 1063 }, 1064 1065 makePositioned: function(element) { 1066 element = $(element); 1067 var pos = Element.getStyle(element, 'position'); 1068 if (pos == 'static' || !pos) { 1069 element._madePositioned = true; 1070 element.style.position = 'relative'; 1071 // Opera returns the offset relative to the positioning context, when an 1072 // element is position relative but top and left have not been defined 1073 if (window.opera) { 1074 element.style.top = 0; 1075 element.style.left = 0; 1076 } 1077 } 1078 }, 1079 1080 undoPositioned: function(element) { 1081 element = $(element); 1082 if (element._madePositioned) { 1083 element._madePositioned = undefined; 1084 element.style.position = 1085 element.style.top = 1086 element.style.left = 1087 element.style.bottom = 1088 element.style.right = ''; 1089 } 1090 }, 1091 1092 makeClipping: function(element) { 1093 element = $(element); 1094 if (element._overflow) return; 1095 element._overflow = element.style.overflow; 1096 if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') 1097 element.style.overflow = 'hidden'; 1098 }, 1099 1100 undoClipping: function(element) { 1101 element = $(element); 1102 if (element._overflow) return; 1103 element.style.overflow = element._overflow; 1104 element._overflow = undefined; 1105 } 1106} 1107 1108Object.extend(Element, Element.Methods); 1109 1110var _nativeExtensions = false; 1111 1112if(!HTMLElement && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) { 1113 var HTMLElement = {} 1114 HTMLElement.prototype = document.createElement('div').__proto__; 1115} 1116 1117Element.addMethods = function(methods) { 1118 Object.extend(Element.Methods, methods || {}); 1119 1120 if(typeof HTMLElement != 'undefined') { 1121 var methods = Element.Methods, cache = Element.extend.cache; 1122 for (property in methods) { 1123 var value = methods[property]; 1124 if (typeof value == 'function') 1125 HTMLElement.prototype[property] = cache.findOrStore(value); 1126 } 1127 _nativeExtensions = true; 1128 } 1129} 1130 1131Element.addMethods(); 1132 1133var Toggle = new Object(); 1134Toggle.display = Element.toggle; 1135 1136/*--------------------------------------------------------------------------*/ 1137 1138Abstract.Insertion = function(adjacency) { 1139 this.adjacency = adjacency; 1140} 1141 1142Abstract.Insertion.prototype = { 1143 initialize: function(element, content) { 1144 this.element = $(element); 1145 this.content = content.stripScripts(); 1146 1147 if (this.adjacency && this.element.insertAdjacentHTML) { 1148 try { 1149 this.element.insertAdjacentHTML(this.adjacency, this.content); 1150 } catch (e) { 1151 var tagName = this.element.tagName.toLowerCase(); 1152 if (tagName == 'tbody' || tagName == 'tr') { 1153 this.insertContent(this.contentFromAnonymousTable()); 1154 } else { 1155 throw e; 1156 } 1157 } 1158 } else { 1159 this.range = this.element.ownerDocument.createRange(); 1160 if (this.initializeRange) this.initializeRange(); 1161 this.insertContent([this.range.createContextualFragment(this.content)]); 1162 } 1163 1164 setTimeout(function() {content.evalScripts()}, 10); 1165 }, 1166 1167 contentFromAnonymousTable: function() { 1168 var div = document.createElement('div'); 1169 div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>'; 1170 return $A(div.childNodes[0].childNodes[0].childNodes); 1171 } 1172} 1173 1174var Insertion = new Object(); 1175 1176Insertion.Before = Class.create(); 1177Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), { 1178 initializeRange: function() { 1179 this.range.setStartBefore(this.element); 1180 }, 1181 1182 insertContent: function(fragments) { 1183 fragments.each((function(fragment) { 1184 this.element.parentNode.insertBefore(fragment, this.element); 1185 }).bind(this)); 1186 } 1187}); 1188 1189Insertion.Top = Class.create(); 1190Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), { 1191 initializeRange: function() { 1192 this.range.selectNodeContents(this.element); 1193 this.range.collapse(true); 1194 }, 1195 1196 insertContent: function(fragments) { 1197 fragments.reverse(false).each((function(fragment) { 1198 this.element.insertBefore(fragment, this.element.firstChild); 1199 }).bind(this)); 1200 } 1201}); 1202 1203Insertion.Bottom = Class.create(); 1204Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), { 1205 initializeRange: function() { 1206 this.range.selectNodeContents(this.element); 1207 this.range.collapse(this.element); 1208 }, 1209 1210 insertContent: function(fragments) { 1211 fragments.each((function(fragment) { 1212 this.element.appendChild(fragment); 1213 }).bind(this)); 1214 } 1215}); 1216 1217Insertion.After = Class.create(); 1218Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), { 1219 initializeRange: function() { 1220 this.range.setStartAfter(this.element); 1221 }, 1222 1223 insertContent: function(fragments) { 1224 fragments.each((function(fragment) { 1225 this.element.parentNode.insertBefore(fragment, 1226 this.element.nextSibling); 1227 }).bind(this)); 1228 } 1229}); 1230 1231/*--------------------------------------------------------------------------*/ 1232 1233Element.ClassNames = Class.create(); 1234Element.ClassNames.prototype = { 1235 initialize: function(element) { 1236 this.element = $(element); 1237 }, 1238 1239 _each: function(iterator) { 1240 this.element.className.split(/\s+/).select(function(name) { 1241 return name.length > 0; 1242 })._each(iterator); 1243 }, 1244 1245 set: function(className) { 1246 this.element.className = className; 1247 }, 1248 1249 add: function(classNameToAdd) { 1250 if (this.include(classNameToAdd)) return; 1251 this.set(this.toArray().concat(classNameToAdd).join(' ')); 1252 }, 1253 1254 remove: function(classNameToRemove) { 1255 if (!this.include(classNameToRemove)) return; 1256 this.set(this.select(function(className) { 1257 return className != classNameToRemove; 1258 }).join(' ')); 1259 }, 1260 1261 toString: function() { 1262 return this.toArray().join(' '); 1263 } 1264} 1265 1266Object.extend(Element.ClassNames.prototype, Enumerable); 1267var Selector = Class.create(); 1268Selector.prototype = { 1269 initialize: function(expression) { 1270 this.params = {classNames: []}; 1271 this.expression = expression.toString().strip(); 1272 this.parseExpression(); 1273 this.compileMatcher(); 1274 }, 1275 1276 parseExpression: function() { 1277 function abort(message) { throw 'Parse error in selector: ' + message; } 1278 1279 if (this.expression == '') abort('empty expression'); 1280 1281 var params = this.params, expr = this.expression, match, modifier, clause, rest; 1282 while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) { 1283 params.attributes = params.attributes || []; 1284 params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''}); 1285 expr = match[1]; 1286 } 1287 1288 if (expr == '*') return this.params.wildcard = true; 1289 1290 while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) { 1291 modifier = match[1], clause = match[2], rest = match[3]; 1292 switch (modifier) { 1293 case '#': params.id = clause; break; 1294 case '.': params.classNames.push(clause); break; 1295 case '': 1296 case undefined: params.tagName = clause.toUpperCase(); break; 1297 default: abort(expr.inspect()); 1298 } 1299 expr = rest; 1300 } 1301 1302 if (expr.length > 0) abort(expr.inspect()); 1303 }, 1304 1305 buildMatchExpression: function() { 1306 var params = this.params, conditions = [], clause; 1307 1308 if (params.wildcard) 1309 conditions.push('true'); 1310 if (clause = params.id) 1311 conditions.push('element.id == ' + clause.inspect()); 1312 if (clause = params.tagName) 1313 conditions.push('element.tagName.toUpperCase() == ' + clause.inspect()); 1314 if ((clause = params.classNames).length > 0) 1315 for (var i = 0; i < clause.length; i++) 1316 conditions.push('Element.hasClassName(element, ' + clause[i].inspect() + ')'); 1317 if (clause = params.attributes) { 1318 clause.each(function(attribute) { 1319 var value = 'element.getAttribute(' + attribute.name.inspect() + ')'; 1320 var splitValueBy = function(delimiter) { 1321 return value + ' && ' + value + '.split(' + delimiter.inspect() + ')'; 1322 } 1323 1324 switch (attribute.operator) { 1325 case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break; 1326 case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break; 1327 case '|=': conditions.push( 1328 splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect() 1329 ); break; 1330 case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break; 1331 case '': 1332 case undefined: conditions.push(value + ' != null'); break; 1333 default: throw 'Unknown operator ' + attribute.operator + ' in selector'; 1334 } 1335 }); 1336 } 1337 1338 return conditions.join(' && '); 1339 }, 1340 1341 compileMatcher: function() { 1342 this.match = new Function('element', 'if (!element.tagName) return false; \n' + 1343 'return ' + this.buildMatchExpression()); 1344 }, 1345 1346 findElements: function(scope) { 1347 var element; 1348 1349 if (element = $(this.params.id)) 1350 if (this.match(element)) 1351 if (!scope || Element.childOf(element, scope)) 1352 return [element]; 1353 1354 scope = (scope || document).getElementsByTagName(this.params.tagName || '*'); 1355 1356 var results = []; 1357 for (var i = 0; i < scope.length; i++) 1358 if (this.match(element = scope[i])) 1359 results.push(Element.extend(element)); 1360 1361 return results; 1362 }, 1363 1364 toString: function() { 1365 return this.expression; 1366 } 1367} 1368 1369function $$() { 1370 return $A(arguments).map(function(expression) { 1371 return expression.strip().split(/\s+/).inject([null], function(results, expr) { 1372 var selector = new Selector(expr); 1373 return results.map(selector.findElements.bind(selector)).flatten(); 1374 }); 1375 }).flatten(); 1376} 1377var Field = { 1378 clear: function() { 1379 for (var i = 0; i < arguments.length; i++) 1380 $(arguments[i]).value = ''; 1381 }, 1382 1383 focus: function(element) { 1384 $(element).focus(); 1385 }, 1386 1387 present: function() { 1388 for (var i = 0; i < arguments.length; i++) 1389 if ($(arguments[i]).value == '') return false; 1390 return true; 1391 }, 1392 1393 select: function(element) { 1394 $(element).select(); 1395 }, 1396 1397 activate: function(element) { 1398 element = $(element); 1399 element.focus(); 1400 if (element.select) 1401 element.select(); 1402 } 1403} 1404 1405/*--------------------------------------------------------------------------*/ 1406 1407var Form = { 1408 serialize: function(form) { 1409 var elements = Form.getElements($(form)); 1410 var queryComponents = new Array(); 1411 1412 for (var i = 0; i < elements.length; i++) { 1413 var queryComponent = Form.Element.serialize(elements[i]); 1414 if (queryComponent) 1415 queryComponents.push(queryComponent); 1416 } 1417 1418 return queryComponents.join('&'); 1419 }, 1420 1421 getElements: function(form) { 1422 form = $(form); 1423 var elements = new Array(); 1424 1425 for (var tagName in Form.Element.Serializers) { 1426 var tagElements = form.getElementsByTagName(tagName); 1427 for (var j = 0; j < tagElements.length; j++) 1428 elements.push(tagElements[j]); 1429 } 1430 return elements; 1431 }, 1432 1433 getInputs: function(form, typeName, name) { 1434 form = $(form); 1435 var inputs = form.getElementsByTagName('input'); 1436 1437 if (!typeName && !name) 1438 return inputs; 1439 1440 var matchingInputs = new Array(); 1441 for (var i = 0; i < inputs.length; i++) { 1442 var input = inputs[i]; 1443 if ((typeName && input.type != typeName) || 1444 (name && input.name != name)) 1445 continue; 1446 matchingInputs.push(input); 1447 } 1448 1449 return matchingInputs; 1450 }, 1451 1452 disable: function(form) { 1453 var elements = Form.getElements(form); 1454 for (var i = 0; i < elements.length; i++) { 1455 var element = elements[i]; 1456 element.blur(); 1457 element.disabled = 'true'; 1458 } 1459 }, 1460 1461 enable: function(form) { 1462 var elements = Form.getElements(form); 1463 for (var i = 0; i < elements.length; i++) { 1464 var element = elements[i]; 1465 element.disabled = ''; 1466 } 1467 }, 1468 1469 findFirstElement: function(form) { 1470 return Form.getElements(form).find(function(element) { 1471 return element.type != 'hidden' && !element.disabled && 1472 ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); 1473 }); 1474 }, 1475 1476 focusFirstElement: function(form) { 1477 Field.activate(Form.findFirstElement(form)); 1478 }, 1479 1480 reset: function(form) { 1481 $(form).reset(); 1482 } 1483} 1484 1485Form.Element = { 1486 serialize: function(element) { 1487 element = $(element); 1488 var method = element.tagName.toLowerCase(); 1489 var parameter = Form.Element.Serializers[method](element); 1490 1491 if (parameter) { 1492 var key = encodeURIComponent(parameter[0]); 1493 if (key.length == 0) return; 1494 1495 if (parameter[1].constructor != Array) 1496 parameter[1] = [parameter[1]]; 1497 1498 return parameter[1].map(function(value) { 1499 return key + '=' + encodeURIComponent(value); 1500 }).join('&'); 1501 } 1502 }, 1503 1504 getValue: function(element) { 1505 element = $(element); 1506 var method = element.tagName.toLowerCase(); 1507 var parameter = Form.Element.Serializers[method](element); 1508 1509 if (parameter) 1510 return parameter[1]; 1511 } 1512} 1513 1514Form.Element.Serializers = { 1515 input: function(element) { 1516 switch (element.type.toLowerCase()) { 1517 case 'submit': 1518 case 'hidden': 1519 case 'password': 1520 case 'text': 1521 return Form.Element.Serializers.textarea(element); 1522 case 'checkbox': 1523 case 'radio': 1524 return Form.Element.Serializers.inputSelector(element); 1525 } 1526 return false; 1527 }, 1528 1529 inputSelector: function(element) { 1530 if (element.checked) 1531 return [element.name, element.value]; 1532 }, 1533 1534 textarea: function(element) { 1535 return [element.name, element.value]; 1536 }, 1537 1538 select: function(element) { 1539 return Form.Element.Serializers[element.type == 'select-one' ? 1540 'selectOne' : 'selectMany'](element); 1541 }, 1542 1543 selectOne: function(element) { 1544 var value = '', opt, index = element.selectedIndex; 1545 if (index >= 0) { 1546 opt = element.options[index]; 1547 value = opt.value || opt.text; 1548 } 1549 return [element.name, value]; 1550 }, 1551 1552 selectMany: function(element) { 1553 var value = []; 1554 for (var i = 0; i < element.length; i++) { 1555 var opt = element.options[i]; 1556 if (opt.selected) 1557 value.push(opt.value || opt.text); 1558 } 1559 return [element.name, value]; 1560 } 1561} 1562 1563/*--------------------------------------------------------------------------*/ 1564 1565var $F = Form.Element.getValue; 1566 1567/*--------------------------------------------------------------------------*/ 1568 1569Abstract.TimedObserver = function() {} 1570Abstract.TimedObserver.prototype = { 1571 initialize: function(element, frequency, callback) { 1572 this.frequency = frequency; 1573 this.element = $(element); 1574 this.callback = callback; 1575 1576 this.lastValue = this.getValue(); 1577 this.registerCallback(); 1578 }, 1579 1580 registerCallback: function() { 1581 setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); 1582 }, 1583 1584 onTimerEvent: function() { 1585 var value = this.getValue(); 1586 if (this.lastValue != value) { 1587 this.callback(this.element, value); 1588 this.lastValue = value; 1589 } 1590 } 1591} 1592 1593Form.Element.Observer = Class.create(); 1594Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { 1595 getValue: function() { 1596 return Form.Element.getValue(this.element); 1597 } 1598}); 1599 1600Form.Observer = Class.create(); 1601Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { 1602 getValue: function() { 1603 return Form.serialize(this.element); 1604 } 1605}); 1606 1607/*--------------------------------------------------------------------------*/ 1608 1609Abstract.EventObserver = function() {} 1610Abstract.EventObserver.prototype = { 1611 initialize: function(element, callback) { 1612 this.element = $(element); 1613 this.callback = callback; 1614 1615 this.lastValue = this.getValue(); 1616 if (this.element.tagName.toLowerCase() == 'form') 1617 this.registerFormCallbacks(); 1618 else 1619 this.registerCallback(this.element); 1620 }, 1621 1622 onElementEvent: function() { 1623 var value = this.getValue(); 1624 if (this.lastValue != value) { 1625 this.callback(this.element, value); 1626 this.lastValue = value; 1627 } 1628 }, 1629 1630 registerFormCallbacks: function() { 1631 var elements = Form.getElements(this.element); 1632 for (var i = 0; i < elements.length; i++) 1633 this.registerCallback(elements[i]); 1634 }, 1635 1636 registerCallback: function(element) { 1637 if (element.type) { 1638 switch (element.type.toLowerCase()) { 1639 case 'checkbox': 1640 case 'radio': 1641 Event.observe(element, 'click', this.onElementEvent.bind(this)); 1642 break; 1643 case 'password': 1644 case 'text': 1645 case 'textarea': 1646 case 'select-one': 1647 case 'select-multiple': 1648 Event.observe(element, 'change', this.onElementEvent.bind(this)); 1649 break; 1650 } 1651 } 1652 } 1653} 1654 1655Form.Element.EventObserver = Class.create(); 1656Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { 1657 getValue: function() { 1658 return Form.Element.getValue(this.element); 1659 } 1660}); 1661 1662Form.EventObserver = Class.create(); 1663Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { 1664 getValue: function() { 1665 return Form.serialize(this.element); 1666 } 1667}); 1668if (!window.Event) { 1669 var Event = new Object(); 1670} 1671 1672Object.extend(Event, { 1673 KEY_BACKSPACE: 8, 1674 KEY_TAB: 9, 1675 KEY_RETURN: 13, 1676 KEY_ESC: 27, 1677 KEY_LEFT: 37, 1678 KEY_UP: 38, 1679 KEY_RIGHT: 39, 1680 KEY_DOWN: 40, 1681 KEY_DELETE: 46, 1682 1683 element: function(event) { 1684 return event.target || event.srcElement; 1685 }, 1686 1687 isLeftClick: function(event) { 1688 return (((event.which) && (event.which == 1)) || 1689 ((event.button) && (event.button == 1))); 1690 }, 1691 1692 pointerX: function(event) { 1693 return event.pageX || (event.clientX + 1694 (document.documentElement.scrollLeft || document.body.scrollLeft)); 1695 }, 1696 1697 pointerY: function(event) { 1698 return event.pageY || (event.clientY + 1699 (document.documentElement.scrollTop || document.body.scrollTop)); 1700 }, 1701 1702 stop: function(event) { 1703 if (event.preventDefault) { 1704 event.preventDefault(); 1705 event.stopPropagation(); 1706 } else { 1707 event.returnValue = false; 1708 event.cancelBubble = true; 1709 } 1710 }, 1711 1712 // find the first node with the given tagName, starting from the 1713 // node the event was triggered on; traverses the DOM upwards 1714 findElement: function(event, tagName) { 1715 var element = Event.element(event); 1716 while (element.parentNode && (!element.tagName || 1717 (element.tagName.toUpperCase() != tagName.toUpperCase()))) 1718 element = element.parentNode; 1719 return element; 1720 }, 1721 1722 observers: false, 1723 1724 _observeAndCache: function(element, name, observer, useCapture) { 1725 if (!this.observers) this.observers = []; 1726 if (element.addEventListener) { 1727 this.observers.push([element, name, observer, useCapture]); 1728 element.addEventListener(name, observer, useCapture); 1729 } else if (element.attachEvent) { 1730 this.observers.push([element, name, observer, useCapture]); 1731 element.attachEvent('on' + name, observer); 1732 } 1733 }, 1734 1735 unloadCache: function() { 1736 if (!Event.observers) return; 1737 for (var i = 0; i < Event.observers.length; i++) { 1738 Event.stopObserving.apply(this, Event.observers[i]); 1739 Event.observers[i][0] = null; 1740 } 1741 Event.observers = false; 1742 }, 1743 1744 observe: function(element, name, observer, useCapture) { 1745 var element = $(element); 1746 useCapture = useCapture || false; 1747 1748 if (name == 'keypress' && 1749 (navigator.appVersion.match(/Konqueror|Safari|KHTML/) 1750 || element.attachEvent)) 1751 name = 'keydown'; 1752 1753 this._observeAndCache(element, name, observer, useCapture); 1754 }, 1755 1756 stopObserving: function(element, name, observer, useCapture) { 1757 var element = $(element); 1758 useCapture = useCapture || false; 1759 1760 if (name == 'keypress' && 1761 (navigator.appVersion.match(/Konqueror|Safari|KHTML/) 1762 || element.detachEvent)) 1763 name = 'keydown'; 1764 1765 if (element.removeEventListener) { 1766 element.removeEventListener(name, observer, useCapture); 1767 } else if (element.detachEvent) { 1768 element.detachEvent('on' + name, observer); 1769 } 1770 } 1771}); 1772 1773/* prevent memory leaks in IE */ 1774if (navigator.appVersion.match(/\bMSIE\b/)) 1775 Event.observe(window, 'unload', Event.unloadCache, false); 1776var Position = { 1777 // set to true if needed, warning: firefox performance problems 1778 // NOT neeeded for page scrolling, only if draggable contained in 1779 // scrollable elements 1780 includeScrollOffsets: false, 1781 1782 // must be called before calling withinIncludingScrolloffset, every time the 1783 // page is scrolled 1784 prepare: function() { 1785 this.deltaX = window.pageXOffset 1786 || document.documentElement.scrollLeft 1787 || document.body.scrollLeft 1788 || 0; 1789 this.deltaY = window.pageYOffset 1790 || document.documentElement.scrollTop 1791 || document.body.scrollTop 1792 || 0; 1793 }, 1794 1795 realOffset: function(element) { 1796 var valueT = 0, valueL = 0; 1797 do { 1798 valueT += element.scrollTop || 0; 1799 valueL += element.scrollLeft || 0; 1800 element = element.parentNode; 1801 } while (element); 1802 return [valueL, valueT]; 1803 }, 1804 1805 cumulativeOffset: function(element) { 1806 var valueT = 0, valueL = 0; 1807 do { 1808 valueT += element.offsetTop || 0; 1809 valueL += element.offsetLeft || 0; 1810 element = element.offsetParent; 1811 } while (element); 1812 return [valueL, valueT]; 1813 }, 1814 1815 positionedOffset: function(element) { 1816 var valueT = 0, valueL = 0; 1817 do { 1818 valueT += element.offsetTop || 0; 1819 valueL += element.offsetLeft || 0; 1820 element = element.offsetParent; 1821 if (element) { 1822 p = Element.getStyle(element, 'position'); 1823 if (p == 'relative' || p == 'absolute') break; 1824 } 1825 } while (element); 1826 return [valueL, valueT]; 1827 }, 1828 1829 offsetParent: function(element) { 1830 if (element.offsetParent) return element.offsetParent; 1831 if (element == document.body) return element; 1832 1833 while ((element = element.parentNode) && element != document.body) 1834 if (Element.getStyle(element, 'position') != 'static') 1835 return element; 1836 1837 return document.body; 1838 }, 1839 1840 // caches x/y coordinate pair to use with overlap 1841 within: function(element, x, y) { 1842 if (this.includeScrollOffsets) 1843 return this.withinIncludingScrolloffsets(element, x, y); 1844 this.xcomp = x; 1845 this.ycomp = y; 1846 this.offset = this.cumulativeOffset(element); 1847 1848 return (y >= this.offset[1] && 1849 …
Large files files are truncated, but you can click here to view the full file