annotate .svn/pristine/16/1665bbb2717b49de68649a3ba32e9deb6f26e40f.svn-base @ 1082:997f6d7738f7 bug_531

In repo controller entry action, show the page for the file even if it's binary (so user still has access to history etc links). This makes it possible to use the entry action as the default when a file is clicked on
author Chris Cannam <chris.cannam@soundsoftware.ac.uk>
date Thu, 22 Nov 2012 18:04:17 +0000
parents cbb26bc654de
children
rev   line source
Chris@909 1 /* Prototype JavaScript framework, version 1.7
Chris@909 2 * (c) 2005-2010 Sam Stephenson
Chris@909 3 *
Chris@909 4 * Prototype is freely distributable under the terms of an MIT-style license.
Chris@909 5 * For details, see the Prototype web site: http://www.prototypejs.org/
Chris@909 6 *
Chris@909 7 *--------------------------------------------------------------------------*/
Chris@909 8
Chris@909 9 var Prototype = {
Chris@909 10
Chris@909 11 Version: '1.7',
Chris@909 12
Chris@909 13 Browser: (function(){
Chris@909 14 var ua = navigator.userAgent;
Chris@909 15 var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
Chris@909 16 return {
Chris@909 17 IE: !!window.attachEvent && !isOpera,
Chris@909 18 Opera: isOpera,
Chris@909 19 WebKit: ua.indexOf('AppleWebKit/') > -1,
Chris@909 20 Gecko: ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1,
Chris@909 21 MobileSafari: /Apple.*Mobile/.test(ua)
Chris@909 22 }
Chris@909 23 })(),
Chris@909 24
Chris@909 25 BrowserFeatures: {
Chris@909 26 XPath: !!document.evaluate,
Chris@909 27
Chris@909 28 SelectorsAPI: !!document.querySelector,
Chris@909 29
Chris@909 30 ElementExtensions: (function() {
Chris@909 31 var constructor = window.Element || window.HTMLElement;
Chris@909 32 return !!(constructor && constructor.prototype);
Chris@909 33 })(),
Chris@909 34 SpecificElementExtensions: (function() {
Chris@909 35 if (typeof window.HTMLDivElement !== 'undefined')
Chris@909 36 return true;
Chris@909 37
Chris@909 38 var div = document.createElement('div'),
Chris@909 39 form = document.createElement('form'),
Chris@909 40 isSupported = false;
Chris@909 41
Chris@909 42 if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) {
Chris@909 43 isSupported = true;
Chris@909 44 }
Chris@909 45
Chris@909 46 div = form = null;
Chris@909 47
Chris@909 48 return isSupported;
Chris@909 49 })()
Chris@909 50 },
Chris@909 51
Chris@909 52 ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
Chris@909 53 JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
Chris@909 54
Chris@909 55 emptyFunction: function() { },
Chris@909 56
Chris@909 57 K: function(x) { return x }
Chris@909 58 };
Chris@909 59
Chris@909 60 if (Prototype.Browser.MobileSafari)
Chris@909 61 Prototype.BrowserFeatures.SpecificElementExtensions = false;
Chris@909 62
Chris@909 63
Chris@909 64 var Abstract = { };
Chris@909 65
Chris@909 66
Chris@909 67 var Try = {
Chris@909 68 these: function() {
Chris@909 69 var returnValue;
Chris@909 70
Chris@909 71 for (var i = 0, length = arguments.length; i < length; i++) {
Chris@909 72 var lambda = arguments[i];
Chris@909 73 try {
Chris@909 74 returnValue = lambda();
Chris@909 75 break;
Chris@909 76 } catch (e) { }
Chris@909 77 }
Chris@909 78
Chris@909 79 return returnValue;
Chris@909 80 }
Chris@909 81 };
Chris@909 82
Chris@909 83 /* Based on Alex Arnell's inheritance implementation. */
Chris@909 84
Chris@909 85 var Class = (function() {
Chris@909 86
Chris@909 87 var IS_DONTENUM_BUGGY = (function(){
Chris@909 88 for (var p in { toString: 1 }) {
Chris@909 89 if (p === 'toString') return false;
Chris@909 90 }
Chris@909 91 return true;
Chris@909 92 })();
Chris@909 93
Chris@909 94 function subclass() {};
Chris@909 95 function create() {
Chris@909 96 var parent = null, properties = $A(arguments);
Chris@909 97 if (Object.isFunction(properties[0]))
Chris@909 98 parent = properties.shift();
Chris@909 99
Chris@909 100 function klass() {
Chris@909 101 this.initialize.apply(this, arguments);
Chris@909 102 }
Chris@909 103
Chris@909 104 Object.extend(klass, Class.Methods);
Chris@909 105 klass.superclass = parent;
Chris@909 106 klass.subclasses = [];
Chris@909 107
Chris@909 108 if (parent) {
Chris@909 109 subclass.prototype = parent.prototype;
Chris@909 110 klass.prototype = new subclass;
Chris@909 111 parent.subclasses.push(klass);
Chris@909 112 }
Chris@909 113
Chris@909 114 for (var i = 0, length = properties.length; i < length; i++)
Chris@909 115 klass.addMethods(properties[i]);
Chris@909 116
Chris@909 117 if (!klass.prototype.initialize)
Chris@909 118 klass.prototype.initialize = Prototype.emptyFunction;
Chris@909 119
Chris@909 120 klass.prototype.constructor = klass;
Chris@909 121 return klass;
Chris@909 122 }
Chris@909 123
Chris@909 124 function addMethods(source) {
Chris@909 125 var ancestor = this.superclass && this.superclass.prototype,
Chris@909 126 properties = Object.keys(source);
Chris@909 127
Chris@909 128 if (IS_DONTENUM_BUGGY) {
Chris@909 129 if (source.toString != Object.prototype.toString)
Chris@909 130 properties.push("toString");
Chris@909 131 if (source.valueOf != Object.prototype.valueOf)
Chris@909 132 properties.push("valueOf");
Chris@909 133 }
Chris@909 134
Chris@909 135 for (var i = 0, length = properties.length; i < length; i++) {
Chris@909 136 var property = properties[i], value = source[property];
Chris@909 137 if (ancestor && Object.isFunction(value) &&
Chris@909 138 value.argumentNames()[0] == "$super") {
Chris@909 139 var method = value;
Chris@909 140 value = (function(m) {
Chris@909 141 return function() { return ancestor[m].apply(this, arguments); };
Chris@909 142 })(property).wrap(method);
Chris@909 143
Chris@909 144 value.valueOf = method.valueOf.bind(method);
Chris@909 145 value.toString = method.toString.bind(method);
Chris@909 146 }
Chris@909 147 this.prototype[property] = value;
Chris@909 148 }
Chris@909 149
Chris@909 150 return this;
Chris@909 151 }
Chris@909 152
Chris@909 153 return {
Chris@909 154 create: create,
Chris@909 155 Methods: {
Chris@909 156 addMethods: addMethods
Chris@909 157 }
Chris@909 158 };
Chris@909 159 })();
Chris@909 160 (function() {
Chris@909 161
Chris@909 162 var _toString = Object.prototype.toString,
Chris@909 163 NULL_TYPE = 'Null',
Chris@909 164 UNDEFINED_TYPE = 'Undefined',
Chris@909 165 BOOLEAN_TYPE = 'Boolean',
Chris@909 166 NUMBER_TYPE = 'Number',
Chris@909 167 STRING_TYPE = 'String',
Chris@909 168 OBJECT_TYPE = 'Object',
Chris@909 169 FUNCTION_CLASS = '[object Function]',
Chris@909 170 BOOLEAN_CLASS = '[object Boolean]',
Chris@909 171 NUMBER_CLASS = '[object Number]',
Chris@909 172 STRING_CLASS = '[object String]',
Chris@909 173 ARRAY_CLASS = '[object Array]',
Chris@909 174 DATE_CLASS = '[object Date]',
Chris@909 175 NATIVE_JSON_STRINGIFY_SUPPORT = window.JSON &&
Chris@909 176 typeof JSON.stringify === 'function' &&
Chris@909 177 JSON.stringify(0) === '0' &&
Chris@909 178 typeof JSON.stringify(Prototype.K) === 'undefined';
Chris@909 179
Chris@909 180 function Type(o) {
Chris@909 181 switch(o) {
Chris@909 182 case null: return NULL_TYPE;
Chris@909 183 case (void 0): return UNDEFINED_TYPE;
Chris@909 184 }
Chris@909 185 var type = typeof o;
Chris@909 186 switch(type) {
Chris@909 187 case 'boolean': return BOOLEAN_TYPE;
Chris@909 188 case 'number': return NUMBER_TYPE;
Chris@909 189 case 'string': return STRING_TYPE;
Chris@909 190 }
Chris@909 191 return OBJECT_TYPE;
Chris@909 192 }
Chris@909 193
Chris@909 194 function extend(destination, source) {
Chris@909 195 for (var property in source)
Chris@909 196 destination[property] = source[property];
Chris@909 197 return destination;
Chris@909 198 }
Chris@909 199
Chris@909 200 function inspect(object) {
Chris@909 201 try {
Chris@909 202 if (isUndefined(object)) return 'undefined';
Chris@909 203 if (object === null) return 'null';
Chris@909 204 return object.inspect ? object.inspect() : String(object);
Chris@909 205 } catch (e) {
Chris@909 206 if (e instanceof RangeError) return '...';
Chris@909 207 throw e;
Chris@909 208 }
Chris@909 209 }
Chris@909 210
Chris@909 211 function toJSON(value) {
Chris@909 212 return Str('', { '': value }, []);
Chris@909 213 }
Chris@909 214
Chris@909 215 function Str(key, holder, stack) {
Chris@909 216 var value = holder[key],
Chris@909 217 type = typeof value;
Chris@909 218
Chris@909 219 if (Type(value) === OBJECT_TYPE && typeof value.toJSON === 'function') {
Chris@909 220 value = value.toJSON(key);
Chris@909 221 }
Chris@909 222
Chris@909 223 var _class = _toString.call(value);
Chris@909 224
Chris@909 225 switch (_class) {
Chris@909 226 case NUMBER_CLASS:
Chris@909 227 case BOOLEAN_CLASS:
Chris@909 228 case STRING_CLASS:
Chris@909 229 value = value.valueOf();
Chris@909 230 }
Chris@909 231
Chris@909 232 switch (value) {
Chris@909 233 case null: return 'null';
Chris@909 234 case true: return 'true';
Chris@909 235 case false: return 'false';
Chris@909 236 }
Chris@909 237
Chris@909 238 type = typeof value;
Chris@909 239 switch (type) {
Chris@909 240 case 'string':
Chris@909 241 return value.inspect(true);
Chris@909 242 case 'number':
Chris@909 243 return isFinite(value) ? String(value) : 'null';
Chris@909 244 case 'object':
Chris@909 245
Chris@909 246 for (var i = 0, length = stack.length; i < length; i++) {
Chris@909 247 if (stack[i] === value) { throw new TypeError(); }
Chris@909 248 }
Chris@909 249 stack.push(value);
Chris@909 250
Chris@909 251 var partial = [];
Chris@909 252 if (_class === ARRAY_CLASS) {
Chris@909 253 for (var i = 0, length = value.length; i < length; i++) {
Chris@909 254 var str = Str(i, value, stack);
Chris@909 255 partial.push(typeof str === 'undefined' ? 'null' : str);
Chris@909 256 }
Chris@909 257 partial = '[' + partial.join(',') + ']';
Chris@909 258 } else {
Chris@909 259 var keys = Object.keys(value);
Chris@909 260 for (var i = 0, length = keys.length; i < length; i++) {
Chris@909 261 var key = keys[i], str = Str(key, value, stack);
Chris@909 262 if (typeof str !== "undefined") {
Chris@909 263 partial.push(key.inspect(true)+ ':' + str);
Chris@909 264 }
Chris@909 265 }
Chris@909 266 partial = '{' + partial.join(',') + '}';
Chris@909 267 }
Chris@909 268 stack.pop();
Chris@909 269 return partial;
Chris@909 270 }
Chris@909 271 }
Chris@909 272
Chris@909 273 function stringify(object) {
Chris@909 274 return JSON.stringify(object);
Chris@909 275 }
Chris@909 276
Chris@909 277 function toQueryString(object) {
Chris@909 278 return $H(object).toQueryString();
Chris@909 279 }
Chris@909 280
Chris@909 281 function toHTML(object) {
Chris@909 282 return object && object.toHTML ? object.toHTML() : String.interpret(object);
Chris@909 283 }
Chris@909 284
Chris@909 285 function keys(object) {
Chris@909 286 if (Type(object) !== OBJECT_TYPE) { throw new TypeError(); }
Chris@909 287 var results = [];
Chris@909 288 for (var property in object) {
Chris@909 289 if (object.hasOwnProperty(property)) {
Chris@909 290 results.push(property);
Chris@909 291 }
Chris@909 292 }
Chris@909 293 return results;
Chris@909 294 }
Chris@909 295
Chris@909 296 function values(object) {
Chris@909 297 var results = [];
Chris@909 298 for (var property in object)
Chris@909 299 results.push(object[property]);
Chris@909 300 return results;
Chris@909 301 }
Chris@909 302
Chris@909 303 function clone(object) {
Chris@909 304 return extend({ }, object);
Chris@909 305 }
Chris@909 306
Chris@909 307 function isElement(object) {
Chris@909 308 return !!(object && object.nodeType == 1);
Chris@909 309 }
Chris@909 310
Chris@909 311 function isArray(object) {
Chris@909 312 return _toString.call(object) === ARRAY_CLASS;
Chris@909 313 }
Chris@909 314
Chris@909 315 var hasNativeIsArray = (typeof Array.isArray == 'function')
Chris@909 316 && Array.isArray([]) && !Array.isArray({});
Chris@909 317
Chris@909 318 if (hasNativeIsArray) {
Chris@909 319 isArray = Array.isArray;
Chris@909 320 }
Chris@909 321
Chris@909 322 function isHash(object) {
Chris@909 323 return object instanceof Hash;
Chris@909 324 }
Chris@909 325
Chris@909 326 function isFunction(object) {
Chris@909 327 return _toString.call(object) === FUNCTION_CLASS;
Chris@909 328 }
Chris@909 329
Chris@909 330 function isString(object) {
Chris@909 331 return _toString.call(object) === STRING_CLASS;
Chris@909 332 }
Chris@909 333
Chris@909 334 function isNumber(object) {
Chris@909 335 return _toString.call(object) === NUMBER_CLASS;
Chris@909 336 }
Chris@909 337
Chris@909 338 function isDate(object) {
Chris@909 339 return _toString.call(object) === DATE_CLASS;
Chris@909 340 }
Chris@909 341
Chris@909 342 function isUndefined(object) {
Chris@909 343 return typeof object === "undefined";
Chris@909 344 }
Chris@909 345
Chris@909 346 extend(Object, {
Chris@909 347 extend: extend,
Chris@909 348 inspect: inspect,
Chris@909 349 toJSON: NATIVE_JSON_STRINGIFY_SUPPORT ? stringify : toJSON,
Chris@909 350 toQueryString: toQueryString,
Chris@909 351 toHTML: toHTML,
Chris@909 352 keys: Object.keys || keys,
Chris@909 353 values: values,
Chris@909 354 clone: clone,
Chris@909 355 isElement: isElement,
Chris@909 356 isArray: isArray,
Chris@909 357 isHash: isHash,
Chris@909 358 isFunction: isFunction,
Chris@909 359 isString: isString,
Chris@909 360 isNumber: isNumber,
Chris@909 361 isDate: isDate,
Chris@909 362 isUndefined: isUndefined
Chris@909 363 });
Chris@909 364 })();
Chris@909 365 Object.extend(Function.prototype, (function() {
Chris@909 366 var slice = Array.prototype.slice;
Chris@909 367
Chris@909 368 function update(array, args) {
Chris@909 369 var arrayLength = array.length, length = args.length;
Chris@909 370 while (length--) array[arrayLength + length] = args[length];
Chris@909 371 return array;
Chris@909 372 }
Chris@909 373
Chris@909 374 function merge(array, args) {
Chris@909 375 array = slice.call(array, 0);
Chris@909 376 return update(array, args);
Chris@909 377 }
Chris@909 378
Chris@909 379 function argumentNames() {
Chris@909 380 var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
Chris@909 381 .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
Chris@909 382 .replace(/\s+/g, '').split(',');
Chris@909 383 return names.length == 1 && !names[0] ? [] : names;
Chris@909 384 }
Chris@909 385
Chris@909 386 function bind(context) {
Chris@909 387 if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
Chris@909 388 var __method = this, args = slice.call(arguments, 1);
Chris@909 389 return function() {
Chris@909 390 var a = merge(args, arguments);
Chris@909 391 return __method.apply(context, a);
Chris@909 392 }
Chris@909 393 }
Chris@909 394
Chris@909 395 function bindAsEventListener(context) {
Chris@909 396 var __method = this, args = slice.call(arguments, 1);
Chris@909 397 return function(event) {
Chris@909 398 var a = update([event || window.event], args);
Chris@909 399 return __method.apply(context, a);
Chris@909 400 }
Chris@909 401 }
Chris@909 402
Chris@909 403 function curry() {
Chris@909 404 if (!arguments.length) return this;
Chris@909 405 var __method = this, args = slice.call(arguments, 0);
Chris@909 406 return function() {
Chris@909 407 var a = merge(args, arguments);
Chris@909 408 return __method.apply(this, a);
Chris@909 409 }
Chris@909 410 }
Chris@909 411
Chris@909 412 function delay(timeout) {
Chris@909 413 var __method = this, args = slice.call(arguments, 1);
Chris@909 414 timeout = timeout * 1000;
Chris@909 415 return window.setTimeout(function() {
Chris@909 416 return __method.apply(__method, args);
Chris@909 417 }, timeout);
Chris@909 418 }
Chris@909 419
Chris@909 420 function defer() {
Chris@909 421 var args = update([0.01], arguments);
Chris@909 422 return this.delay.apply(this, args);
Chris@909 423 }
Chris@909 424
Chris@909 425 function wrap(wrapper) {
Chris@909 426 var __method = this;
Chris@909 427 return function() {
Chris@909 428 var a = update([__method.bind(this)], arguments);
Chris@909 429 return wrapper.apply(this, a);
Chris@909 430 }
Chris@909 431 }
Chris@909 432
Chris@909 433 function methodize() {
Chris@909 434 if (this._methodized) return this._methodized;
Chris@909 435 var __method = this;
Chris@909 436 return this._methodized = function() {
Chris@909 437 var a = update([this], arguments);
Chris@909 438 return __method.apply(null, a);
Chris@909 439 };
Chris@909 440 }
Chris@909 441
Chris@909 442 return {
Chris@909 443 argumentNames: argumentNames,
Chris@909 444 bind: bind,
Chris@909 445 bindAsEventListener: bindAsEventListener,
Chris@909 446 curry: curry,
Chris@909 447 delay: delay,
Chris@909 448 defer: defer,
Chris@909 449 wrap: wrap,
Chris@909 450 methodize: methodize
Chris@909 451 }
Chris@909 452 })());
Chris@909 453
Chris@909 454
Chris@909 455
Chris@909 456 (function(proto) {
Chris@909 457
Chris@909 458
Chris@909 459 function toISOString() {
Chris@909 460 return this.getUTCFullYear() + '-' +
Chris@909 461 (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
Chris@909 462 this.getUTCDate().toPaddedString(2) + 'T' +
Chris@909 463 this.getUTCHours().toPaddedString(2) + ':' +
Chris@909 464 this.getUTCMinutes().toPaddedString(2) + ':' +
Chris@909 465 this.getUTCSeconds().toPaddedString(2) + 'Z';
Chris@909 466 }
Chris@909 467
Chris@909 468
Chris@909 469 function toJSON() {
Chris@909 470 return this.toISOString();
Chris@909 471 }
Chris@909 472
Chris@909 473 if (!proto.toISOString) proto.toISOString = toISOString;
Chris@909 474 if (!proto.toJSON) proto.toJSON = toJSON;
Chris@909 475
Chris@909 476 })(Date.prototype);
Chris@909 477
Chris@909 478
Chris@909 479 RegExp.prototype.match = RegExp.prototype.test;
Chris@909 480
Chris@909 481 RegExp.escape = function(str) {
Chris@909 482 return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
Chris@909 483 };
Chris@909 484 var PeriodicalExecuter = Class.create({
Chris@909 485 initialize: function(callback, frequency) {
Chris@909 486 this.callback = callback;
Chris@909 487 this.frequency = frequency;
Chris@909 488 this.currentlyExecuting = false;
Chris@909 489
Chris@909 490 this.registerCallback();
Chris@909 491 },
Chris@909 492
Chris@909 493 registerCallback: function() {
Chris@909 494 this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
Chris@909 495 },
Chris@909 496
Chris@909 497 execute: function() {
Chris@909 498 this.callback(this);
Chris@909 499 },
Chris@909 500
Chris@909 501 stop: function() {
Chris@909 502 if (!this.timer) return;
Chris@909 503 clearInterval(this.timer);
Chris@909 504 this.timer = null;
Chris@909 505 },
Chris@909 506
Chris@909 507 onTimerEvent: function() {
Chris@909 508 if (!this.currentlyExecuting) {
Chris@909 509 try {
Chris@909 510 this.currentlyExecuting = true;
Chris@909 511 this.execute();
Chris@909 512 this.currentlyExecuting = false;
Chris@909 513 } catch(e) {
Chris@909 514 this.currentlyExecuting = false;
Chris@909 515 throw e;
Chris@909 516 }
Chris@909 517 }
Chris@909 518 }
Chris@909 519 });
Chris@909 520 Object.extend(String, {
Chris@909 521 interpret: function(value) {
Chris@909 522 return value == null ? '' : String(value);
Chris@909 523 },
Chris@909 524 specialChar: {
Chris@909 525 '\b': '\\b',
Chris@909 526 '\t': '\\t',
Chris@909 527 '\n': '\\n',
Chris@909 528 '\f': '\\f',
Chris@909 529 '\r': '\\r',
Chris@909 530 '\\': '\\\\'
Chris@909 531 }
Chris@909 532 });
Chris@909 533
Chris@909 534 Object.extend(String.prototype, (function() {
Chris@909 535 var NATIVE_JSON_PARSE_SUPPORT = window.JSON &&
Chris@909 536 typeof JSON.parse === 'function' &&
Chris@909 537 JSON.parse('{"test": true}').test;
Chris@909 538
Chris@909 539 function prepareReplacement(replacement) {
Chris@909 540 if (Object.isFunction(replacement)) return replacement;
Chris@909 541 var template = new Template(replacement);
Chris@909 542 return function(match) { return template.evaluate(match) };
Chris@909 543 }
Chris@909 544
Chris@909 545 function gsub(pattern, replacement) {
Chris@909 546 var result = '', source = this, match;
Chris@909 547 replacement = prepareReplacement(replacement);
Chris@909 548
Chris@909 549 if (Object.isString(pattern))
Chris@909 550 pattern = RegExp.escape(pattern);
Chris@909 551
Chris@909 552 if (!(pattern.length || pattern.source)) {
Chris@909 553 replacement = replacement('');
Chris@909 554 return replacement + source.split('').join(replacement) + replacement;
Chris@909 555 }
Chris@909 556
Chris@909 557 while (source.length > 0) {
Chris@909 558 if (match = source.match(pattern)) {
Chris@909 559 result += source.slice(0, match.index);
Chris@909 560 result += String.interpret(replacement(match));
Chris@909 561 source = source.slice(match.index + match[0].length);
Chris@909 562 } else {
Chris@909 563 result += source, source = '';
Chris@909 564 }
Chris@909 565 }
Chris@909 566 return result;
Chris@909 567 }
Chris@909 568
Chris@909 569 function sub(pattern, replacement, count) {
Chris@909 570 replacement = prepareReplacement(replacement);
Chris@909 571 count = Object.isUndefined(count) ? 1 : count;
Chris@909 572
Chris@909 573 return this.gsub(pattern, function(match) {
Chris@909 574 if (--count < 0) return match[0];
Chris@909 575 return replacement(match);
Chris@909 576 });
Chris@909 577 }
Chris@909 578
Chris@909 579 function scan(pattern, iterator) {
Chris@909 580 this.gsub(pattern, iterator);
Chris@909 581 return String(this);
Chris@909 582 }
Chris@909 583
Chris@909 584 function truncate(length, truncation) {
Chris@909 585 length = length || 30;
Chris@909 586 truncation = Object.isUndefined(truncation) ? '...' : truncation;
Chris@909 587 return this.length > length ?
Chris@909 588 this.slice(0, length - truncation.length) + truncation : String(this);
Chris@909 589 }
Chris@909 590
Chris@909 591 function strip() {
Chris@909 592 return this.replace(/^\s+/, '').replace(/\s+$/, '');
Chris@909 593 }
Chris@909 594
Chris@909 595 function stripTags() {
Chris@909 596 return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, '');
Chris@909 597 }
Chris@909 598
Chris@909 599 function stripScripts() {
Chris@909 600 return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
Chris@909 601 }
Chris@909 602
Chris@909 603 function extractScripts() {
Chris@909 604 var matchAll = new RegExp(Prototype.ScriptFragment, 'img'),
Chris@909 605 matchOne = new RegExp(Prototype.ScriptFragment, 'im');
Chris@909 606 return (this.match(matchAll) || []).map(function(scriptTag) {
Chris@909 607 return (scriptTag.match(matchOne) || ['', ''])[1];
Chris@909 608 });
Chris@909 609 }
Chris@909 610
Chris@909 611 function evalScripts() {
Chris@909 612 return this.extractScripts().map(function(script) { return eval(script) });
Chris@909 613 }
Chris@909 614
Chris@909 615 function escapeHTML() {
Chris@909 616 return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
Chris@909 617 }
Chris@909 618
Chris@909 619 function unescapeHTML() {
Chris@909 620 return this.stripTags().replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&amp;/g,'&');
Chris@909 621 }
Chris@909 622
Chris@909 623
Chris@909 624 function toQueryParams(separator) {
Chris@909 625 var match = this.strip().match(/([^?#]*)(#.*)?$/);
Chris@909 626 if (!match) return { };
Chris@909 627
Chris@909 628 return match[1].split(separator || '&').inject({ }, function(hash, pair) {
Chris@909 629 if ((pair = pair.split('='))[0]) {
Chris@909 630 var key = decodeURIComponent(pair.shift()),
Chris@909 631 value = pair.length > 1 ? pair.join('=') : pair[0];
Chris@909 632
Chris@909 633 if (value != undefined) value = decodeURIComponent(value);
Chris@909 634
Chris@909 635 if (key in hash) {
Chris@909 636 if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
Chris@909 637 hash[key].push(value);
Chris@909 638 }
Chris@909 639 else hash[key] = value;
Chris@909 640 }
Chris@909 641 return hash;
Chris@909 642 });
Chris@909 643 }
Chris@909 644
Chris@909 645 function toArray() {
Chris@909 646 return this.split('');
Chris@909 647 }
Chris@909 648
Chris@909 649 function succ() {
Chris@909 650 return this.slice(0, this.length - 1) +
Chris@909 651 String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
Chris@909 652 }
Chris@909 653
Chris@909 654 function times(count) {
Chris@909 655 return count < 1 ? '' : new Array(count + 1).join(this);
Chris@909 656 }
Chris@909 657
Chris@909 658 function camelize() {
Chris@909 659 return this.replace(/-+(.)?/g, function(match, chr) {
Chris@909 660 return chr ? chr.toUpperCase() : '';
Chris@909 661 });
Chris@909 662 }
Chris@909 663
Chris@909 664 function capitalize() {
Chris@909 665 return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
Chris@909 666 }
Chris@909 667
Chris@909 668 function underscore() {
Chris@909 669 return this.replace(/::/g, '/')
Chris@909 670 .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
Chris@909 671 .replace(/([a-z\d])([A-Z])/g, '$1_$2')
Chris@909 672 .replace(/-/g, '_')
Chris@909 673 .toLowerCase();
Chris@909 674 }
Chris@909 675
Chris@909 676 function dasherize() {
Chris@909 677 return this.replace(/_/g, '-');
Chris@909 678 }
Chris@909 679
Chris@909 680 function inspect(useDoubleQuotes) {
Chris@909 681 var escapedString = this.replace(/[\x00-\x1f\\]/g, function(character) {
Chris@909 682 if (character in String.specialChar) {
Chris@909 683 return String.specialChar[character];
Chris@909 684 }
Chris@909 685 return '\\u00' + character.charCodeAt().toPaddedString(2, 16);
Chris@909 686 });
Chris@909 687 if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
Chris@909 688 return "'" + escapedString.replace(/'/g, '\\\'') + "'";
Chris@909 689 }
Chris@909 690
Chris@909 691 function unfilterJSON(filter) {
Chris@909 692 return this.replace(filter || Prototype.JSONFilter, '$1');
Chris@909 693 }
Chris@909 694
Chris@909 695 function isJSON() {
Chris@909 696 var str = this;
Chris@909 697 if (str.blank()) return false;
Chris@909 698 str = str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@');
Chris@909 699 str = str.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
Chris@909 700 str = str.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
Chris@909 701 return (/^[\],:{}\s]*$/).test(str);
Chris@909 702 }
Chris@909 703
Chris@909 704 function evalJSON(sanitize) {
Chris@909 705 var json = this.unfilterJSON(),
Chris@909 706 cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
Chris@909 707 if (cx.test(json)) {
Chris@909 708 json = json.replace(cx, function (a) {
Chris@909 709 return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
Chris@909 710 });
Chris@909 711 }
Chris@909 712 try {
Chris@909 713 if (!sanitize || json.isJSON()) return eval('(' + json + ')');
Chris@909 714 } catch (e) { }
Chris@909 715 throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
Chris@909 716 }
Chris@909 717
Chris@909 718 function parseJSON() {
Chris@909 719 var json = this.unfilterJSON();
Chris@909 720 return JSON.parse(json);
Chris@909 721 }
Chris@909 722
Chris@909 723 function include(pattern) {
Chris@909 724 return this.indexOf(pattern) > -1;
Chris@909 725 }
Chris@909 726
Chris@909 727 function startsWith(pattern) {
Chris@909 728 return this.lastIndexOf(pattern, 0) === 0;
Chris@909 729 }
Chris@909 730
Chris@909 731 function endsWith(pattern) {
Chris@909 732 var d = this.length - pattern.length;
Chris@909 733 return d >= 0 && this.indexOf(pattern, d) === d;
Chris@909 734 }
Chris@909 735
Chris@909 736 function empty() {
Chris@909 737 return this == '';
Chris@909 738 }
Chris@909 739
Chris@909 740 function blank() {
Chris@909 741 return /^\s*$/.test(this);
Chris@909 742 }
Chris@909 743
Chris@909 744 function interpolate(object, pattern) {
Chris@909 745 return new Template(this, pattern).evaluate(object);
Chris@909 746 }
Chris@909 747
Chris@909 748 return {
Chris@909 749 gsub: gsub,
Chris@909 750 sub: sub,
Chris@909 751 scan: scan,
Chris@909 752 truncate: truncate,
Chris@909 753 strip: String.prototype.trim || strip,
Chris@909 754 stripTags: stripTags,
Chris@909 755 stripScripts: stripScripts,
Chris@909 756 extractScripts: extractScripts,
Chris@909 757 evalScripts: evalScripts,
Chris@909 758 escapeHTML: escapeHTML,
Chris@909 759 unescapeHTML: unescapeHTML,
Chris@909 760 toQueryParams: toQueryParams,
Chris@909 761 parseQuery: toQueryParams,
Chris@909 762 toArray: toArray,
Chris@909 763 succ: succ,
Chris@909 764 times: times,
Chris@909 765 camelize: camelize,
Chris@909 766 capitalize: capitalize,
Chris@909 767 underscore: underscore,
Chris@909 768 dasherize: dasherize,
Chris@909 769 inspect: inspect,
Chris@909 770 unfilterJSON: unfilterJSON,
Chris@909 771 isJSON: isJSON,
Chris@909 772 evalJSON: NATIVE_JSON_PARSE_SUPPORT ? parseJSON : evalJSON,
Chris@909 773 include: include,
Chris@909 774 startsWith: startsWith,
Chris@909 775 endsWith: endsWith,
Chris@909 776 empty: empty,
Chris@909 777 blank: blank,
Chris@909 778 interpolate: interpolate
Chris@909 779 };
Chris@909 780 })());
Chris@909 781
Chris@909 782 var Template = Class.create({
Chris@909 783 initialize: function(template, pattern) {
Chris@909 784 this.template = template.toString();
Chris@909 785 this.pattern = pattern || Template.Pattern;
Chris@909 786 },
Chris@909 787
Chris@909 788 evaluate: function(object) {
Chris@909 789 if (object && Object.isFunction(object.toTemplateReplacements))
Chris@909 790 object = object.toTemplateReplacements();
Chris@909 791
Chris@909 792 return this.template.gsub(this.pattern, function(match) {
Chris@909 793 if (object == null) return (match[1] + '');
Chris@909 794
Chris@909 795 var before = match[1] || '';
Chris@909 796 if (before == '\\') return match[2];
Chris@909 797
Chris@909 798 var ctx = object, expr = match[3],
Chris@909 799 pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
Chris@909 800
Chris@909 801 match = pattern.exec(expr);
Chris@909 802 if (match == null) return before;
Chris@909 803
Chris@909 804 while (match != null) {
Chris@909 805 var comp = match[1].startsWith('[') ? match[2].replace(/\\\\]/g, ']') : match[1];
Chris@909 806 ctx = ctx[comp];
Chris@909 807 if (null == ctx || '' == match[3]) break;
Chris@909 808 expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
Chris@909 809 match = pattern.exec(expr);
Chris@909 810 }
Chris@909 811
Chris@909 812 return before + String.interpret(ctx);
Chris@909 813 });
Chris@909 814 }
Chris@909 815 });
Chris@909 816 Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
Chris@909 817
Chris@909 818 var $break = { };
Chris@909 819
Chris@909 820 var Enumerable = (function() {
Chris@909 821 function each(iterator, context) {
Chris@909 822 var index = 0;
Chris@909 823 try {
Chris@909 824 this._each(function(value) {
Chris@909 825 iterator.call(context, value, index++);
Chris@909 826 });
Chris@909 827 } catch (e) {
Chris@909 828 if (e != $break) throw e;
Chris@909 829 }
Chris@909 830 return this;
Chris@909 831 }
Chris@909 832
Chris@909 833 function eachSlice(number, iterator, context) {
Chris@909 834 var index = -number, slices = [], array = this.toArray();
Chris@909 835 if (number < 1) return array;
Chris@909 836 while ((index += number) < array.length)
Chris@909 837 slices.push(array.slice(index, index+number));
Chris@909 838 return slices.collect(iterator, context);
Chris@909 839 }
Chris@909 840
Chris@909 841 function all(iterator, context) {
Chris@909 842 iterator = iterator || Prototype.K;
Chris@909 843 var result = true;
Chris@909 844 this.each(function(value, index) {
Chris@909 845 result = result && !!iterator.call(context, value, index);
Chris@909 846 if (!result) throw $break;
Chris@909 847 });
Chris@909 848 return result;
Chris@909 849 }
Chris@909 850
Chris@909 851 function any(iterator, context) {
Chris@909 852 iterator = iterator || Prototype.K;
Chris@909 853 var result = false;
Chris@909 854 this.each(function(value, index) {
Chris@909 855 if (result = !!iterator.call(context, value, index))
Chris@909 856 throw $break;
Chris@909 857 });
Chris@909 858 return result;
Chris@909 859 }
Chris@909 860
Chris@909 861 function collect(iterator, context) {
Chris@909 862 iterator = iterator || Prototype.K;
Chris@909 863 var results = [];
Chris@909 864 this.each(function(value, index) {
Chris@909 865 results.push(iterator.call(context, value, index));
Chris@909 866 });
Chris@909 867 return results;
Chris@909 868 }
Chris@909 869
Chris@909 870 function detect(iterator, context) {
Chris@909 871 var result;
Chris@909 872 this.each(function(value, index) {
Chris@909 873 if (iterator.call(context, value, index)) {
Chris@909 874 result = value;
Chris@909 875 throw $break;
Chris@909 876 }
Chris@909 877 });
Chris@909 878 return result;
Chris@909 879 }
Chris@909 880
Chris@909 881 function findAll(iterator, context) {
Chris@909 882 var results = [];
Chris@909 883 this.each(function(value, index) {
Chris@909 884 if (iterator.call(context, value, index))
Chris@909 885 results.push(value);
Chris@909 886 });
Chris@909 887 return results;
Chris@909 888 }
Chris@909 889
Chris@909 890 function grep(filter, iterator, context) {
Chris@909 891 iterator = iterator || Prototype.K;
Chris@909 892 var results = [];
Chris@909 893
Chris@909 894 if (Object.isString(filter))
Chris@909 895 filter = new RegExp(RegExp.escape(filter));
Chris@909 896
Chris@909 897 this.each(function(value, index) {
Chris@909 898 if (filter.match(value))
Chris@909 899 results.push(iterator.call(context, value, index));
Chris@909 900 });
Chris@909 901 return results;
Chris@909 902 }
Chris@909 903
Chris@909 904 function include(object) {
Chris@909 905 if (Object.isFunction(this.indexOf))
Chris@909 906 if (this.indexOf(object) != -1) return true;
Chris@909 907
Chris@909 908 var found = false;
Chris@909 909 this.each(function(value) {
Chris@909 910 if (value == object) {
Chris@909 911 found = true;
Chris@909 912 throw $break;
Chris@909 913 }
Chris@909 914 });
Chris@909 915 return found;
Chris@909 916 }
Chris@909 917
Chris@909 918 function inGroupsOf(number, fillWith) {
Chris@909 919 fillWith = Object.isUndefined(fillWith) ? null : fillWith;
Chris@909 920 return this.eachSlice(number, function(slice) {
Chris@909 921 while(slice.length < number) slice.push(fillWith);
Chris@909 922 return slice;
Chris@909 923 });
Chris@909 924 }
Chris@909 925
Chris@909 926 function inject(memo, iterator, context) {
Chris@909 927 this.each(function(value, index) {
Chris@909 928 memo = iterator.call(context, memo, value, index);
Chris@909 929 });
Chris@909 930 return memo;
Chris@909 931 }
Chris@909 932
Chris@909 933 function invoke(method) {
Chris@909 934 var args = $A(arguments).slice(1);
Chris@909 935 return this.map(function(value) {
Chris@909 936 return value[method].apply(value, args);
Chris@909 937 });
Chris@909 938 }
Chris@909 939
Chris@909 940 function max(iterator, context) {
Chris@909 941 iterator = iterator || Prototype.K;
Chris@909 942 var result;
Chris@909 943 this.each(function(value, index) {
Chris@909 944 value = iterator.call(context, value, index);
Chris@909 945 if (result == null || value >= result)
Chris@909 946 result = value;
Chris@909 947 });
Chris@909 948 return result;
Chris@909 949 }
Chris@909 950
Chris@909 951 function min(iterator, context) {
Chris@909 952 iterator = iterator || Prototype.K;
Chris@909 953 var result;
Chris@909 954 this.each(function(value, index) {
Chris@909 955 value = iterator.call(context, value, index);
Chris@909 956 if (result == null || value < result)
Chris@909 957 result = value;
Chris@909 958 });
Chris@909 959 return result;
Chris@909 960 }
Chris@909 961
Chris@909 962 function partition(iterator, context) {
Chris@909 963 iterator = iterator || Prototype.K;
Chris@909 964 var trues = [], falses = [];
Chris@909 965 this.each(function(value, index) {
Chris@909 966 (iterator.call(context, value, index) ?
Chris@909 967 trues : falses).push(value);
Chris@909 968 });
Chris@909 969 return [trues, falses];
Chris@909 970 }
Chris@909 971
Chris@909 972 function pluck(property) {
Chris@909 973 var results = [];
Chris@909 974 this.each(function(value) {
Chris@909 975 results.push(value[property]);
Chris@909 976 });
Chris@909 977 return results;
Chris@909 978 }
Chris@909 979
Chris@909 980 function reject(iterator, context) {
Chris@909 981 var results = [];
Chris@909 982 this.each(function(value, index) {
Chris@909 983 if (!iterator.call(context, value, index))
Chris@909 984 results.push(value);
Chris@909 985 });
Chris@909 986 return results;
Chris@909 987 }
Chris@909 988
Chris@909 989 function sortBy(iterator, context) {
Chris@909 990 return this.map(function(value, index) {
Chris@909 991 return {
Chris@909 992 value: value,
Chris@909 993 criteria: iterator.call(context, value, index)
Chris@909 994 };
Chris@909 995 }).sort(function(left, right) {
Chris@909 996 var a = left.criteria, b = right.criteria;
Chris@909 997 return a < b ? -1 : a > b ? 1 : 0;
Chris@909 998 }).pluck('value');
Chris@909 999 }
Chris@909 1000
Chris@909 1001 function toArray() {
Chris@909 1002 return this.map();
Chris@909 1003 }
Chris@909 1004
Chris@909 1005 function zip() {
Chris@909 1006 var iterator = Prototype.K, args = $A(arguments);
Chris@909 1007 if (Object.isFunction(args.last()))
Chris@909 1008 iterator = args.pop();
Chris@909 1009
Chris@909 1010 var collections = [this].concat(args).map($A);
Chris@909 1011 return this.map(function(value, index) {
Chris@909 1012 return iterator(collections.pluck(index));
Chris@909 1013 });
Chris@909 1014 }
Chris@909 1015
Chris@909 1016 function size() {
Chris@909 1017 return this.toArray().length;
Chris@909 1018 }
Chris@909 1019
Chris@909 1020 function inspect() {
Chris@909 1021 return '#<Enumerable:' + this.toArray().inspect() + '>';
Chris@909 1022 }
Chris@909 1023
Chris@909 1024
Chris@909 1025
Chris@909 1026
Chris@909 1027
Chris@909 1028
Chris@909 1029
Chris@909 1030
Chris@909 1031
Chris@909 1032 return {
Chris@909 1033 each: each,
Chris@909 1034 eachSlice: eachSlice,
Chris@909 1035 all: all,
Chris@909 1036 every: all,
Chris@909 1037 any: any,
Chris@909 1038 some: any,
Chris@909 1039 collect: collect,
Chris@909 1040 map: collect,
Chris@909 1041 detect: detect,
Chris@909 1042 findAll: findAll,
Chris@909 1043 select: findAll,
Chris@909 1044 filter: findAll,
Chris@909 1045 grep: grep,
Chris@909 1046 include: include,
Chris@909 1047 member: include,
Chris@909 1048 inGroupsOf: inGroupsOf,
Chris@909 1049 inject: inject,
Chris@909 1050 invoke: invoke,
Chris@909 1051 max: max,
Chris@909 1052 min: min,
Chris@909 1053 partition: partition,
Chris@909 1054 pluck: pluck,
Chris@909 1055 reject: reject,
Chris@909 1056 sortBy: sortBy,
Chris@909 1057 toArray: toArray,
Chris@909 1058 entries: toArray,
Chris@909 1059 zip: zip,
Chris@909 1060 size: size,
Chris@909 1061 inspect: inspect,
Chris@909 1062 find: detect
Chris@909 1063 };
Chris@909 1064 })();
Chris@909 1065
Chris@909 1066 function $A(iterable) {
Chris@909 1067 if (!iterable) return [];
Chris@909 1068 if ('toArray' in Object(iterable)) return iterable.toArray();
Chris@909 1069 var length = iterable.length || 0, results = new Array(length);
Chris@909 1070 while (length--) results[length] = iterable[length];
Chris@909 1071 return results;
Chris@909 1072 }
Chris@909 1073
Chris@909 1074
Chris@909 1075 function $w(string) {
Chris@909 1076 if (!Object.isString(string)) return [];
Chris@909 1077 string = string.strip();
Chris@909 1078 return string ? string.split(/\s+/) : [];
Chris@909 1079 }
Chris@909 1080
Chris@909 1081 Array.from = $A;
Chris@909 1082
Chris@909 1083
Chris@909 1084 (function() {
Chris@909 1085 var arrayProto = Array.prototype,
Chris@909 1086 slice = arrayProto.slice,
Chris@909 1087 _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available
Chris@909 1088
Chris@909 1089 function each(iterator, context) {
Chris@909 1090 for (var i = 0, length = this.length >>> 0; i < length; i++) {
Chris@909 1091 if (i in this) iterator.call(context, this[i], i, this);
Chris@909 1092 }
Chris@909 1093 }
Chris@909 1094 if (!_each) _each = each;
Chris@909 1095
Chris@909 1096 function clear() {
Chris@909 1097 this.length = 0;
Chris@909 1098 return this;
Chris@909 1099 }
Chris@909 1100
Chris@909 1101 function first() {
Chris@909 1102 return this[0];
Chris@909 1103 }
Chris@909 1104
Chris@909 1105 function last() {
Chris@909 1106 return this[this.length - 1];
Chris@909 1107 }
Chris@909 1108
Chris@909 1109 function compact() {
Chris@909 1110 return this.select(function(value) {
Chris@909 1111 return value != null;
Chris@909 1112 });
Chris@909 1113 }
Chris@909 1114
Chris@909 1115 function flatten() {
Chris@909 1116 return this.inject([], function(array, value) {
Chris@909 1117 if (Object.isArray(value))
Chris@909 1118 return array.concat(value.flatten());
Chris@909 1119 array.push(value);
Chris@909 1120 return array;
Chris@909 1121 });
Chris@909 1122 }
Chris@909 1123
Chris@909 1124 function without() {
Chris@909 1125 var values = slice.call(arguments, 0);
Chris@909 1126 return this.select(function(value) {
Chris@909 1127 return !values.include(value);
Chris@909 1128 });
Chris@909 1129 }
Chris@909 1130
Chris@909 1131 function reverse(inline) {
Chris@909 1132 return (inline === false ? this.toArray() : this)._reverse();
Chris@909 1133 }
Chris@909 1134
Chris@909 1135 function uniq(sorted) {
Chris@909 1136 return this.inject([], function(array, value, index) {
Chris@909 1137 if (0 == index || (sorted ? array.last() != value : !array.include(value)))
Chris@909 1138 array.push(value);
Chris@909 1139 return array;
Chris@909 1140 });
Chris@909 1141 }
Chris@909 1142
Chris@909 1143 function intersect(array) {
Chris@909 1144 return this.uniq().findAll(function(item) {
Chris@909 1145 return array.detect(function(value) { return item === value });
Chris@909 1146 });
Chris@909 1147 }
Chris@909 1148
Chris@909 1149
Chris@909 1150 function clone() {
Chris@909 1151 return slice.call(this, 0);
Chris@909 1152 }
Chris@909 1153
Chris@909 1154 function size() {
Chris@909 1155 return this.length;
Chris@909 1156 }
Chris@909 1157
Chris@909 1158 function inspect() {
Chris@909 1159 return '[' + this.map(Object.inspect).join(', ') + ']';
Chris@909 1160 }
Chris@909 1161
Chris@909 1162 function indexOf(item, i) {
Chris@909 1163 i || (i = 0);
Chris@909 1164 var length = this.length;
Chris@909 1165 if (i < 0) i = length + i;
Chris@909 1166 for (; i < length; i++)
Chris@909 1167 if (this[i] === item) return i;
Chris@909 1168 return -1;
Chris@909 1169 }
Chris@909 1170
Chris@909 1171 function lastIndexOf(item, i) {
Chris@909 1172 i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
Chris@909 1173 var n = this.slice(0, i).reverse().indexOf(item);
Chris@909 1174 return (n < 0) ? n : i - n - 1;
Chris@909 1175 }
Chris@909 1176
Chris@909 1177 function concat() {
Chris@909 1178 var array = slice.call(this, 0), item;
Chris@909 1179 for (var i = 0, length = arguments.length; i < length; i++) {
Chris@909 1180 item = arguments[i];
Chris@909 1181 if (Object.isArray(item) && !('callee' in item)) {
Chris@909 1182 for (var j = 0, arrayLength = item.length; j < arrayLength; j++)
Chris@909 1183 array.push(item[j]);
Chris@909 1184 } else {
Chris@909 1185 array.push(item);
Chris@909 1186 }
Chris@909 1187 }
Chris@909 1188 return array;
Chris@909 1189 }
Chris@909 1190
Chris@909 1191 Object.extend(arrayProto, Enumerable);
Chris@909 1192
Chris@909 1193 if (!arrayProto._reverse)
Chris@909 1194 arrayProto._reverse = arrayProto.reverse;
Chris@909 1195
Chris@909 1196 Object.extend(arrayProto, {
Chris@909 1197 _each: _each,
Chris@909 1198 clear: clear,
Chris@909 1199 first: first,
Chris@909 1200 last: last,
Chris@909 1201 compact: compact,
Chris@909 1202 flatten: flatten,
Chris@909 1203 without: without,
Chris@909 1204 reverse: reverse,
Chris@909 1205 uniq: uniq,
Chris@909 1206 intersect: intersect,
Chris@909 1207 clone: clone,
Chris@909 1208 toArray: clone,
Chris@909 1209 size: size,
Chris@909 1210 inspect: inspect
Chris@909 1211 });
Chris@909 1212
Chris@909 1213 var CONCAT_ARGUMENTS_BUGGY = (function() {
Chris@909 1214 return [].concat(arguments)[0][0] !== 1;
Chris@909 1215 })(1,2)
Chris@909 1216
Chris@909 1217 if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat;
Chris@909 1218
Chris@909 1219 if (!arrayProto.indexOf) arrayProto.indexOf = indexOf;
Chris@909 1220 if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf;
Chris@909 1221 })();
Chris@909 1222 function $H(object) {
Chris@909 1223 return new Hash(object);
Chris@909 1224 };
Chris@909 1225
Chris@909 1226 var Hash = Class.create(Enumerable, (function() {
Chris@909 1227 function initialize(object) {
Chris@909 1228 this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
Chris@909 1229 }
Chris@909 1230
Chris@909 1231
Chris@909 1232 function _each(iterator) {
Chris@909 1233 for (var key in this._object) {
Chris@909 1234 var value = this._object[key], pair = [key, value];
Chris@909 1235 pair.key = key;
Chris@909 1236 pair.value = value;
Chris@909 1237 iterator(pair);
Chris@909 1238 }
Chris@909 1239 }
Chris@909 1240
Chris@909 1241 function set(key, value) {
Chris@909 1242 return this._object[key] = value;
Chris@909 1243 }
Chris@909 1244
Chris@909 1245 function get(key) {
Chris@909 1246 if (this._object[key] !== Object.prototype[key])
Chris@909 1247 return this._object[key];
Chris@909 1248 }
Chris@909 1249
Chris@909 1250 function unset(key) {
Chris@909 1251 var value = this._object[key];
Chris@909 1252 delete this._object[key];
Chris@909 1253 return value;
Chris@909 1254 }
Chris@909 1255
Chris@909 1256 function toObject() {
Chris@909 1257 return Object.clone(this._object);
Chris@909 1258 }
Chris@909 1259
Chris@909 1260
Chris@909 1261
Chris@909 1262 function keys() {
Chris@909 1263 return this.pluck('key');
Chris@909 1264 }
Chris@909 1265
Chris@909 1266 function values() {
Chris@909 1267 return this.pluck('value');
Chris@909 1268 }
Chris@909 1269
Chris@909 1270 function index(value) {
Chris@909 1271 var match = this.detect(function(pair) {
Chris@909 1272 return pair.value === value;
Chris@909 1273 });
Chris@909 1274 return match && match.key;
Chris@909 1275 }
Chris@909 1276
Chris@909 1277 function merge(object) {
Chris@909 1278 return this.clone().update(object);
Chris@909 1279 }
Chris@909 1280
Chris@909 1281 function update(object) {
Chris@909 1282 return new Hash(object).inject(this, function(result, pair) {
Chris@909 1283 result.set(pair.key, pair.value);
Chris@909 1284 return result;
Chris@909 1285 });
Chris@909 1286 }
Chris@909 1287
Chris@909 1288 function toQueryPair(key, value) {
Chris@909 1289 if (Object.isUndefined(value)) return key;
Chris@909 1290 return key + '=' + encodeURIComponent(String.interpret(value));
Chris@909 1291 }
Chris@909 1292
Chris@909 1293 function toQueryString() {
Chris@909 1294 return this.inject([], function(results, pair) {
Chris@909 1295 var key = encodeURIComponent(pair.key), values = pair.value;
Chris@909 1296
Chris@909 1297 if (values && typeof values == 'object') {
Chris@909 1298 if (Object.isArray(values)) {
Chris@909 1299 var queryValues = [];
Chris@909 1300 for (var i = 0, len = values.length, value; i < len; i++) {
Chris@909 1301 value = values[i];
Chris@909 1302 queryValues.push(toQueryPair(key, value));
Chris@909 1303 }
Chris@909 1304 return results.concat(queryValues);
Chris@909 1305 }
Chris@909 1306 } else results.push(toQueryPair(key, values));
Chris@909 1307 return results;
Chris@909 1308 }).join('&');
Chris@909 1309 }
Chris@909 1310
Chris@909 1311 function inspect() {
Chris@909 1312 return '#<Hash:{' + this.map(function(pair) {
Chris@909 1313 return pair.map(Object.inspect).join(': ');
Chris@909 1314 }).join(', ') + '}>';
Chris@909 1315 }
Chris@909 1316
Chris@909 1317 function clone() {
Chris@909 1318 return new Hash(this);
Chris@909 1319 }
Chris@909 1320
Chris@909 1321 return {
Chris@909 1322 initialize: initialize,
Chris@909 1323 _each: _each,
Chris@909 1324 set: set,
Chris@909 1325 get: get,
Chris@909 1326 unset: unset,
Chris@909 1327 toObject: toObject,
Chris@909 1328 toTemplateReplacements: toObject,
Chris@909 1329 keys: keys,
Chris@909 1330 values: values,
Chris@909 1331 index: index,
Chris@909 1332 merge: merge,
Chris@909 1333 update: update,
Chris@909 1334 toQueryString: toQueryString,
Chris@909 1335 inspect: inspect,
Chris@909 1336 toJSON: toObject,
Chris@909 1337 clone: clone
Chris@909 1338 };
Chris@909 1339 })());
Chris@909 1340
Chris@909 1341 Hash.from = $H;
Chris@909 1342 Object.extend(Number.prototype, (function() {
Chris@909 1343 function toColorPart() {
Chris@909 1344 return this.toPaddedString(2, 16);
Chris@909 1345 }
Chris@909 1346
Chris@909 1347 function succ() {
Chris@909 1348 return this + 1;
Chris@909 1349 }
Chris@909 1350
Chris@909 1351 function times(iterator, context) {
Chris@909 1352 $R(0, this, true).each(iterator, context);
Chris@909 1353 return this;
Chris@909 1354 }
Chris@909 1355
Chris@909 1356 function toPaddedString(length, radix) {
Chris@909 1357 var string = this.toString(radix || 10);
Chris@909 1358 return '0'.times(length - string.length) + string;
Chris@909 1359 }
Chris@909 1360
Chris@909 1361 function abs() {
Chris@909 1362 return Math.abs(this);
Chris@909 1363 }
Chris@909 1364
Chris@909 1365 function round() {
Chris@909 1366 return Math.round(this);
Chris@909 1367 }
Chris@909 1368
Chris@909 1369 function ceil() {
Chris@909 1370 return Math.ceil(this);
Chris@909 1371 }
Chris@909 1372
Chris@909 1373 function floor() {
Chris@909 1374 return Math.floor(this);
Chris@909 1375 }
Chris@909 1376
Chris@909 1377 return {
Chris@909 1378 toColorPart: toColorPart,
Chris@909 1379 succ: succ,
Chris@909 1380 times: times,
Chris@909 1381 toPaddedString: toPaddedString,
Chris@909 1382 abs: abs,
Chris@909 1383 round: round,
Chris@909 1384 ceil: ceil,
Chris@909 1385 floor: floor
Chris@909 1386 };
Chris@909 1387 })());
Chris@909 1388
Chris@909 1389 function $R(start, end, exclusive) {
Chris@909 1390 return new ObjectRange(start, end, exclusive);
Chris@909 1391 }
Chris@909 1392
Chris@909 1393 var ObjectRange = Class.create(Enumerable, (function() {
Chris@909 1394 function initialize(start, end, exclusive) {
Chris@909 1395 this.start = start;
Chris@909 1396 this.end = end;
Chris@909 1397 this.exclusive = exclusive;
Chris@909 1398 }
Chris@909 1399
Chris@909 1400 function _each(iterator) {
Chris@909 1401 var value = this.start;
Chris@909 1402 while (this.include(value)) {
Chris@909 1403 iterator(value);
Chris@909 1404 value = value.succ();
Chris@909 1405 }
Chris@909 1406 }
Chris@909 1407
Chris@909 1408 function include(value) {
Chris@909 1409 if (value < this.start)
Chris@909 1410 return false;
Chris@909 1411 if (this.exclusive)
Chris@909 1412 return value < this.end;
Chris@909 1413 return value <= this.end;
Chris@909 1414 }
Chris@909 1415
Chris@909 1416 return {
Chris@909 1417 initialize: initialize,
Chris@909 1418 _each: _each,
Chris@909 1419 include: include
Chris@909 1420 };
Chris@909 1421 })());
Chris@909 1422
Chris@909 1423
Chris@909 1424
Chris@909 1425 var Ajax = {
Chris@909 1426 getTransport: function() {
Chris@909 1427 return Try.these(
Chris@909 1428 function() {return new XMLHttpRequest()},
Chris@909 1429 function() {return new ActiveXObject('Msxml2.XMLHTTP')},
Chris@909 1430 function() {return new ActiveXObject('Microsoft.XMLHTTP')}
Chris@909 1431 ) || false;
Chris@909 1432 },
Chris@909 1433
Chris@909 1434 activeRequestCount: 0
Chris@909 1435 };
Chris@909 1436
Chris@909 1437 Ajax.Responders = {
Chris@909 1438 responders: [],
Chris@909 1439
Chris@909 1440 _each: function(iterator) {
Chris@909 1441 this.responders._each(iterator);
Chris@909 1442 },
Chris@909 1443
Chris@909 1444 register: function(responder) {
Chris@909 1445 if (!this.include(responder))
Chris@909 1446 this.responders.push(responder);
Chris@909 1447 },
Chris@909 1448
Chris@909 1449 unregister: function(responder) {
Chris@909 1450 this.responders = this.responders.without(responder);
Chris@909 1451 },
Chris@909 1452
Chris@909 1453 dispatch: function(callback, request, transport, json) {
Chris@909 1454 this.each(function(responder) {
Chris@909 1455 if (Object.isFunction(responder[callback])) {
Chris@909 1456 try {
Chris@909 1457 responder[callback].apply(responder, [request, transport, json]);
Chris@909 1458 } catch (e) { }
Chris@909 1459 }
Chris@909 1460 });
Chris@909 1461 }
Chris@909 1462 };
Chris@909 1463
Chris@909 1464 Object.extend(Ajax.Responders, Enumerable);
Chris@909 1465
Chris@909 1466 Ajax.Responders.register({
Chris@909 1467 onCreate: function() { Ajax.activeRequestCount++ },
Chris@909 1468 onComplete: function() { Ajax.activeRequestCount-- }
Chris@909 1469 });
Chris@909 1470 Ajax.Base = Class.create({
Chris@909 1471 initialize: function(options) {
Chris@909 1472 this.options = {
Chris@909 1473 method: 'post',
Chris@909 1474 asynchronous: true,
Chris@909 1475 contentType: 'application/x-www-form-urlencoded',
Chris@909 1476 encoding: 'UTF-8',
Chris@909 1477 parameters: '',
Chris@909 1478 evalJSON: true,
Chris@909 1479 evalJS: true
Chris@909 1480 };
Chris@909 1481 Object.extend(this.options, options || { });
Chris@909 1482
Chris@909 1483 this.options.method = this.options.method.toLowerCase();
Chris@909 1484
Chris@909 1485 if (Object.isHash(this.options.parameters))
Chris@909 1486 this.options.parameters = this.options.parameters.toObject();
Chris@909 1487 }
Chris@909 1488 });
Chris@909 1489 Ajax.Request = Class.create(Ajax.Base, {
Chris@909 1490 _complete: false,
Chris@909 1491
Chris@909 1492 initialize: function($super, url, options) {
Chris@909 1493 $super(options);
Chris@909 1494 this.transport = Ajax.getTransport();
Chris@909 1495 this.request(url);
Chris@909 1496 },
Chris@909 1497
Chris@909 1498 request: function(url) {
Chris@909 1499 this.url = url;
Chris@909 1500 this.method = this.options.method;
Chris@909 1501 var params = Object.isString(this.options.parameters) ?
Chris@909 1502 this.options.parameters :
Chris@909 1503 Object.toQueryString(this.options.parameters);
Chris@909 1504
Chris@909 1505 if (!['get', 'post'].include(this.method)) {
Chris@909 1506 params += (params ? '&' : '') + "_method=" + this.method;
Chris@909 1507 this.method = 'post';
Chris@909 1508 }
Chris@909 1509
Chris@909 1510 if (params && this.method === 'get') {
Chris@909 1511 this.url += (this.url.include('?') ? '&' : '?') + params;
Chris@909 1512 }
Chris@909 1513
Chris@909 1514 this.parameters = params.toQueryParams();
Chris@909 1515
Chris@909 1516 try {
Chris@909 1517 var response = new Ajax.Response(this);
Chris@909 1518 if (this.options.onCreate) this.options.onCreate(response);
Chris@909 1519 Ajax.Responders.dispatch('onCreate', this, response);
Chris@909 1520
Chris@909 1521 this.transport.open(this.method.toUpperCase(), this.url,
Chris@909 1522 this.options.asynchronous);
Chris@909 1523
Chris@909 1524 if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
Chris@909 1525
Chris@909 1526 this.transport.onreadystatechange = this.onStateChange.bind(this);
Chris@909 1527 this.setRequestHeaders();
Chris@909 1528
Chris@909 1529 this.body = this.method == 'post' ? (this.options.postBody || params) : null;
Chris@909 1530 this.transport.send(this.body);
Chris@909 1531
Chris@909 1532 /* Force Firefox to handle ready state 4 for synchronous requests */
Chris@909 1533 if (!this.options.asynchronous && this.transport.overrideMimeType)
Chris@909 1534 this.onStateChange();
Chris@909 1535
Chris@909 1536 }
Chris@909 1537 catch (e) {
Chris@909 1538 this.dispatchException(e);
Chris@909 1539 }
Chris@909 1540 },
Chris@909 1541
Chris@909 1542 onStateChange: function() {
Chris@909 1543 var readyState = this.transport.readyState;
Chris@909 1544 if (readyState > 1 && !((readyState == 4) && this._complete))
Chris@909 1545 this.respondToReadyState(this.transport.readyState);
Chris@909 1546 },
Chris@909 1547
Chris@909 1548 setRequestHeaders: function() {
Chris@909 1549 var headers = {
Chris@909 1550 'X-Requested-With': 'XMLHttpRequest',
Chris@909 1551 'X-Prototype-Version': Prototype.Version,
Chris@909 1552 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
Chris@909 1553 };
Chris@909 1554
Chris@909 1555 if (this.method == 'post') {
Chris@909 1556 headers['Content-type'] = this.options.contentType +
Chris@909 1557 (this.options.encoding ? '; charset=' + this.options.encoding : '');
Chris@909 1558
Chris@909 1559 /* Force "Connection: close" for older Mozilla browsers to work
Chris@909 1560 * around a bug where XMLHttpRequest sends an incorrect
Chris@909 1561 * Content-length header. See Mozilla Bugzilla #246651.
Chris@909 1562 */
Chris@909 1563 if (this.transport.overrideMimeType &&
Chris@909 1564 (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
Chris@909 1565 headers['Connection'] = 'close';
Chris@909 1566 }
Chris@909 1567
Chris@909 1568 if (typeof this.options.requestHeaders == 'object') {
Chris@909 1569 var extras = this.options.requestHeaders;
Chris@909 1570
Chris@909 1571 if (Object.isFunction(extras.push))
Chris@909 1572 for (var i = 0, length = extras.length; i < length; i += 2)
Chris@909 1573 headers[extras[i]] = extras[i+1];
Chris@909 1574 else
Chris@909 1575 $H(extras).each(function(pair) { headers[pair.key] = pair.value });
Chris@909 1576 }
Chris@909 1577
Chris@909 1578 for (var name in headers)
Chris@909 1579 this.transport.setRequestHeader(name, headers[name]);
Chris@909 1580 },
Chris@909 1581
Chris@909 1582 success: function() {
Chris@909 1583 var status = this.getStatus();
Chris@909 1584 return !status || (status >= 200 && status < 300) || status == 304;
Chris@909 1585 },
Chris@909 1586
Chris@909 1587 getStatus: function() {
Chris@909 1588 try {
Chris@909 1589 if (this.transport.status === 1223) return 204;
Chris@909 1590 return this.transport.status || 0;
Chris@909 1591 } catch (e) { return 0 }
Chris@909 1592 },
Chris@909 1593
Chris@909 1594 respondToReadyState: function(readyState) {
Chris@909 1595 var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);
Chris@909 1596
Chris@909 1597 if (state == 'Complete') {
Chris@909 1598 try {
Chris@909 1599 this._complete = true;
Chris@909 1600 (this.options['on' + response.status]
Chris@909 1601 || this.options['on' + (this.success() ? 'Success' : 'Failure')]
Chris@909 1602 || Prototype.emptyFunction)(response, response.headerJSON);
Chris@909 1603 } catch (e) {
Chris@909 1604 this.dispatchException(e);
Chris@909 1605 }
Chris@909 1606
Chris@909 1607 var contentType = response.getHeader('Content-type');
Chris@909 1608 if (this.options.evalJS == 'force'
Chris@909 1609 || (this.options.evalJS && this.isSameOrigin() && contentType
Chris@909 1610 && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
Chris@909 1611 this.evalResponse();
Chris@909 1612 }
Chris@909 1613
Chris@909 1614 try {
Chris@909 1615 (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
Chris@909 1616 Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
Chris@909 1617 } catch (e) {
Chris@909 1618 this.dispatchException(e);
Chris@909 1619 }
Chris@909 1620
Chris@909 1621 if (state == 'Complete') {
Chris@909 1622 this.transport.onreadystatechange = Prototype.emptyFunction;
Chris@909 1623 }
Chris@909 1624 },
Chris@909 1625
Chris@909 1626 isSameOrigin: function() {
Chris@909 1627 var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
Chris@909 1628 return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
Chris@909 1629 protocol: location.protocol,
Chris@909 1630 domain: document.domain,
Chris@909 1631 port: location.port ? ':' + location.port : ''
Chris@909 1632 }));
Chris@909 1633 },
Chris@909 1634
Chris@909 1635 getHeader: function(name) {
Chris@909 1636 try {
Chris@909 1637 return this.transport.getResponseHeader(name) || null;
Chris@909 1638 } catch (e) { return null; }
Chris@909 1639 },
Chris@909 1640
Chris@909 1641 evalResponse: function() {
Chris@909 1642 try {
Chris@909 1643 return eval((this.transport.responseText || '').unfilterJSON());
Chris@909 1644 } catch (e) {
Chris@909 1645 this.dispatchException(e);
Chris@909 1646 }
Chris@909 1647 },
Chris@909 1648
Chris@909 1649 dispatchException: function(exception) {
Chris@909 1650 (this.options.onException || Prototype.emptyFunction)(this, exception);
Chris@909 1651 Ajax.Responders.dispatch('onException', this, exception);
Chris@909 1652 }
Chris@909 1653 });
Chris@909 1654
Chris@909 1655 Ajax.Request.Events =
Chris@909 1656 ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
Chris@909 1657
Chris@909 1658
Chris@909 1659
Chris@909 1660
Chris@909 1661
Chris@909 1662
Chris@909 1663
Chris@909 1664
Chris@909 1665 Ajax.Response = Class.create({
Chris@909 1666 initialize: function(request){
Chris@909 1667 this.request = request;
Chris@909 1668 var transport = this.transport = request.transport,
Chris@909 1669 readyState = this.readyState = transport.readyState;
Chris@909 1670
Chris@909 1671 if ((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
Chris@909 1672 this.status = this.getStatus();
Chris@909 1673 this.statusText = this.getStatusText();
Chris@909 1674 this.responseText = String.interpret(transport.responseText);
Chris@909 1675 this.headerJSON = this._getHeaderJSON();
Chris@909 1676 }
Chris@909 1677
Chris@909 1678 if (readyState == 4) {
Chris@909 1679 var xml = transport.responseXML;
Chris@909 1680 this.responseXML = Object.isUndefined(xml) ? null : xml;
Chris@909 1681 this.responseJSON = this._getResponseJSON();
Chris@909 1682 }
Chris@909 1683 },
Chris@909 1684
Chris@909 1685 status: 0,
Chris@909 1686
Chris@909 1687 statusText: '',
Chris@909 1688
Chris@909 1689 getStatus: Ajax.Request.prototype.getStatus,
Chris@909 1690
Chris@909 1691 getStatusText: function() {
Chris@909 1692 try {
Chris@909 1693 return this.transport.statusText || '';
Chris@909 1694 } catch (e) { return '' }
Chris@909 1695 },
Chris@909 1696
Chris@909 1697 getHeader: Ajax.Request.prototype.getHeader,
Chris@909 1698
Chris@909 1699 getAllHeaders: function() {
Chris@909 1700 try {
Chris@909 1701 return this.getAllResponseHeaders();
Chris@909 1702 } catch (e) { return null }
Chris@909 1703 },
Chris@909 1704
Chris@909 1705 getResponseHeader: function(name) {
Chris@909 1706 return this.transport.getResponseHeader(name);
Chris@909 1707 },
Chris@909 1708
Chris@909 1709 getAllResponseHeaders: function() {
Chris@909 1710 return this.transport.getAllResponseHeaders();
Chris@909 1711 },
Chris@909 1712
Chris@909 1713 _getHeaderJSON: function() {
Chris@909 1714 var json = this.getHeader('X-JSON');
Chris@909 1715 if (!json) return null;
Chris@909 1716 json = decodeURIComponent(escape(json));
Chris@909 1717 try {
Chris@909 1718 return json.evalJSON(this.request.options.sanitizeJSON ||
Chris@909 1719 !this.request.isSameOrigin());
Chris@909 1720 } catch (e) {
Chris@909 1721 this.request.dispatchException(e);
Chris@909 1722 }
Chris@909 1723 },
Chris@909 1724
Chris@909 1725 _getResponseJSON: function() {
Chris@909 1726 var options = this.request.options;
Chris@909 1727 if (!options.evalJSON || (options.evalJSON != 'force' &&
Chris@909 1728 !(this.getHeader('Content-type') || '').include('application/json')) ||
Chris@909 1729 this.responseText.blank())
Chris@909 1730 return null;
Chris@909 1731 try {
Chris@909 1732 return this.responseText.evalJSON(options.sanitizeJSON ||
Chris@909 1733 !this.request.isSameOrigin());
Chris@909 1734 } catch (e) {
Chris@909 1735 this.request.dispatchException(e);
Chris@909 1736 }
Chris@909 1737 }
Chris@909 1738 });
Chris@909 1739
Chris@909 1740 Ajax.Updater = Class.create(Ajax.Request, {
Chris@909 1741 initialize: function($super, container, url, options) {
Chris@909 1742 this.container = {
Chris@909 1743 success: (container.success || container),
Chris@909 1744 failure: (container.failure || (container.success ? null : container))
Chris@909 1745 };
Chris@909 1746
Chris@909 1747 options = Object.clone(options);
Chris@909 1748 var onComplete = options.onComplete;
Chris@909 1749 options.onComplete = (function(response, json) {
Chris@909 1750 this.updateContent(response.responseText);
Chris@909 1751 if (Object.isFunction(onComplete)) onComplete(response, json);
Chris@909 1752 }).bind(this);
Chris@909 1753
Chris@909 1754 $super(url, options);
Chris@909 1755 },
Chris@909 1756
Chris@909 1757 updateContent: function(responseText) {
Chris@909 1758 var receiver = this.container[this.success() ? 'success' : 'failure'],
Chris@909 1759 options = this.options;
Chris@909 1760
Chris@909 1761 if (!options.evalScripts) responseText = responseText.stripScripts();
Chris@909 1762
Chris@909 1763 if (receiver = $(receiver)) {
Chris@909 1764 if (options.insertion) {
Chris@909 1765 if (Object.isString(options.insertion)) {
Chris@909 1766 var insertion = { }; insertion[options.insertion] = responseText;
Chris@909 1767 receiver.insert(insertion);
Chris@909 1768 }
Chris@909 1769 else options.insertion(receiver, responseText);
Chris@909 1770 }
Chris@909 1771 else receiver.update(responseText);
Chris@909 1772 }
Chris@909 1773 }
Chris@909 1774 });
Chris@909 1775
Chris@909 1776 Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
Chris@909 1777 initialize: function($super, container, url, options) {
Chris@909 1778 $super(options);
Chris@909 1779 this.onComplete = this.options.onComplete;
Chris@909 1780
Chris@909 1781 this.frequency = (this.options.frequency || 2);
Chris@909 1782 this.decay = (this.options.decay || 1);
Chris@909 1783
Chris@909 1784 this.updater = { };
Chris@909 1785 this.container = container;
Chris@909 1786 this.url = url;
Chris@909 1787
Chris@909 1788 this.start();
Chris@909 1789 },
Chris@909 1790
Chris@909 1791 start: function() {
Chris@909 1792 this.options.onComplete = this.updateComplete.bind(this);
Chris@909 1793 this.onTimerEvent();
Chris@909 1794 },
Chris@909 1795
Chris@909 1796 stop: function() {
Chris@909 1797 this.updater.options.onComplete = undefined;
Chris@909 1798 clearTimeout(this.timer);
Chris@909 1799 (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
Chris@909 1800 },
Chris@909 1801
Chris@909 1802 updateComplete: function(response) {
Chris@909 1803 if (this.options.decay) {
Chris@909 1804 this.decay = (response.responseText == this.lastText ?
Chris@909 1805 this.decay * this.options.decay : 1);
Chris@909 1806
Chris@909 1807 this.lastText = response.responseText;
Chris@909 1808 }
Chris@909 1809 this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
Chris@909 1810 },
Chris@909 1811
Chris@909 1812 onTimerEvent: function() {
Chris@909 1813 this.updater = new Ajax.Updater(this.container, this.url, this.options);
Chris@909 1814 }
Chris@909 1815 });
Chris@909 1816
Chris@909 1817
Chris@909 1818 function $(element) {
Chris@909 1819 if (arguments.length > 1) {
Chris@909 1820 for (var i = 0, elements = [], length = arguments.length; i < length; i++)
Chris@909 1821 elements.push($(arguments[i]));
Chris@909 1822 return elements;
Chris@909 1823 }
Chris@909 1824 if (Object.isString(element))
Chris@909 1825 element = document.getElementById(element);
Chris@909 1826 return Element.extend(element);
Chris@909 1827 }
Chris@909 1828
Chris@909 1829 if (Prototype.BrowserFeatures.XPath) {
Chris@909 1830 document._getElementsByXPath = function(expression, parentElement) {
Chris@909 1831 var results = [];
Chris@909 1832 var query = document.evaluate(expression, $(parentElement) || document,
Chris@909 1833 null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
Chris@909 1834 for (var i = 0, length = query.snapshotLength; i < length; i++)
Chris@909 1835 results.push(Element.extend(query.snapshotItem(i)));
Chris@909 1836 return results;
Chris@909 1837 };
Chris@909 1838 }
Chris@909 1839
Chris@909 1840 /*--------------------------------------------------------------------------*/
Chris@909 1841
Chris@909 1842 if (!Node) var Node = { };
Chris@909 1843
Chris@909 1844 if (!Node.ELEMENT_NODE) {
Chris@909 1845 Object.extend(Node, {
Chris@909 1846 ELEMENT_NODE: 1,
Chris@909 1847 ATTRIBUTE_NODE: 2,
Chris@909 1848 TEXT_NODE: 3,
Chris@909 1849 CDATA_SECTION_NODE: 4,
Chris@909 1850 ENTITY_REFERENCE_NODE: 5,
Chris@909 1851 ENTITY_NODE: 6,
Chris@909 1852 PROCESSING_INSTRUCTION_NODE: 7,
Chris@909 1853 COMMENT_NODE: 8,
Chris@909 1854 DOCUMENT_NODE: 9,
Chris@909 1855 DOCUMENT_TYPE_NODE: 10,
Chris@909 1856 DOCUMENT_FRAGMENT_NODE: 11,
Chris@909 1857 NOTATION_NODE: 12
Chris@909 1858 });
Chris@909 1859 }
Chris@909 1860
Chris@909 1861
Chris@909 1862
Chris@909 1863 (function(global) {
Chris@909 1864 function shouldUseCache(tagName, attributes) {
Chris@909 1865 if (tagName === 'select') return false;
Chris@909 1866 if ('type' in attributes) return false;
Chris@909 1867 return true;
Chris@909 1868 }
Chris@909 1869
Chris@909 1870 var HAS_EXTENDED_CREATE_ELEMENT_SYNTAX = (function(){
Chris@909 1871 try {
Chris@909 1872 var el = document.createElement('<input name="x">');
Chris@909 1873 return el.tagName.toLowerCase() === 'input' && el.name === 'x';
Chris@909 1874 }
Chris@909 1875 catch(err) {
Chris@909 1876 return false;
Chris@909 1877 }
Chris@909 1878 })();
Chris@909 1879
Chris@909 1880 var element = global.Element;
Chris@909 1881
Chris@909 1882 global.Element = function(tagName, attributes) {
Chris@909 1883 attributes = attributes || { };
Chris@909 1884 tagName = tagName.toLowerCase();
Chris@909 1885 var cache = Element.cache;
Chris@909 1886
Chris@909 1887 if (HAS_EXTENDED_CREATE_ELEMENT_SYNTAX && attributes.name) {
Chris@909 1888 tagName = '<' + tagName + ' name="' + attributes.name + '">';
Chris@909 1889 delete attributes.name;
Chris@909 1890 return Element.writeAttribute(document.createElement(tagName), attributes);
Chris@909 1891 }
Chris@909 1892
Chris@909 1893 if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
Chris@909 1894
Chris@909 1895 var node = shouldUseCache(tagName, attributes) ?
Chris@909 1896 cache[tagName].cloneNode(false) : document.createElement(tagName);
Chris@909 1897
Chris@909 1898 return Element.writeAttribute(node, attributes);
Chris@909 1899 };
Chris@909 1900
Chris@909 1901 Object.extend(global.Element, element || { });
Chris@909 1902 if (element) global.Element.prototype = element.prototype;
Chris@909 1903
Chris@909 1904 })(this);
Chris@909 1905
Chris@909 1906 Element.idCounter = 1;
Chris@909 1907 Element.cache = { };
Chris@909 1908
Chris@909 1909 Element._purgeElement = function(element) {
Chris@909 1910 var uid = element._prototypeUID;
Chris@909 1911 if (uid) {
Chris@909 1912 Element.stopObserving(element);
Chris@909 1913 element._prototypeUID = void 0;
Chris@909 1914 delete Element.Storage[uid];
Chris@909 1915 }
Chris@909 1916 }
Chris@909 1917
Chris@909 1918 Element.Methods = {
Chris@909 1919 visible: function(element) {
Chris@909 1920 return $(element).style.display != 'none';
Chris@909 1921 },
Chris@909 1922
Chris@909 1923 toggle: function(element) {
Chris@909 1924 element = $(element);
Chris@909 1925 Element[Element.visible(element) ? 'hide' : 'show'](element);
Chris@909 1926 return element;
Chris@909 1927 },
Chris@909 1928
Chris@909 1929 hide: function(element) {
Chris@909 1930 element = $(element);
Chris@909 1931 element.style.display = 'none';
Chris@909 1932 return element;
Chris@909 1933 },
Chris@909 1934
Chris@909 1935 show: function(element) {
Chris@909 1936 element = $(element);
Chris@909 1937 element.style.display = '';
Chris@909 1938 return element;
Chris@909 1939 },
Chris@909 1940
Chris@909 1941 remove: function(element) {
Chris@909 1942 element = $(element);
Chris@909 1943 element.parentNode.removeChild(element);
Chris@909 1944 return element;
Chris@909 1945 },
Chris@909 1946
Chris@909 1947 update: (function(){
Chris@909 1948
Chris@909 1949 var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){
Chris@909 1950 var el = document.createElement("select"),
Chris@909 1951 isBuggy = true;
Chris@909 1952 el.innerHTML = "<option value=\"test\">test</option>";
Chris@909 1953 if (el.options && el.options[0]) {
Chris@909 1954 isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION";
Chris@909 1955 }
Chris@909 1956 el = null;
Chris@909 1957 return isBuggy;
Chris@909 1958 })();
Chris@909 1959
Chris@909 1960 var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){
Chris@909 1961 try {
Chris@909 1962 var el = document.createElement("table");
Chris@909 1963 if (el && el.tBodies) {
Chris@909 1964 el.innerHTML = "<tbody><tr><td>test</td></tr></tbody>";
Chris@909 1965 var isBuggy = typeof el.tBodies[0] == "undefined";
Chris@909 1966 el = null;
Chris@909 1967 return isBuggy;
Chris@909 1968 }
Chris@909 1969 } catch (e) {
Chris@909 1970 return true;
Chris@909 1971 }
Chris@909 1972 })();
Chris@909 1973
Chris@909 1974 var LINK_ELEMENT_INNERHTML_BUGGY = (function() {
Chris@909 1975 try {
Chris@909 1976 var el = document.createElement('div');
Chris@909 1977 el.innerHTML = "<link>";
Chris@909 1978 var isBuggy = (el.childNodes.length === 0);
Chris@909 1979 el = null;
Chris@909 1980 return isBuggy;
Chris@909 1981 } catch(e) {
Chris@909 1982 return true;
Chris@909 1983 }
Chris@909 1984 })();
Chris@909 1985
Chris@909 1986 var ANY_INNERHTML_BUGGY = SELECT_ELEMENT_INNERHTML_BUGGY ||
Chris@909 1987 TABLE_ELEMENT_INNERHTML_BUGGY || LINK_ELEMENT_INNERHTML_BUGGY;
Chris@909 1988
Chris@909 1989 var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () {
Chris@909 1990 var s = document.createElement("script"),
Chris@909 1991 isBuggy = false;
Chris@909 1992 try {
Chris@909 1993 s.appendChild(document.createTextNode(""));
Chris@909 1994 isBuggy = !s.firstChild ||
Chris@909 1995 s.firstChild && s.firstChild.nodeType !== 3;
Chris@909 1996 } catch (e) {
Chris@909 1997 isBuggy = true;
Chris@909 1998 }
Chris@909 1999 s = null;
Chris@909 2000 return isBuggy;
Chris@909 2001 })();
Chris@909 2002
Chris@909 2003
Chris@909 2004 function update(element, content) {
Chris@909 2005 element = $(element);
Chris@909 2006 var purgeElement = Element._purgeElement;
Chris@909 2007
Chris@909 2008 var descendants = element.getElementsByTagName('*'),
Chris@909 2009 i = descendants.length;
Chris@909 2010 while (i--) purgeElement(descendants[i]);
Chris@909 2011
Chris@909 2012 if (content && content.toElement)
Chris@909 2013 content = content.toElement();
Chris@909 2014
Chris@909 2015 if (Object.isElement(content))
Chris@909 2016 return element.update().insert(content);
Chris@909 2017
Chris@909 2018 content = Object.toHTML(content);
Chris@909 2019
Chris@909 2020 var tagName = element.tagName.toUpperCase();
Chris@909 2021
Chris@909 2022 if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) {
Chris@909 2023 element.text = content;
Chris@909 2024 return element;
Chris@909 2025 }
Chris@909 2026
Chris@909 2027 if (ANY_INNERHTML_BUGGY) {
Chris@909 2028 if (tagName in Element._insertionTranslations.tags) {
Chris@909 2029 while (element.firstChild) {
Chris@909 2030 element.removeChild(element.firstChild);
Chris@909 2031 }
Chris@909 2032 Element._getContentFromAnonymousElement(tagName, content.stripScripts())
Chris@909 2033 .each(function(node) {
Chris@909 2034 element.appendChild(node)
Chris@909 2035 });
Chris@909 2036 } else if (LINK_ELEMENT_INNERHTML_BUGGY && Object.isString(content) && content.indexOf('<link') > -1) {
Chris@909 2037 while (element.firstChild) {
Chris@909 2038 element.removeChild(element.firstChild);
Chris@909 2039 }
Chris@909 2040 var nodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts(), true);
Chris@909 2041 nodes.each(function(node) { element.appendChild(node) });
Chris@909 2042 }
Chris@909 2043 else {
Chris@909 2044 element.innerHTML = content.stripScripts();
Chris@909 2045 }
Chris@909 2046 }
Chris@909 2047 else {
Chris@909 2048 element.innerHTML = content.stripScripts();
Chris@909 2049 }
Chris@909 2050
Chris@909 2051 content.evalScripts.bind(content).defer();
Chris@909 2052 return element;
Chris@909 2053 }
Chris@909 2054
Chris@909 2055 return update;
Chris@909 2056 })(),
Chris@909 2057
Chris@909 2058 replace: function(element, content) {
Chris@909 2059 element = $(element);
Chris@909 2060 if (content && content.toElement) content = content.toElement();
Chris@909 2061 else if (!Object.isElement(content)) {
Chris@909 2062 content = Object.toHTML(content);
Chris@909 2063 var range = element.ownerDocument.createRange();
Chris@909 2064 range.selectNode(element);
Chris@909 2065 content.evalScripts.bind(content).defer();
Chris@909 2066 content = range.createContextualFragment(content.stripScripts());
Chris@909 2067 }
Chris@909 2068 element.parentNode.replaceChild(content, element);
Chris@909 2069 return element;
Chris@909 2070 },
Chris@909 2071
Chris@909 2072 insert: function(element, insertions) {
Chris@909 2073 element = $(element);
Chris@909 2074
Chris@909 2075 if (Object.isString(insertions) || Object.isNumber(insertions) ||
Chris@909 2076 Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
Chris@909 2077 insertions = {bottom:insertions};
Chris@909 2078
Chris@909 2079 var content, insert, tagName, childNodes;
Chris@909 2080
Chris@909 2081 for (var position in insertions) {
Chris@909 2082 content = insertions[position];
Chris@909 2083 position = position.toLowerCase();
Chris@909 2084 insert = Element._insertionTranslations[position];
Chris@909 2085
Chris@909 2086 if (content && content.toElement) content = content.toElement();
Chris@909 2087 if (Object.isElement(content)) {
Chris@909 2088 insert(element, content);
Chris@909 2089 continue;
Chris@909 2090 }
Chris@909 2091
Chris@909 2092 content = Object.toHTML(content);
Chris@909 2093
Chris@909 2094 tagName = ((position == 'before' || position == 'after')
Chris@909 2095 ? element.parentNode : element).tagName.toUpperCase();
Chris@909 2096
Chris@909 2097 childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
Chris@909 2098
Chris@909 2099 if (position == 'top' || position == 'after') childNodes.reverse();
Chris@909 2100 childNodes.each(insert.curry(element));
Chris@909 2101
Chris@909 2102 content.evalScripts.bind(content).defer();
Chris@909 2103 }
Chris@909 2104
Chris@909 2105 return element;
Chris@909 2106 },
Chris@909 2107
Chris@909 2108 wrap: function(element, wrapper, attributes) {
Chris@909 2109 element = $(element);
Chris@909 2110 if (Object.isElement(wrapper))
Chris@909 2111 $(wrapper).writeAttribute(attributes || { });
Chris@909 2112 else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);
Chris@909 2113 else wrapper = new Element('div', wrapper);
Chris@909 2114 if (element.parentNode)
Chris@909 2115 element.parentNode.replaceChild(wrapper, element);
Chris@909 2116 wrapper.appendChild(element);
Chris@909 2117 return wrapper;
Chris@909 2118 },
Chris@909 2119
Chris@909 2120 inspect: function(element) {
Chris@909 2121 element = $(element);
Chris@909 2122 var result = '<' + element.tagName.toLowerCase();
Chris@909 2123 $H({'id': 'id', 'className': 'class'}).each(function(pair) {
Chris@909 2124 var property = pair.first(),
Chris@909 2125 attribute = pair.last(),
Chris@909 2126 value = (element[property] || '').toString();
Chris@909 2127 if (value) result += ' ' + attribute + '=' + value.inspect(true);
Chris@909 2128 });
Chris@909 2129 return result + '>';
Chris@909 2130 },
Chris@909 2131
Chris@909 2132 recursivelyCollect: function(element, property, maximumLength) {
Chris@909 2133 element = $(element);
Chris@909 2134 maximumLength = maximumLength || -1;
Chris@909 2135 var elements = [];
Chris@909 2136
Chris@909 2137 while (element = element[property]) {
Chris@909 2138 if (element.nodeType == 1)
Chris@909 2139 elements.push(Element.extend(element));
Chris@909 2140 if (elements.length == maximumLength)
Chris@909 2141 break;
Chris@909 2142 }
Chris@909 2143
Chris@909 2144 return elements;
Chris@909 2145 },
Chris@909 2146
Chris@909 2147 ancestors: function(element) {
Chris@909 2148 return Element.recursivelyCollect(element, 'parentNode');
Chris@909 2149 },
Chris@909 2150
Chris@909 2151 descendants: function(element) {
Chris@909 2152 return Element.select(element, "*");
Chris@909 2153 },
Chris@909 2154
Chris@909 2155 firstDescendant: function(element) {
Chris@909 2156 element = $(element).firstChild;
Chris@909 2157 while (element && element.nodeType != 1) element = element.nextSibling;
Chris@909 2158 return $(element);
Chris@909 2159 },
Chris@909 2160
Chris@909 2161 immediateDescendants: function(element) {
Chris@909 2162 var results = [], child = $(element).firstChild;
Chris@909 2163 while (child) {
Chris@909 2164 if (child.nodeType === 1) {
Chris@909 2165 results.push(Element.extend(child));
Chris@909 2166 }
Chris@909 2167 child = child.nextSibling;
Chris@909 2168 }
Chris@909 2169 return results;
Chris@909 2170 },
Chris@909 2171
Chris@909 2172 previousSiblings: function(element, maximumLength) {
Chris@909 2173 return Element.recursivelyCollect(element, 'previousSibling');
Chris@909 2174 },
Chris@909 2175
Chris@909 2176 nextSiblings: function(element) {
Chris@909 2177 return Element.recursivelyCollect(element, 'nextSibling');
Chris@909 2178 },
Chris@909 2179
Chris@909 2180 siblings: function(element) {
Chris@909 2181 element = $(element);
Chris@909 2182 return Element.previousSiblings(element).reverse()
Chris@909 2183 .concat(Element.nextSiblings(element));
Chris@909 2184 },
Chris@909 2185
Chris@909 2186 match: function(element, selector) {
Chris@909 2187 element = $(element);
Chris@909 2188 if (Object.isString(selector))
Chris@909 2189 return Prototype.Selector.match(element, selector);
Chris@909 2190 return selector.match(element);
Chris@909 2191 },
Chris@909 2192
Chris@909 2193 up: function(element, expression, index) {
Chris@909 2194 element = $(element);
Chris@909 2195 if (arguments.length == 1) return $(element.parentNode);
Chris@909 2196 var ancestors = Element.ancestors(element);
Chris@909 2197 return Object.isNumber(expression) ? ancestors[expression] :
Chris@909 2198 Prototype.Selector.find(ancestors, expression, index);
Chris@909 2199 },
Chris@909 2200
Chris@909 2201 down: function(element, expression, index) {
Chris@909 2202 element = $(element);
Chris@909 2203 if (arguments.length == 1) return Element.firstDescendant(element);
Chris@909 2204 return Object.isNumber(expression) ? Element.descendants(element)[expression] :
Chris@909 2205 Element.select(element, expression)[index || 0];
Chris@909 2206 },
Chris@909 2207
Chris@909 2208 previous: function(element, expression, index) {
Chris@909 2209 element = $(element);
Chris@909 2210 if (Object.isNumber(expression)) index = expression, expression = false;
Chris@909 2211 if (!Object.isNumber(index)) index = 0;
Chris@909 2212
Chris@909 2213 if (expression) {
Chris@909 2214 return Prototype.Selector.find(element.previousSiblings(), expression, index);
Chris@909 2215 } else {
Chris@909 2216 return element.recursivelyCollect("previousSibling", index + 1)[index];
Chris@909 2217 }
Chris@909 2218 },
Chris@909 2219
Chris@909 2220 next: function(element, expression, index) {
Chris@909 2221 element = $(element);
Chris@909 2222 if (Object.isNumber(expression)) index = expression, expression = false;
Chris@909 2223 if (!Object.isNumber(index)) index = 0;
Chris@909 2224
Chris@909 2225 if (expression) {
Chris@909 2226 return Prototype.Selector.find(element.nextSiblings(), expression, index);
Chris@909 2227 } else {
Chris@909 2228 var maximumLength = Object.isNumber(index) ? index + 1 : 1;
Chris@909 2229 return element.recursivelyCollect("nextSibling", index + 1)[index];
Chris@909 2230 }
Chris@909 2231 },
Chris@909 2232
Chris@909 2233
Chris@909 2234 select: function(element) {
Chris@909 2235 element = $(element);
Chris@909 2236 var expressions = Array.prototype.slice.call(arguments, 1).join(', ');
Chris@909 2237 return Prototype.Selector.select(expressions, element);
Chris@909 2238 },
Chris@909 2239
Chris@909 2240 adjacent: function(element) {
Chris@909 2241 element = $(element);
Chris@909 2242 var expressions = Array.prototype.slice.call(arguments, 1).join(', ');
Chris@909 2243 return Prototype.Selector.select(expressions, element.parentNode).without(element);
Chris@909 2244 },
Chris@909 2245
Chris@909 2246 identify: function(element) {
Chris@909 2247 element = $(element);
Chris@909 2248 var id = Element.readAttribute(element, 'id');
Chris@909 2249 if (id) return id;
Chris@909 2250 do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id));
Chris@909 2251 Element.writeAttribute(element, 'id', id);
Chris@909 2252 return id;
Chris@909 2253 },
Chris@909 2254
Chris@909 2255 readAttribute: function(element, name) {
Chris@909 2256 element = $(element);
Chris@909 2257 if (Prototype.Browser.IE) {
Chris@909 2258 var t = Element._attributeTranslations.read;
Chris@909 2259 if (t.values[name]) return t.values[name](element, name);
Chris@909 2260 if (t.names[name]) name = t.names[name];
Chris@909 2261 if (name.include(':')) {
Chris@909 2262 return (!element.attributes || !element.attributes[name]) ? null :
Chris@909 2263 element.attributes[name].value;
Chris@909 2264 }
Chris@909 2265 }
Chris@909 2266 return element.getAttribute(name);
Chris@909 2267 },
Chris@909 2268
Chris@909 2269 writeAttribute: function(element, name, value) {
Chris@909 2270 element = $(element);
Chris@909 2271 var attributes = { }, t = Element._attributeTranslations.write;
Chris@909 2272
Chris@909 2273 if (typeof name == 'object') attributes = name;
Chris@909 2274 else attributes[name] = Object.isUndefined(value) ? true : value;
Chris@909 2275
Chris@909 2276 for (var attr in attributes) {
Chris@909 2277 name = t.names[attr] || attr;
Chris@909 2278 value = attributes[attr];
Chris@909 2279 if (t.values[attr]) name = t.values[attr](element, value);
Chris@909 2280 if (value === false || value === null)
Chris@909 2281 element.removeAttribute(name);
Chris@909 2282 else if (value === true)
Chris@909 2283 element.setAttribute(name, name);
Chris@909 2284 else element.setAttribute(name, value);
Chris@909 2285 }
Chris@909 2286 return element;
Chris@909 2287 },
Chris@909 2288
Chris@909 2289 getHeight: function(element) {
Chris@909 2290 return Element.getDimensions(element).height;
Chris@909 2291 },
Chris@909 2292
Chris@909 2293 getWidth: function(element) {
Chris@909 2294 return Element.getDimensions(element).width;
Chris@909 2295 },
Chris@909 2296
Chris@909 2297 classNames: function(element) {
Chris@909 2298 return new Element.ClassNames(element);
Chris@909 2299 },
Chris@909 2300
Chris@909 2301 hasClassName: function(element, className) {
Chris@909 2302 if (!(element = $(element))) return;
Chris@909 2303 var elementClassName = element.className;
Chris@909 2304 return (elementClassName.length > 0 && (elementClassName == className ||
Chris@909 2305 new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
Chris@909 2306 },
Chris@909 2307
Chris@909 2308 addClassName: function(element, className) {
Chris@909 2309 if (!(element = $(element))) return;
Chris@909 2310 if (!Element.hasClassName(element, className))
Chris@909 2311 element.className += (element.className ? ' ' : '') + className;
Chris@909 2312 return element;
Chris@909 2313 },
Chris@909 2314
Chris@909 2315 removeClassName: function(element, className) {
Chris@909 2316 if (!(element = $(element))) return;
Chris@909 2317 element.className = element.className.replace(
Chris@909 2318 new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
Chris@909 2319 return element;
Chris@909 2320 },
Chris@909 2321
Chris@909 2322 toggleClassName: function(element, className) {
Chris@909 2323 if (!(element = $(element))) return;
Chris@909 2324 return Element[Element.hasClassName(element, className) ?
Chris@909 2325 'removeClassName' : 'addClassName'](element, className);
Chris@909 2326 },
Chris@909 2327
Chris@909 2328 cleanWhitespace: function(element) {
Chris@909 2329 element = $(element);
Chris@909 2330 var node = element.firstChild;
Chris@909 2331 while (node) {
Chris@909 2332 var nextNode = node.nextSibling;
Chris@909 2333 if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
Chris@909 2334 element.removeChild(node);
Chris@909 2335 node = nextNode;
Chris@909 2336 }
Chris@909 2337 return element;
Chris@909 2338 },
Chris@909 2339
Chris@909 2340 empty: function(element) {
Chris@909 2341 return $(element).innerHTML.blank();
Chris@909 2342 },
Chris@909 2343
Chris@909 2344 descendantOf: function(element, ancestor) {
Chris@909 2345 element = $(element), ancestor = $(ancestor);
Chris@909 2346
Chris@909 2347 if (element.compareDocumentPosition)
Chris@909 2348 return (element.compareDocumentPosition(ancestor) & 8) === 8;
Chris@909 2349
Chris@909 2350 if (ancestor.contains)
Chris@909 2351 return ancestor.contains(element) && ancestor !== element;
Chris@909 2352
Chris@909 2353 while (element = element.parentNode)
Chris@909 2354 if (element == ancestor) return true;
Chris@909 2355
Chris@909 2356 return false;
Chris@909 2357 },
Chris@909 2358
Chris@909 2359 scrollTo: function(element) {
Chris@909 2360 element = $(element);
Chris@909 2361 var pos = Element.cumulativeOffset(element);
Chris@909 2362 window.scrollTo(pos[0], pos[1]);
Chris@909 2363 return element;
Chris@909 2364 },
Chris@909 2365
Chris@909 2366 getStyle: function(element, style) {
Chris@909 2367 element = $(element);
Chris@909 2368 style = style == 'float' ? 'cssFloat' : style.camelize();
Chris@909 2369 var value = element.style[style];
Chris@909 2370 if (!value || value == 'auto') {
Chris@909 2371 var css = document.defaultView.getComputedStyle(element, null);
Chris@909 2372 value = css ? css[style] : null;
Chris@909 2373 }
Chris@909 2374 if (style == 'opacity') return value ? parseFloat(value) : 1.0;
Chris@909 2375 return value == 'auto' ? null : value;
Chris@909 2376 },
Chris@909 2377
Chris@909 2378 getOpacity: function(element) {
Chris@909 2379 return $(element).getStyle('opacity');
Chris@909 2380 },
Chris@909 2381
Chris@909 2382 setStyle: function(element, styles) {
Chris@909 2383 element = $(element);
Chris@909 2384 var elementStyle = element.style, match;
Chris@909 2385 if (Object.isString(styles)) {
Chris@909 2386 element.style.cssText += ';' + styles;
Chris@909 2387 return styles.include('opacity') ?
Chris@909 2388 element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
Chris@909 2389 }
Chris@909 2390 for (var property in styles)
Chris@909 2391 if (property == 'opacity') element.setOpacity(styles[property]);
Chris@909 2392 else
Chris@909 2393 elementStyle[(property == 'float' || property == 'cssFloat') ?
Chris@909 2394 (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
Chris@909 2395 property] = styles[property];
Chris@909 2396
Chris@909 2397 return element;
Chris@909 2398 },
Chris@909 2399
Chris@909 2400 setOpacity: function(element, value) {
Chris@909 2401 element = $(element);
Chris@909 2402 element.style.opacity = (value == 1 || value === '') ? '' :
Chris@909 2403 (value < 0.00001) ? 0 : value;
Chris@909 2404 return element;
Chris@909 2405 },
Chris@909 2406
Chris@909 2407 makePositioned: function(element) {
Chris@909 2408 element = $(element);
Chris@909 2409 var pos = Element.getStyle(element, 'position');
Chris@909 2410 if (pos == 'static' || !pos) {
Chris@909 2411 element._madePositioned = true;
Chris@909 2412 element.style.position = 'relative';
Chris@909 2413 if (Prototype.Browser.Opera) {
Chris@909 2414 element.style.top = 0;
Chris@909 2415 element.style.left = 0;
Chris@909 2416 }
Chris@909 2417 }
Chris@909 2418 return element;
Chris@909 2419 },
Chris@909 2420
Chris@909 2421 undoPositioned: function(element) {
Chris@909 2422 element = $(element);
Chris@909 2423 if (element._madePositioned) {
Chris@909 2424 element._madePositioned = undefined;
Chris@909 2425 element.style.position =
Chris@909 2426 element.style.top =
Chris@909 2427 element.style.left =
Chris@909 2428 element.style.bottom =
Chris@909 2429 element.style.right = '';
Chris@909 2430 }
Chris@909 2431 return element;
Chris@909 2432 },
Chris@909 2433
Chris@909 2434 makeClipping: function(element) {
Chris@909 2435 element = $(element);
Chris@909 2436 if (element._overflow) return element;
Chris@909 2437 element._overflow = Element.getStyle(element, 'overflow') || 'auto';
Chris@909 2438 if (element._overflow !== 'hidden')
Chris@909 2439 element.style.overflow = 'hidden';
Chris@909 2440 return element;
Chris@909 2441 },
Chris@909 2442
Chris@909 2443 undoClipping: function(element) {
Chris@909 2444 element = $(element);
Chris@909 2445 if (!element._overflow) return element;
Chris@909 2446 element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
Chris@909 2447 element._overflow = null;
Chris@909 2448 return element;
Chris@909 2449 },
Chris@909 2450
Chris@909 2451 clonePosition: function(element, source) {
Chris@909 2452 var options = Object.extend({
Chris@909 2453 setLeft: true,
Chris@909 2454 setTop: true,
Chris@909 2455 setWidth: true,
Chris@909 2456 setHeight: true,
Chris@909 2457 offsetTop: 0,
Chris@909 2458 offsetLeft: 0
Chris@909 2459 }, arguments[2] || { });
Chris@909 2460
Chris@909 2461 source = $(source);
Chris@909 2462 var p = Element.viewportOffset(source), delta = [0, 0], parent = null;
Chris@909 2463
Chris@909 2464 element = $(element);
Chris@909 2465
Chris@909 2466 if (Element.getStyle(element, 'position') == 'absolute') {
Chris@909 2467 parent = Element.getOffsetParent(element);
Chris@909 2468 delta = Element.viewportOffset(parent);
Chris@909 2469 }
Chris@909 2470
Chris@909 2471 if (parent == document.body) {
Chris@909 2472 delta[0] -= document.body.offsetLeft;
Chris@909 2473 delta[1] -= document.body.offsetTop;
Chris@909 2474 }
Chris@909 2475
Chris@909 2476 if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
Chris@909 2477 if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
Chris@909 2478 if (options.setWidth) element.style.width = source.offsetWidth + 'px';
Chris@909 2479 if (options.setHeight) element.style.height = source.offsetHeight + 'px';
Chris@909 2480 return element;
Chris@909 2481 }
Chris@909 2482 };
Chris@909 2483
Chris@909 2484 Object.extend(Element.Methods, {
Chris@909 2485 getElementsBySelector: Element.Methods.select,
Chris@909 2486
Chris@909 2487 childElements: Element.Methods.immediateDescendants
Chris@909 2488 });
Chris@909 2489
Chris@909 2490 Element._attributeTranslations = {
Chris@909 2491 write: {
Chris@909 2492 names: {
Chris@909 2493 className: 'class',
Chris@909 2494 htmlFor: 'for'
Chris@909 2495 },
Chris@909 2496 values: { }
Chris@909 2497 }
Chris@909 2498 };
Chris@909 2499
Chris@909 2500 if (Prototype.Browser.Opera) {
Chris@909 2501 Element.Methods.getStyle = Element.Methods.getStyle.wrap(
Chris@909 2502 function(proceed, element, style) {
Chris@909 2503 switch (style) {
Chris@909 2504 case 'height': case 'width':
Chris@909 2505 if (!Element.visible(element)) return null;
Chris@909 2506
Chris@909 2507 var dim = parseInt(proceed(element, style), 10);
Chris@909 2508
Chris@909 2509 if (dim !== element['offset' + style.capitalize()])
Chris@909 2510 return dim + 'px';
Chris@909 2511
Chris@909 2512 var properties;
Chris@909 2513 if (style === 'height') {
Chris@909 2514 properties = ['border-top-width', 'padding-top',
Chris@909 2515 'padding-bottom', 'border-bottom-width'];
Chris@909 2516 }
Chris@909 2517 else {
Chris@909 2518 properties = ['border-left-width', 'padding-left',
Chris@909 2519 'padding-right', 'border-right-width'];
Chris@909 2520 }
Chris@909 2521 return properties.inject(dim, function(memo, property) {
Chris@909 2522 var val = proceed(element, property);
Chris@909 2523 return val === null ? memo : memo - parseInt(val, 10);
Chris@909 2524 }) + 'px';
Chris@909 2525 default: return proceed(element, style);
Chris@909 2526 }
Chris@909 2527 }
Chris@909 2528 );
Chris@909 2529
Chris@909 2530 Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
Chris@909 2531 function(proceed, element, attribute) {
Chris@909 2532 if (attribute === 'title') return element.title;
Chris@909 2533 return proceed(element, attribute);
Chris@909 2534 }
Chris@909 2535 );
Chris@909 2536 }
Chris@909 2537
Chris@909 2538 else if (Prototype.Browser.IE) {
Chris@909 2539 Element.Methods.getStyle = function(element, style) {
Chris@909 2540 element = $(element);
Chris@909 2541 style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
Chris@909 2542 var value = element.style[style];
Chris@909 2543 if (!value && element.currentStyle) value = element.currentStyle[style];
Chris@909 2544
Chris@909 2545 if (style == 'opacity') {
Chris@909 2546 if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
Chris@909 2547 if (value[1]) return parseFloat(value[1]) / 100;
Chris@909 2548 return 1.0;
Chris@909 2549 }
Chris@909 2550
Chris@909 2551 if (value == 'auto') {
Chris@909 2552 if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
Chris@909 2553 return element['offset' + style.capitalize()] + 'px';
Chris@909 2554 return null;
Chris@909 2555 }
Chris@909 2556 return value;
Chris@909 2557 };
Chris@909 2558
Chris@909 2559 Element.Methods.setOpacity = function(element, value) {
Chris@909 2560 function stripAlpha(filter){
Chris@909 2561 return filter.replace(/alpha\([^\)]*\)/gi,'');
Chris@909 2562 }
Chris@909 2563 element = $(element);
Chris@909 2564 var currentStyle = element.currentStyle;
Chris@909 2565 if ((currentStyle && !currentStyle.hasLayout) ||
Chris@909 2566 (!currentStyle && element.style.zoom == 'normal'))
Chris@909 2567 element.style.zoom = 1;
Chris@909 2568
Chris@909 2569 var filter = element.getStyle('filter'), style = element.style;
Chris@909 2570 if (value == 1 || value === '') {
Chris@909 2571 (filter = stripAlpha(filter)) ?
Chris@909 2572 style.filter = filter : style.removeAttribute('filter');
Chris@909 2573 return element;
Chris@909 2574 } else if (value < 0.00001) value = 0;
Chris@909 2575 style.filter = stripAlpha(filter) +
Chris@909 2576 'alpha(opacity=' + (value * 100) + ')';
Chris@909 2577 return element;
Chris@909 2578 };
Chris@909 2579
Chris@909 2580 Element._attributeTranslations = (function(){
Chris@909 2581
Chris@909 2582 var classProp = 'className',
Chris@909 2583 forProp = 'for',
Chris@909 2584 el = document.createElement('div');
Chris@909 2585
Chris@909 2586 el.setAttribute(classProp, 'x');
Chris@909 2587
Chris@909 2588 if (el.className !== 'x') {
Chris@909 2589 el.setAttribute('class', 'x');
Chris@909 2590 if (el.className === 'x') {
Chris@909 2591 classProp = 'class';
Chris@909 2592 }
Chris@909 2593 }
Chris@909 2594 el = null;
Chris@909 2595
Chris@909 2596 el = document.createElement('label');
Chris@909 2597 el.setAttribute(forProp, 'x');
Chris@909 2598 if (el.htmlFor !== 'x') {
Chris@909 2599 el.setAttribute('htmlFor', 'x');
Chris@909 2600 if (el.htmlFor === 'x') {
Chris@909 2601 forProp = 'htmlFor';
Chris@909 2602 }
Chris@909 2603 }
Chris@909 2604 el = null;
Chris@909 2605
Chris@909 2606 return {
Chris@909 2607 read: {
Chris@909 2608 names: {
Chris@909 2609 'class': classProp,
Chris@909 2610 'className': classProp,
Chris@909 2611 'for': forProp,
Chris@909 2612 'htmlFor': forProp
Chris@909 2613 },
Chris@909 2614 values: {
Chris@909 2615 _getAttr: function(element, attribute) {
Chris@909 2616 return element.getAttribute(attribute);
Chris@909 2617 },
Chris@909 2618 _getAttr2: function(element, attribute) {
Chris@909 2619 return element.getAttribute(attribute, 2);
Chris@909 2620 },
Chris@909 2621 _getAttrNode: function(element, attribute) {
Chris@909 2622 var node = element.getAttributeNode(attribute);
Chris@909 2623 return node ? node.value : "";
Chris@909 2624 },
Chris@909 2625 _getEv: (function(){
Chris@909 2626
Chris@909 2627 var el = document.createElement('div'), f;
Chris@909 2628 el.onclick = Prototype.emptyFunction;
Chris@909 2629 var value = el.getAttribute('onclick');
Chris@909 2630
Chris@909 2631 if (String(value).indexOf('{') > -1) {
Chris@909 2632 f = function(element, attribute) {
Chris@909 2633 attribute = element.getAttribute(attribute);
Chris@909 2634 if (!attribute) return null;
Chris@909 2635 attribute = attribute.toString();
Chris@909 2636 attribute = attribute.split('{')[1];
Chris@909 2637 attribute = attribute.split('}')[0];
Chris@909 2638 return attribute.strip();
Chris@909 2639 };
Chris@909 2640 }
Chris@909 2641 else if (value === '') {
Chris@909 2642 f = function(element, attribute) {
Chris@909 2643 attribute = element.getAttribute(attribute);
Chris@909 2644 if (!attribute) return null;
Chris@909 2645 return attribute.strip();
Chris@909 2646 };
Chris@909 2647 }
Chris@909 2648 el = null;
Chris@909 2649 return f;
Chris@909 2650 })(),
Chris@909 2651 _flag: function(element, attribute) {
Chris@909 2652 return $(element).hasAttribute(attribute) ? attribute : null;
Chris@909 2653 },
Chris@909 2654 style: function(element) {
Chris@909 2655 return element.style.cssText.toLowerCase();
Chris@909 2656 },
Chris@909 2657 title: function(element) {
Chris@909 2658 return element.title;
Chris@909 2659 }
Chris@909 2660 }
Chris@909 2661 }
Chris@909 2662 }
Chris@909 2663 })();
Chris@909 2664
Chris@909 2665 Element._attributeTranslations.write = {
Chris@909 2666 names: Object.extend({
Chris@909 2667 cellpadding: 'cellPadding',
Chris@909 2668 cellspacing: 'cellSpacing'
Chris@909 2669 }, Element._attributeTranslations.read.names),
Chris@909 2670 values: {
Chris@909 2671 checked: function(element, value) {
Chris@909 2672 element.checked = !!value;
Chris@909 2673 },
Chris@909 2674
Chris@909 2675 style: function(element, value) {
Chris@909 2676 element.style.cssText = value ? value : '';
Chris@909 2677 }
Chris@909 2678 }
Chris@909 2679 };
Chris@909 2680
Chris@909 2681 Element._attributeTranslations.has = {};
Chris@909 2682
Chris@909 2683 $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
Chris@909 2684 'encType maxLength readOnly longDesc frameBorder').each(function(attr) {
Chris@909 2685 Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
Chris@909 2686 Element._attributeTranslations.has[attr.toLowerCase()] = attr;
Chris@909 2687 });
Chris@909 2688
Chris@909 2689 (function(v) {
Chris@909 2690 Object.extend(v, {
Chris@909 2691 href: v._getAttr2,
Chris@909 2692 src: v._getAttr2,
Chris@909 2693 type: v._getAttr,
Chris@909 2694 action: v._getAttrNode,
Chris@909 2695 disabled: v._flag,
Chris@909 2696 checked: v._flag,
Chris@909 2697 readonly: v._flag,
Chris@909 2698 multiple: v._flag,
Chris@909 2699 onload: v._getEv,
Chris@909 2700 onunload: v._getEv,
Chris@909 2701 onclick: v._getEv,
Chris@909 2702 ondblclick: v._getEv,
Chris@909 2703 onmousedown: v._getEv,
Chris@909 2704 onmouseup: v._getEv,
Chris@909 2705 onmouseover: v._getEv,
Chris@909 2706 onmousemove: v._getEv,
Chris@909 2707 onmouseout: v._getEv,
Chris@909 2708 onfocus: v._getEv,
Chris@909 2709 onblur: v._getEv,
Chris@909 2710 onkeypress: v._getEv,
Chris@909 2711 onkeydown: v._getEv,
Chris@909 2712 onkeyup: v._getEv,
Chris@909 2713 onsubmit: v._getEv,
Chris@909 2714 onreset: v._getEv,
Chris@909 2715 onselect: v._getEv,
Chris@909 2716 onchange: v._getEv
Chris@909 2717 });
Chris@909 2718 })(Element._attributeTranslations.read.values);
Chris@909 2719
Chris@909 2720 if (Prototype.BrowserFeatures.ElementExtensions) {
Chris@909 2721 (function() {
Chris@909 2722 function _descendants(element) {
Chris@909 2723 var nodes = element.getElementsByTagName('*'), results = [];
Chris@909 2724 for (var i = 0, node; node = nodes[i]; i++)
Chris@909 2725 if (node.tagName !== "!") // Filter out comment nodes.
Chris@909 2726 results.push(node);
Chris@909 2727 return results;
Chris@909 2728 }
Chris@909 2729
Chris@909 2730 Element.Methods.down = function(element, expression, index) {
Chris@909 2731 element = $(element);
Chris@909 2732 if (arguments.length == 1) return element.firstDescendant();
Chris@909 2733 return Object.isNumber(expression) ? _descendants(element)[expression] :
Chris@909 2734 Element.select(element, expression)[index || 0];
Chris@909 2735 }
Chris@909 2736 })();
Chris@909 2737 }
Chris@909 2738
Chris@909 2739 }
Chris@909 2740
Chris@909 2741 else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
Chris@909 2742 Element.Methods.setOpacity = function(element, value) {
Chris@909 2743 element = $(element);
Chris@909 2744 element.style.opacity = (value == 1) ? 0.999999 :
Chris@909 2745 (value === '') ? '' : (value < 0.00001) ? 0 : value;
Chris@909 2746 return element;
Chris@909 2747 };
Chris@909 2748 }
Chris@909 2749
Chris@909 2750 else if (Prototype.Browser.WebKit) {
Chris@909 2751 Element.Methods.setOpacity = function(element, value) {
Chris@909 2752 element = $(element);
Chris@909 2753 element.style.opacity = (value == 1 || value === '') ? '' :
Chris@909 2754 (value < 0.00001) ? 0 : value;
Chris@909 2755
Chris@909 2756 if (value == 1)
Chris@909 2757 if (element.tagName.toUpperCase() == 'IMG' && element.width) {
Chris@909 2758 element.width++; element.width--;
Chris@909 2759 } else try {
Chris@909 2760 var n = document.createTextNode(' ');
Chris@909 2761 element.appendChild(n);
Chris@909 2762 element.removeChild(n);
Chris@909 2763 } catch (e) { }
Chris@909 2764
Chris@909 2765 return element;
Chris@909 2766 };
Chris@909 2767 }
Chris@909 2768
Chris@909 2769 if ('outerHTML' in document.documentElement) {
Chris@909 2770 Element.Methods.replace = function(element, content) {
Chris@909 2771 element = $(element);
Chris@909 2772
Chris@909 2773 if (content && content.toElement) content = content.toElement();
Chris@909 2774 if (Object.isElement(content)) {
Chris@909 2775 element.parentNode.replaceChild(content, element);
Chris@909 2776 return element;
Chris@909 2777 }
Chris@909 2778
Chris@909 2779 content = Object.toHTML(content);
Chris@909 2780 var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
Chris@909 2781
Chris@909 2782 if (Element._insertionTranslations.tags[tagName]) {
Chris@909 2783 var nextSibling = element.next(),
Chris@909 2784 fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
Chris@909 2785 parent.removeChild(element);
Chris@909 2786 if (nextSibling)
Chris@909 2787 fragments.each(function(node) { parent.insertBefore(node, nextSibling) });
Chris@909 2788 else
Chris@909 2789 fragments.each(function(node) { parent.appendChild(node) });
Chris@909 2790 }
Chris@909 2791 else element.outerHTML = content.stripScripts();
Chris@909 2792
Chris@909 2793 content.evalScripts.bind(content).defer();
Chris@909 2794 return element;
Chris@909 2795 };
Chris@909 2796 }
Chris@909 2797
Chris@909 2798 Element._returnOffset = function(l, t) {
Chris@909 2799 var result = [l, t];
Chris@909 2800 result.left = l;
Chris@909 2801 result.top = t;
Chris@909 2802 return result;
Chris@909 2803 };
Chris@909 2804
Chris@909 2805 Element._getContentFromAnonymousElement = function(tagName, html, force) {
Chris@909 2806 var div = new Element('div'),
Chris@909 2807 t = Element._insertionTranslations.tags[tagName];
Chris@909 2808
Chris@909 2809 var workaround = false;
Chris@909 2810 if (t) workaround = true;
Chris@909 2811 else if (force) {
Chris@909 2812 workaround = true;
Chris@909 2813 t = ['', '', 0];
Chris@909 2814 }
Chris@909 2815
Chris@909 2816 if (workaround) {
Chris@909 2817 div.innerHTML = '&nbsp;' + t[0] + html + t[1];
Chris@909 2818 div.removeChild(div.firstChild);
Chris@909 2819 for (var i = t[2]; i--; ) {
Chris@909 2820 div = div.firstChild;
Chris@909 2821 }
Chris@909 2822 }
Chris@909 2823 else {
Chris@909 2824 div.innerHTML = html;
Chris@909 2825 }
Chris@909 2826 return $A(div.childNodes);
Chris@909 2827 };
Chris@909 2828
Chris@909 2829 Element._insertionTranslations = {
Chris@909 2830 before: function(element, node) {
Chris@909 2831 element.parentNode.insertBefore(node, element);
Chris@909 2832 },
Chris@909 2833 top: function(element, node) {
Chris@909 2834 element.insertBefore(node, element.firstChild);
Chris@909 2835 },
Chris@909 2836 bottom: function(element, node) {
Chris@909 2837 element.appendChild(node);
Chris@909 2838 },
Chris@909 2839 after: function(element, node) {
Chris@909 2840 element.parentNode.insertBefore(node, element.nextSibling);
Chris@909 2841 },
Chris@909 2842 tags: {
Chris@909 2843 TABLE: ['<table>', '</table>', 1],
Chris@909 2844 TBODY: ['<table><tbody>', '</tbody></table>', 2],
Chris@909 2845 TR: ['<table><tbody><tr>', '</tr></tbody></table>', 3],
Chris@909 2846 TD: ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
Chris@909 2847 SELECT: ['<select>', '</select>', 1]
Chris@909 2848 }
Chris@909 2849 };
Chris@909 2850
Chris@909 2851 (function() {
Chris@909 2852 var tags = Element._insertionTranslations.tags;
Chris@909 2853 Object.extend(tags, {
Chris@909 2854 THEAD: tags.TBODY,
Chris@909 2855 TFOOT: tags.TBODY,
Chris@909 2856 TH: tags.TD
Chris@909 2857 });
Chris@909 2858 })();
Chris@909 2859
Chris@909 2860 Element.Methods.Simulated = {
Chris@909 2861 hasAttribute: function(element, attribute) {
Chris@909 2862 attribute = Element._attributeTranslations.has[attribute] || attribute;
Chris@909 2863 var node = $(element).getAttributeNode(attribute);
Chris@909 2864 return !!(node && node.specified);
Chris@909 2865 }
Chris@909 2866 };
Chris@909 2867
Chris@909 2868 Element.Methods.ByTag = { };
Chris@909 2869
Chris@909 2870 Object.extend(Element, Element.Methods);
Chris@909 2871
Chris@909 2872 (function(div) {
Chris@909 2873
Chris@909 2874 if (!Prototype.BrowserFeatures.ElementExtensions && div['__proto__']) {
Chris@909 2875 window.HTMLElement = { };
Chris@909 2876 window.HTMLElement.prototype = div['__proto__'];
Chris@909 2877 Prototype.BrowserFeatures.ElementExtensions = true;
Chris@909 2878 }
Chris@909 2879
Chris@909 2880 div = null;
Chris@909 2881
Chris@909 2882 })(document.createElement('div'));
Chris@909 2883
Chris@909 2884 Element.extend = (function() {
Chris@909 2885
Chris@909 2886 function checkDeficiency(tagName) {
Chris@909 2887 if (typeof window.Element != 'undefined') {
Chris@909 2888 var proto = window.Element.prototype;
Chris@909 2889 if (proto) {
Chris@909 2890 var id = '_' + (Math.random()+'').slice(2),
Chris@909 2891 el = document.createElement(tagName);
Chris@909 2892 proto[id] = 'x';
Chris@909 2893 var isBuggy = (el[id] !== 'x');
Chris@909 2894 delete proto[id];
Chris@909 2895 el = null;
Chris@909 2896 return isBuggy;
Chris@909 2897 }
Chris@909 2898 }
Chris@909 2899 return false;
Chris@909 2900 }
Chris@909 2901
Chris@909 2902 function extendElementWith(element, methods) {
Chris@909 2903 for (var property in methods) {
Chris@909 2904 var value = methods[property];
Chris@909 2905 if (Object.isFunction(value) && !(property in element))
Chris@909 2906 element[property] = value.methodize();
Chris@909 2907 }
Chris@909 2908 }
Chris@909 2909
Chris@909 2910 var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY = checkDeficiency('object');
Chris@909 2911
Chris@909 2912 if (Prototype.BrowserFeatures.SpecificElementExtensions) {
Chris@909 2913 if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY) {
Chris@909 2914 return function(element) {
Chris@909 2915 if (element && typeof element._extendedByPrototype == 'undefined') {
Chris@909 2916 var t = element.tagName;
Chris@909 2917 if (t && (/^(?:object|applet|embed)$/i.test(t))) {
Chris@909 2918 extendElementWith(element, Element.Methods);
Chris@909 2919 extendElementWith(element, Element.Methods.Simulated);
Chris@909 2920 extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]);
Chris@909 2921 }
Chris@909 2922 }
Chris@909 2923 return element;
Chris@909 2924 }
Chris@909 2925 }
Chris@909 2926 return Prototype.K;
Chris@909 2927 }
Chris@909 2928
Chris@909 2929 var Methods = { }, ByTag = Element.Methods.ByTag;
Chris@909 2930
Chris@909 2931 var extend = Object.extend(function(element) {
Chris@909 2932 if (!element || typeof element._extendedByPrototype != 'undefined' ||
Chris@909 2933 element.nodeType != 1 || element == window) return element;
Chris@909 2934
Chris@909 2935 var methods = Object.clone(Methods),
Chris@909 2936 tagName = element.tagName.toUpperCase();
Chris@909 2937
Chris@909 2938 if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
Chris@909 2939
Chris@909 2940 extendElementWith(element, methods);
Chris@909 2941
Chris@909 2942 element._extendedByPrototype = Prototype.emptyFunction;
Chris@909 2943 return element;
Chris@909 2944
Chris@909 2945 }, {
Chris@909 2946 refresh: function() {
Chris@909 2947 if (!Prototype.BrowserFeatures.ElementExtensions) {
Chris@909 2948 Object.extend(Methods, Element.Methods);
Chris@909 2949 Object.extend(Methods, Element.Methods.Simulated);
Chris@909 2950 }
Chris@909 2951 }
Chris@909 2952 });
Chris@909 2953
Chris@909 2954 extend.refresh();
Chris@909 2955 return extend;
Chris@909 2956 })();
Chris@909 2957
Chris@909 2958 if (document.documentElement.hasAttribute) {
Chris@909 2959 Element.hasAttribute = function(element, attribute) {
Chris@909 2960 return element.hasAttribute(attribute);
Chris@909 2961 };
Chris@909 2962 }
Chris@909 2963 else {
Chris@909 2964 Element.hasAttribute = Element.Methods.Simulated.hasAttribute;
Chris@909 2965 }
Chris@909 2966
Chris@909 2967 Element.addMethods = function(methods) {
Chris@909 2968 var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
Chris@909 2969
Chris@909 2970 if (!methods) {
Chris@909 2971 Object.extend(Form, Form.Methods);
Chris@909 2972 Object.extend(Form.Element, Form.Element.Methods);
Chris@909 2973 Object.extend(Element.Methods.ByTag, {
Chris@909 2974 "FORM": Object.clone(Form.Methods),
Chris@909 2975 "INPUT": Object.clone(Form.Element.Methods),
Chris@909 2976 "SELECT": Object.clone(Form.Element.Methods),
Chris@909 2977 "TEXTAREA": Object.clone(Form.Element.Methods),
Chris@909 2978 "BUTTON": Object.clone(Form.Element.Methods)
Chris@909 2979 });
Chris@909 2980 }
Chris@909 2981
Chris@909 2982 if (arguments.length == 2) {
Chris@909 2983 var tagName = methods;
Chris@909 2984 methods = arguments[1];
Chris@909 2985 }
Chris@909 2986
Chris@909 2987 if (!tagName) Object.extend(Element.Methods, methods || { });
Chris@909 2988 else {
Chris@909 2989 if (Object.isArray(tagName)) tagName.each(extend);
Chris@909 2990 else extend(tagName);
Chris@909 2991 }
Chris@909 2992
Chris@909 2993 function extend(tagName) {
Chris@909 2994 tagName = tagName.toUpperCase();
Chris@909 2995 if (!Element.Methods.ByTag[tagName])
Chris@909 2996 Element.Methods.ByTag[tagName] = { };
Chris@909 2997 Object.extend(Element.Methods.ByTag[tagName], methods);
Chris@909 2998 }
Chris@909 2999
Chris@909 3000 function copy(methods, destination, onlyIfAbsent) {
Chris@909 3001 onlyIfAbsent = onlyIfAbsent || false;
Chris@909 3002 for (var property in methods) {
Chris@909 3003 var value = methods[property];
Chris@909 3004 if (!Object.isFunction(value)) continue;
Chris@909 3005 if (!onlyIfAbsent || !(property in destination))
Chris@909 3006 destination[property] = value.methodize();
Chris@909 3007 }
Chris@909 3008 }
Chris@909 3009
Chris@909 3010 function findDOMClass(tagName) {
Chris@909 3011 var klass;
Chris@909 3012 var trans = {
Chris@909 3013 "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
Chris@909 3014 "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
Chris@909 3015 "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
Chris@909 3016 "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
Chris@909 3017 "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
Chris@909 3018 "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
Chris@909 3019 "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
Chris@909 3020 "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
Chris@909 3021 "FrameSet", "IFRAME": "IFrame"
Chris@909 3022 };
Chris@909 3023 if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
Chris@909 3024 if (window[klass]) return window[klass];
Chris@909 3025 klass = 'HTML' + tagName + 'Element';
Chris@909 3026 if (window[klass]) return window[klass];
Chris@909 3027 klass = 'HTML' + tagName.capitalize() + 'Element';
Chris@909 3028 if (window[klass]) return window[klass];
Chris@909 3029
Chris@909 3030 var element = document.createElement(tagName),
Chris@909 3031 proto = element['__proto__'] || element.constructor.prototype;
Chris@909 3032
Chris@909 3033 element = null;
Chris@909 3034 return proto;
Chris@909 3035 }
Chris@909 3036
Chris@909 3037 var elementPrototype = window.HTMLElement ? HTMLElement.prototype :
Chris@909 3038 Element.prototype;
Chris@909 3039
Chris@909 3040 if (F.ElementExtensions) {
Chris@909 3041 copy(Element.Methods, elementPrototype);
Chris@909 3042 copy(Element.Methods.Simulated, elementPrototype, true);
Chris@909 3043 }
Chris@909 3044
Chris@909 3045 if (F.SpecificElementExtensions) {
Chris@909 3046 for (var tag in Element.Methods.ByTag) {
Chris@909 3047 var klass = findDOMClass(tag);
Chris@909 3048 if (Object.isUndefined(klass)) continue;
Chris@909 3049 copy(T[tag], klass.prototype);
Chris@909 3050 }
Chris@909 3051 }
Chris@909 3052
Chris@909 3053 Object.extend(Element, Element.Methods);
Chris@909 3054 delete Element.ByTag;
Chris@909 3055
Chris@909 3056 if (Element.extend.refresh) Element.extend.refresh();
Chris@909 3057 Element.cache = { };
Chris@909 3058 };
Chris@909 3059
Chris@909 3060
Chris@909 3061 document.viewport = {
Chris@909 3062
Chris@909 3063 getDimensions: function() {
Chris@909 3064 return { width: this.getWidth(), height: this.getHeight() };
Chris@909 3065 },
Chris@909 3066
Chris@909 3067 getScrollOffsets: function() {
Chris@909 3068 return Element._returnOffset(
Chris@909 3069 window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
Chris@909 3070 window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
Chris@909 3071 }
Chris@909 3072 };
Chris@909 3073
Chris@909 3074 (function(viewport) {
Chris@909 3075 var B = Prototype.Browser, doc = document, element, property = {};
Chris@909 3076
Chris@909 3077 function getRootElement() {
Chris@909 3078 if (B.WebKit && !doc.evaluate)
Chris@909 3079 return document;
Chris@909 3080
Chris@909 3081 if (B.Opera && window.parseFloat(window.opera.version()) < 9.5)
Chris@909 3082 return document.body;
Chris@909 3083
Chris@909 3084 return document.documentElement;
Chris@909 3085 }
Chris@909 3086
Chris@909 3087 function define(D) {
Chris@909 3088 if (!element) element = getRootElement();
Chris@909 3089
Chris@909 3090 property[D] = 'client' + D;
Chris@909 3091
Chris@909 3092 viewport['get' + D] = function() { return element[property[D]] };
Chris@909 3093 return viewport['get' + D]();
Chris@909 3094 }
Chris@909 3095
Chris@909 3096 viewport.getWidth = define.curry('Width');
Chris@909 3097
Chris@909 3098 viewport.getHeight = define.curry('Height');
Chris@909 3099 })(document.viewport);
Chris@909 3100
Chris@909 3101
Chris@909 3102 Element.Storage = {
Chris@909 3103 UID: 1
Chris@909 3104 };
Chris@909 3105
Chris@909 3106 Element.addMethods({
Chris@909 3107 getStorage: function(element) {
Chris@909 3108 if (!(element = $(element))) return;
Chris@909 3109
Chris@909 3110 var uid;
Chris@909 3111 if (element === window) {
Chris@909 3112 uid = 0;
Chris@909 3113 } else {
Chris@909 3114 if (typeof element._prototypeUID === "undefined")
Chris@909 3115 element._prototypeUID = Element.Storage.UID++;
Chris@909 3116 uid = element._prototypeUID;
Chris@909 3117 }
Chris@909 3118
Chris@909 3119 if (!Element.Storage[uid])
Chris@909 3120 Element.Storage[uid] = $H();
Chris@909 3121
Chris@909 3122 return Element.Storage[uid];
Chris@909 3123 },
Chris@909 3124
Chris@909 3125 store: function(element, key, value) {
Chris@909 3126 if (!(element = $(element))) return;
Chris@909 3127
Chris@909 3128 if (arguments.length === 2) {
Chris@909 3129 Element.getStorage(element).update(key);
Chris@909 3130 } else {
Chris@909 3131 Element.getStorage(element).set(key, value);
Chris@909 3132 }
Chris@909 3133
Chris@909 3134 return element;
Chris@909 3135 },
Chris@909 3136
Chris@909 3137 retrieve: function(element, key, defaultValue) {
Chris@909 3138 if (!(element = $(element))) return;
Chris@909 3139 var hash = Element.getStorage(element), value = hash.get(key);
Chris@909 3140
Chris@909 3141 if (Object.isUndefined(value)) {
Chris@909 3142 hash.set(key, defaultValue);
Chris@909 3143 value = defaultValue;
Chris@909 3144 }
Chris@909 3145
Chris@909 3146 return value;
Chris@909 3147 },
Chris@909 3148
Chris@909 3149 clone: function(element, deep) {
Chris@909 3150 if (!(element = $(element))) return;
Chris@909 3151 var clone = element.cloneNode(deep);
Chris@909 3152 clone._prototypeUID = void 0;
Chris@909 3153 if (deep) {
Chris@909 3154 var descendants = Element.select(clone, '*'),
Chris@909 3155 i = descendants.length;
Chris@909 3156 while (i--) {
Chris@909 3157 descendants[i]._prototypeUID = void 0;
Chris@909 3158 }
Chris@909 3159 }
Chris@909 3160 return Element.extend(clone);
Chris@909 3161 },
Chris@909 3162
Chris@909 3163 purge: function(element) {
Chris@909 3164 if (!(element = $(element))) return;
Chris@909 3165 var purgeElement = Element._purgeElement;
Chris@909 3166
Chris@909 3167 purgeElement(element);
Chris@909 3168
Chris@909 3169 var descendants = element.getElementsByTagName('*'),
Chris@909 3170 i = descendants.length;
Chris@909 3171
Chris@909 3172 while (i--) purgeElement(descendants[i]);
Chris@909 3173
Chris@909 3174 return null;
Chris@909 3175 }
Chris@909 3176 });
Chris@909 3177
Chris@909 3178 (function() {
Chris@909 3179
Chris@909 3180 function toDecimal(pctString) {
Chris@909 3181 var match = pctString.match(/^(\d+)%?$/i);
Chris@909 3182 if (!match) return null;
Chris@909 3183 return (Number(match[1]) / 100);
Chris@909 3184 }
Chris@909 3185
Chris@909 3186 function getPixelValue(value, property, context) {
Chris@909 3187 var element = null;
Chris@909 3188 if (Object.isElement(value)) {
Chris@909 3189 element = value;
Chris@909 3190 value = element.getStyle(property);
Chris@909 3191 }
Chris@909 3192
Chris@909 3193 if (value === null) {
Chris@909 3194 return null;
Chris@909 3195 }
Chris@909 3196
Chris@909 3197 if ((/^(?:-)?\d+(\.\d+)?(px)?$/i).test(value)) {
Chris@909 3198 return window.parseFloat(value);
Chris@909 3199 }
Chris@909 3200
Chris@909 3201 var isPercentage = value.include('%'), isViewport = (context === document.viewport);
Chris@909 3202
Chris@909 3203 if (/\d/.test(value) && element && element.runtimeStyle && !(isPercentage && isViewport)) {
Chris@909 3204 var style = element.style.left, rStyle = element.runtimeStyle.left;
Chris@909 3205 element.runtimeStyle.left = element.currentStyle.left;
Chris@909 3206 element.style.left = value || 0;
Chris@909 3207 value = element.style.pixelLeft;
Chris@909 3208 element.style.left = style;
Chris@909 3209 element.runtimeStyle.left = rStyle;
Chris@909 3210
Chris@909 3211 return value;
Chris@909 3212 }
Chris@909 3213
Chris@909 3214 if (element && isPercentage) {
Chris@909 3215 context = context || element.parentNode;
Chris@909 3216 var decimal = toDecimal(value);
Chris@909 3217 var whole = null;
Chris@909 3218 var position = element.getStyle('position');
Chris@909 3219
Chris@909 3220 var isHorizontal = property.include('left') || property.include('right') ||
Chris@909 3221 property.include('width');
Chris@909 3222
Chris@909 3223 var isVertical = property.include('top') || property.include('bottom') ||
Chris@909 3224 property.include('height');
Chris@909 3225
Chris@909 3226 if (context === document.viewport) {
Chris@909 3227 if (isHorizontal) {
Chris@909 3228 whole = document.viewport.getWidth();
Chris@909 3229 } else if (isVertical) {
Chris@909 3230 whole = document.viewport.getHeight();
Chris@909 3231 }
Chris@909 3232 } else {
Chris@909 3233 if (isHorizontal) {
Chris@909 3234 whole = $(context).measure('width');
Chris@909 3235 } else if (isVertical) {
Chris@909 3236 whole = $(context).measure('height');
Chris@909 3237 }
Chris@909 3238 }
Chris@909 3239
Chris@909 3240 return (whole === null) ? 0 : whole * decimal;
Chris@909 3241 }
Chris@909 3242
Chris@909 3243 return 0;
Chris@909 3244 }
Chris@909 3245
Chris@909 3246 function toCSSPixels(number) {
Chris@909 3247 if (Object.isString(number) && number.endsWith('px')) {
Chris@909 3248 return number;
Chris@909 3249 }
Chris@909 3250 return number + 'px';
Chris@909 3251 }
Chris@909 3252
Chris@909 3253 function isDisplayed(element) {
Chris@909 3254 var originalElement = element;
Chris@909 3255 while (element && element.parentNode) {
Chris@909 3256 var display = element.getStyle('display');
Chris@909 3257 if (display === 'none') {
Chris@909 3258 return false;
Chris@909 3259 }
Chris@909 3260 element = $(element.parentNode);
Chris@909 3261 }
Chris@909 3262 return true;
Chris@909 3263 }
Chris@909 3264
Chris@909 3265 var hasLayout = Prototype.K;
Chris@909 3266 if ('currentStyle' in document.documentElement) {
Chris@909 3267 hasLayout = function(element) {
Chris@909 3268 if (!element.currentStyle.hasLayout) {
Chris@909 3269 element.style.zoom = 1;
Chris@909 3270 }
Chris@909 3271 return element;
Chris@909 3272 };
Chris@909 3273 }
Chris@909 3274
Chris@909 3275 function cssNameFor(key) {
Chris@909 3276 if (key.include('border')) key = key + '-width';
Chris@909 3277 return key.camelize();
Chris@909 3278 }
Chris@909 3279
Chris@909 3280 Element.Layout = Class.create(Hash, {
Chris@909 3281 initialize: function($super, element, preCompute) {
Chris@909 3282 $super();
Chris@909 3283 this.element = $(element);
Chris@909 3284
Chris@909 3285 Element.Layout.PROPERTIES.each( function(property) {
Chris@909 3286 this._set(property, null);
Chris@909 3287 }, this);
Chris@909 3288
Chris@909 3289 if (preCompute) {
Chris@909 3290 this._preComputing = true;
Chris@909 3291 this._begin();
Chris@909 3292 Element.Layout.PROPERTIES.each( this._compute, this );
Chris@909 3293 this._end();
Chris@909 3294 this._preComputing = false;
Chris@909 3295 }
Chris@909 3296 },
Chris@909 3297
Chris@909 3298 _set: function(property, value) {
Chris@909 3299 return Hash.prototype.set.call(this, property, value);
Chris@909 3300 },
Chris@909 3301
Chris@909 3302 set: function(property, value) {
Chris@909 3303 throw "Properties of Element.Layout are read-only.";
Chris@909 3304 },
Chris@909 3305
Chris@909 3306 get: function($super, property) {
Chris@909 3307 var value = $super(property);
Chris@909 3308 return value === null ? this._compute(property) : value;
Chris@909 3309 },
Chris@909 3310
Chris@909 3311 _begin: function() {
Chris@909 3312 if (this._prepared) return;
Chris@909 3313
Chris@909 3314 var element = this.element;
Chris@909 3315 if (isDisplayed(element)) {
Chris@909 3316 this._prepared = true;
Chris@909 3317 return;
Chris@909 3318 }
Chris@909 3319
Chris@909 3320 var originalStyles = {
Chris@909 3321 position: element.style.position || '',
Chris@909 3322 width: element.style.width || '',
Chris@909 3323 visibility: element.style.visibility || '',
Chris@909 3324 display: element.style.display || ''
Chris@909 3325 };
Chris@909 3326
Chris@909 3327 element.store('prototype_original_styles', originalStyles);
Chris@909 3328
Chris@909 3329 var position = element.getStyle('position'),
Chris@909 3330 width = element.getStyle('width');
Chris@909 3331
Chris@909 3332 if (width === "0px" || width === null) {
Chris@909 3333 element.style.display = 'block';
Chris@909 3334 width = element.getStyle('width');
Chris@909 3335 }
Chris@909 3336
Chris@909 3337 var context = (position === 'fixed') ? document.viewport :
Chris@909 3338 element.parentNode;
Chris@909 3339
Chris@909 3340 element.setStyle({
Chris@909 3341 position: 'absolute',
Chris@909 3342 visibility: 'hidden',
Chris@909 3343 display: 'block'
Chris@909 3344 });
Chris@909 3345
Chris@909 3346 var positionedWidth = element.getStyle('width');
Chris@909 3347
Chris@909 3348 var newWidth;
Chris@909 3349 if (width && (positionedWidth === width)) {
Chris@909 3350 newWidth = getPixelValue(element, 'width', context);
Chris@909 3351 } else if (position === 'absolute' || position === 'fixed') {
Chris@909 3352 newWidth = getPixelValue(element, 'width', context);
Chris@909 3353 } else {
Chris@909 3354 var parent = element.parentNode, pLayout = $(parent).getLayout();
Chris@909 3355
Chris@909 3356 newWidth = pLayout.get('width') -
Chris@909 3357 this.get('margin-left') -
Chris@909 3358 this.get('border-left') -
Chris@909 3359 this.get('padding-left') -
Chris@909 3360 this.get('padding-right') -
Chris@909 3361 this.get('border-right') -
Chris@909 3362 this.get('margin-right');
Chris@909 3363 }
Chris@909 3364
Chris@909 3365 element.setStyle({ width: newWidth + 'px' });
Chris@909 3366
Chris@909 3367 this._prepared = true;
Chris@909 3368 },
Chris@909 3369
Chris@909 3370 _end: function() {
Chris@909 3371 var element = this.element;
Chris@909 3372 var originalStyles = element.retrieve('prototype_original_styles');
Chris@909 3373 element.store('prototype_original_styles', null);
Chris@909 3374 element.setStyle(originalStyles);
Chris@909 3375 this._prepared = false;
Chris@909 3376 },
Chris@909 3377
Chris@909 3378 _compute: function(property) {
Chris@909 3379 var COMPUTATIONS = Element.Layout.COMPUTATIONS;
Chris@909 3380 if (!(property in COMPUTATIONS)) {
Chris@909 3381 throw "Property not found.";
Chris@909 3382 }
Chris@909 3383
Chris@909 3384 return this._set(property, COMPUTATIONS[property].call(this, this.element));
Chris@909 3385 },
Chris@909 3386
Chris@909 3387 toObject: function() {
Chris@909 3388 var args = $A(arguments);
Chris@909 3389 var keys = (args.length === 0) ? Element.Layout.PROPERTIES :
Chris@909 3390 args.join(' ').split(' ');
Chris@909 3391 var obj = {};
Chris@909 3392 keys.each( function(key) {
Chris@909 3393 if (!Element.Layout.PROPERTIES.include(key)) return;
Chris@909 3394 var value = this.get(key);
Chris@909 3395 if (value != null) obj[key] = value;
Chris@909 3396 }, this);
Chris@909 3397 return obj;
Chris@909 3398 },
Chris@909 3399
Chris@909 3400 toHash: function() {
Chris@909 3401 var obj = this.toObject.apply(this, arguments);
Chris@909 3402 return new Hash(obj);
Chris@909 3403 },
Chris@909 3404
Chris@909 3405 toCSS: function() {
Chris@909 3406 var args = $A(arguments);
Chris@909 3407 var keys = (args.length === 0) ? Element.Layout.PROPERTIES :
Chris@909 3408 args.join(' ').split(' ');
Chris@909 3409 var css = {};
Chris@909 3410
Chris@909 3411 keys.each( function(key) {
Chris@909 3412 if (!Element.Layout.PROPERTIES.include(key)) return;
Chris@909 3413 if (Element.Layout.COMPOSITE_PROPERTIES.include(key)) return;
Chris@909 3414
Chris@909 3415 var value = this.get(key);
Chris@909 3416 if (value != null) css[cssNameFor(key)] = value + 'px';
Chris@909 3417 }, this);
Chris@909 3418 return css;
Chris@909 3419 },
Chris@909 3420
Chris@909 3421 inspect: function() {
Chris@909 3422 return "#<Element.Layout>";
Chris@909 3423 }
Chris@909 3424 });
Chris@909 3425
Chris@909 3426 Object.extend(Element.Layout, {
Chris@909 3427 PROPERTIES: $w('height width top left right bottom border-left border-right border-top border-bottom padding-left padding-right padding-top padding-bottom margin-top margin-bottom margin-left margin-right padding-box-width padding-box-height border-box-width border-box-height margin-box-width margin-box-height'),
Chris@909 3428
Chris@909 3429 COMPOSITE_PROPERTIES: $w('padding-box-width padding-box-height margin-box-width margin-box-height border-box-width border-box-height'),
Chris@909 3430
Chris@909 3431 COMPUTATIONS: {
Chris@909 3432 'height': function(element) {
Chris@909 3433 if (!this._preComputing) this._begin();
Chris@909 3434
Chris@909 3435 var bHeight = this.get('border-box-height');
Chris@909 3436 if (bHeight <= 0) {
Chris@909 3437 if (!this._preComputing) this._end();
Chris@909 3438 return 0;
Chris@909 3439 }
Chris@909 3440
Chris@909 3441 var bTop = this.get('border-top'),
Chris@909 3442 bBottom = this.get('border-bottom');
Chris@909 3443
Chris@909 3444 var pTop = this.get('padding-top'),
Chris@909 3445 pBottom = this.get('padding-bottom');
Chris@909 3446
Chris@909 3447 if (!this._preComputing) this._end();
Chris@909 3448
Chris@909 3449 return bHeight - bTop - bBottom - pTop - pBottom;
Chris@909 3450 },
Chris@909 3451
Chris@909 3452 'width': function(element) {
Chris@909 3453 if (!this._preComputing) this._begin();
Chris@909 3454
Chris@909 3455 var bWidth = this.get('border-box-width');
Chris@909 3456 if (bWidth <= 0) {
Chris@909 3457 if (!this._preComputing) this._end();
Chris@909 3458 return 0;
Chris@909 3459 }
Chris@909 3460
Chris@909 3461 var bLeft = this.get('border-left'),
Chris@909 3462 bRight = this.get('border-right');
Chris@909 3463
Chris@909 3464 var pLeft = this.get('padding-left'),
Chris@909 3465 pRight = this.get('padding-right');
Chris@909 3466
Chris@909 3467 if (!this._preComputing) this._end();
Chris@909 3468
Chris@909 3469 return bWidth - bLeft - bRight - pLeft - pRight;
Chris@909 3470 },
Chris@909 3471
Chris@909 3472 'padding-box-height': function(element) {
Chris@909 3473 var height = this.get('height'),
Chris@909 3474 pTop = this.get('padding-top'),
Chris@909 3475 pBottom = this.get('padding-bottom');
Chris@909 3476
Chris@909 3477 return height + pTop + pBottom;
Chris@909 3478 },
Chris@909 3479
Chris@909 3480 'padding-box-width': function(element) {
Chris@909 3481 var width = this.get('width'),
Chris@909 3482 pLeft = this.get('padding-left'),
Chris@909 3483 pRight = this.get('padding-right');
Chris@909 3484
Chris@909 3485 return width + pLeft + pRight;
Chris@909 3486 },
Chris@909 3487
Chris@909 3488 'border-box-height': function(element) {
Chris@909 3489 if (!this._preComputing) this._begin();
Chris@909 3490 var height = element.offsetHeight;
Chris@909 3491 if (!this._preComputing) this._end();
Chris@909 3492 return height;
Chris@909 3493 },
Chris@909 3494
Chris@909 3495 'border-box-width': function(element) {
Chris@909 3496 if (!this._preComputing) this._begin();
Chris@909 3497 var width = element.offsetWidth;
Chris@909 3498 if (!this._preComputing) this._end();
Chris@909 3499 return width;
Chris@909 3500 },
Chris@909 3501
Chris@909 3502 'margin-box-height': function(element) {
Chris@909 3503 var bHeight = this.get('border-box-height'),
Chris@909 3504 mTop = this.get('margin-top'),
Chris@909 3505 mBottom = this.get('margin-bottom');
Chris@909 3506
Chris@909 3507 if (bHeight <= 0) return 0;
Chris@909 3508
Chris@909 3509 return bHeight + mTop + mBottom;
Chris@909 3510 },
Chris@909 3511
Chris@909 3512 'margin-box-width': function(element) {
Chris@909 3513 var bWidth = this.get('border-box-width'),
Chris@909 3514 mLeft = this.get('margin-left'),
Chris@909 3515 mRight = this.get('margin-right');
Chris@909 3516
Chris@909 3517 if (bWidth <= 0) return 0;
Chris@909 3518
Chris@909 3519 return bWidth + mLeft + mRight;
Chris@909 3520 },
Chris@909 3521
Chris@909 3522 'top': function(element) {
Chris@909 3523 var offset = element.positionedOffset();
Chris@909 3524 return offset.top;
Chris@909 3525 },
Chris@909 3526
Chris@909 3527 'bottom': function(element) {
Chris@909 3528 var offset = element.positionedOffset(),
Chris@909 3529 parent = element.getOffsetParent(),
Chris@909 3530 pHeight = parent.measure('height');
Chris@909 3531
Chris@909 3532 var mHeight = this.get('border-box-height');
Chris@909 3533
Chris@909 3534 return pHeight - mHeight - offset.top;
Chris@909 3535 },
Chris@909 3536
Chris@909 3537 'left': function(element) {
Chris@909 3538 var offset = element.positionedOffset();
Chris@909 3539 return offset.left;
Chris@909 3540 },
Chris@909 3541
Chris@909 3542 'right': function(element) {
Chris@909 3543 var offset = element.positionedOffset(),
Chris@909 3544 parent = element.getOffsetParent(),
Chris@909 3545 pWidth = parent.measure('width');
Chris@909 3546
Chris@909 3547 var mWidth = this.get('border-box-width');
Chris@909 3548
Chris@909 3549 return pWidth - mWidth - offset.left;
Chris@909 3550 },
Chris@909 3551
Chris@909 3552 'padding-top': function(element) {
Chris@909 3553 return getPixelValue(element, 'paddingTop');
Chris@909 3554 },
Chris@909 3555
Chris@909 3556 'padding-bottom': function(element) {
Chris@909 3557 return getPixelValue(element, 'paddingBottom');
Chris@909 3558 },
Chris@909 3559
Chris@909 3560 'padding-left': function(element) {
Chris@909 3561 return getPixelValue(element, 'paddingLeft');
Chris@909 3562 },
Chris@909 3563
Chris@909 3564 'padding-right': function(element) {
Chris@909 3565 return getPixelValue(element, 'paddingRight');
Chris@909 3566 },
Chris@909 3567
Chris@909 3568 'border-top': function(element) {
Chris@909 3569 return getPixelValue(element, 'borderTopWidth');
Chris@909 3570 },
Chris@909 3571
Chris@909 3572 'border-bottom': function(element) {
Chris@909 3573 return getPixelValue(element, 'borderBottomWidth');
Chris@909 3574 },
Chris@909 3575
Chris@909 3576 'border-left': function(element) {
Chris@909 3577 return getPixelValue(element, 'borderLeftWidth');
Chris@909 3578 },
Chris@909 3579
Chris@909 3580 'border-right': function(element) {
Chris@909 3581 return getPixelValue(element, 'borderRightWidth');
Chris@909 3582 },
Chris@909 3583
Chris@909 3584 'margin-top': function(element) {
Chris@909 3585 return getPixelValue(element, 'marginTop');
Chris@909 3586 },
Chris@909 3587
Chris@909 3588 'margin-bottom': function(element) {
Chris@909 3589 return getPixelValue(element, 'marginBottom');
Chris@909 3590 },
Chris@909 3591
Chris@909 3592 'margin-left': function(element) {
Chris@909 3593 return getPixelValue(element, 'marginLeft');
Chris@909 3594 },
Chris@909 3595
Chris@909 3596 'margin-right': function(element) {
Chris@909 3597 return getPixelValue(element, 'marginRight');
Chris@909 3598 }
Chris@909 3599 }
Chris@909 3600 });
Chris@909 3601
Chris@909 3602 if ('getBoundingClientRect' in document.documentElement) {
Chris@909 3603 Object.extend(Element.Layout.COMPUTATIONS, {
Chris@909 3604 'right': function(element) {
Chris@909 3605 var parent = hasLayout(element.getOffsetParent());
Chris@909 3606 var rect = element.getBoundingClientRect(),
Chris@909 3607 pRect = parent.getBoundingClientRect();
Chris@909 3608
Chris@909 3609 return (pRect.right - rect.right).round();
Chris@909 3610 },
Chris@909 3611
Chris@909 3612 'bottom': function(element) {
Chris@909 3613 var parent = hasLayout(element.getOffsetParent());
Chris@909 3614 var rect = element.getBoundingClientRect(),
Chris@909 3615 pRect = parent.getBoundingClientRect();
Chris@909 3616
Chris@909 3617 return (pRect.bottom - rect.bottom).round();
Chris@909 3618 }
Chris@909 3619 });
Chris@909 3620 }
Chris@909 3621
Chris@909 3622 Element.Offset = Class.create({
Chris@909 3623 initialize: function(left, top) {
Chris@909 3624 this.left = left.round();
Chris@909 3625 this.top = top.round();
Chris@909 3626
Chris@909 3627 this[0] = this.left;
Chris@909 3628 this[1] = this.top;
Chris@909 3629 },
Chris@909 3630
Chris@909 3631 relativeTo: function(offset) {
Chris@909 3632 return new Element.Offset(
Chris@909 3633 this.left - offset.left,
Chris@909 3634 this.top - offset.top
Chris@909 3635 );
Chris@909 3636 },
Chris@909 3637
Chris@909 3638 inspect: function() {
Chris@909 3639 return "#<Element.Offset left: #{left} top: #{top}>".interpolate(this);
Chris@909 3640 },
Chris@909 3641
Chris@909 3642 toString: function() {
Chris@909 3643 return "[#{left}, #{top}]".interpolate(this);
Chris@909 3644 },
Chris@909 3645
Chris@909 3646 toArray: function() {
Chris@909 3647 return [this.left, this.top];
Chris@909 3648 }
Chris@909 3649 });
Chris@909 3650
Chris@909 3651 function getLayout(element, preCompute) {
Chris@909 3652 return new Element.Layout(element, preCompute);
Chris@909 3653 }
Chris@909 3654
Chris@909 3655 function measure(element, property) {
Chris@909 3656 return $(element).getLayout().get(property);
Chris@909 3657 }
Chris@909 3658
Chris@909 3659 function getDimensions(element) {
Chris@909 3660 element = $(element);
Chris@909 3661 var display = Element.getStyle(element, 'display');
Chris@909 3662
Chris@909 3663 if (display && display !== 'none') {
Chris@909 3664 return { width: element.offsetWidth, height: element.offsetHeight };
Chris@909 3665 }
Chris@909 3666
Chris@909 3667 var style = element.style;
Chris@909 3668 var originalStyles = {
Chris@909 3669 visibility: style.visibility,
Chris@909 3670 position: style.position,
Chris@909 3671 display: style.display
Chris@909 3672 };
Chris@909 3673
Chris@909 3674 var newStyles = {
Chris@909 3675 visibility: 'hidden',
Chris@909 3676 display: 'block'
Chris@909 3677 };
Chris@909 3678
Chris@909 3679 if (originalStyles.position !== 'fixed')
Chris@909 3680 newStyles.position = 'absolute';
Chris@909 3681
Chris@909 3682 Element.setStyle(element, newStyles);
Chris@909 3683
Chris@909 3684 var dimensions = {
Chris@909 3685 width: element.offsetWidth,
Chris@909 3686 height: element.offsetHeight
Chris@909 3687 };
Chris@909 3688
Chris@909 3689 Element.setStyle(element, originalStyles);
Chris@909 3690
Chris@909 3691 return dimensions;
Chris@909 3692 }
Chris@909 3693
Chris@909 3694 function getOffsetParent(element) {
Chris@909 3695 element = $(element);
Chris@909 3696
Chris@909 3697 if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element))
Chris@909 3698 return $(document.body);
Chris@909 3699
Chris@909 3700 var isInline = (Element.getStyle(element, 'display') === 'inline');
Chris@909 3701 if (!isInline && element.offsetParent) return $(element.offsetParent);
Chris@909 3702
Chris@909 3703 while ((element = element.parentNode) && element !== document.body) {
Chris@909 3704 if (Element.getStyle(element, 'position') !== 'static') {
Chris@909 3705 return isHtml(element) ? $(document.body) : $(element);
Chris@909 3706 }
Chris@909 3707 }
Chris@909 3708
Chris@909 3709 return $(document.body);
Chris@909 3710 }
Chris@909 3711
Chris@909 3712
Chris@909 3713 function cumulativeOffset(element) {
Chris@909 3714 element = $(element);
Chris@909 3715 var valueT = 0, valueL = 0;
Chris@909 3716 if (element.parentNode) {
Chris@909 3717 do {
Chris@909 3718 valueT += element.offsetTop || 0;
Chris@909 3719 valueL += element.offsetLeft || 0;
Chris@909 3720 element = element.offsetParent;
Chris@909 3721 } while (element);
Chris@909 3722 }
Chris@909 3723 return new Element.Offset(valueL, valueT);
Chris@909 3724 }
Chris@909 3725
Chris@909 3726 function positionedOffset(element) {
Chris@909 3727 element = $(element);
Chris@909 3728
Chris@909 3729 var layout = element.getLayout();
Chris@909 3730
Chris@909 3731 var valueT = 0, valueL = 0;
Chris@909 3732 do {
Chris@909 3733 valueT += element.offsetTop || 0;
Chris@909 3734 valueL += element.offsetLeft || 0;
Chris@909 3735 element = element.offsetParent;
Chris@909 3736 if (element) {
Chris@909 3737 if (isBody(element)) break;
Chris@909 3738 var p = Element.getStyle(element, 'position');
Chris@909 3739 if (p !== 'static') break;
Chris@909 3740 }
Chris@909 3741 } while (element);
Chris@909 3742
Chris@909 3743 valueL -= layout.get('margin-top');
Chris@909 3744 valueT -= layout.get('margin-left');
Chris@909 3745
Chris@909 3746 return new Element.Offset(valueL, valueT);
Chris@909 3747 }
Chris@909 3748
Chris@909 3749 function cumulativeScrollOffset(element) {
Chris@909 3750 var valueT = 0, valueL = 0;
Chris@909 3751 do {
Chris@909 3752 valueT += element.scrollTop || 0;
Chris@909 3753 valueL += element.scrollLeft || 0;
Chris@909 3754 element = element.parentNode;
Chris@909 3755 } while (element);
Chris@909 3756 return new Element.Offset(valueL, valueT);
Chris@909 3757 }
Chris@909 3758
Chris@909 3759 function viewportOffset(forElement) {
Chris@909 3760 element = $(element);
Chris@909 3761 var valueT = 0, valueL = 0, docBody = document.body;
Chris@909 3762
Chris@909 3763 var element = forElement;
Chris@909 3764 do {
Chris@909 3765 valueT += element.offsetTop || 0;
Chris@909 3766 valueL += element.offsetLeft || 0;
Chris@909 3767 if (element.offsetParent == docBody &&
Chris@909 3768 Element.getStyle(element, 'position') == 'absolute') break;
Chris@909 3769 } while (element = element.offsetParent);
Chris@909 3770
Chris@909 3771 element = forElement;
Chris@909 3772 do {
Chris@909 3773 if (element != docBody) {
Chris@909 3774 valueT -= element.scrollTop || 0;
Chris@909 3775 valueL -= element.scrollLeft || 0;
Chris@909 3776 }
Chris@909 3777 } while (element = element.parentNode);
Chris@909 3778 return new Element.Offset(valueL, valueT);
Chris@909 3779 }
Chris@909 3780
Chris@909 3781 function absolutize(element) {
Chris@909 3782 element = $(element);
Chris@909 3783
Chris@909 3784 if (Element.getStyle(element, 'position') === 'absolute') {
Chris@909 3785 return element;
Chris@909 3786 }
Chris@909 3787
Chris@909 3788 var offsetParent = getOffsetParent(element);
Chris@909 3789 var eOffset = element.viewportOffset(),
Chris@909 3790 pOffset = offsetParent.viewportOffset();
Chris@909 3791
Chris@909 3792 var offset = eOffset.relativeTo(pOffset);
Chris@909 3793 var layout = element.getLayout();
Chris@909 3794
Chris@909 3795 element.store('prototype_absolutize_original_styles', {
Chris@909 3796 left: element.getStyle('left'),
Chris@909 3797 top: element.getStyle('top'),
Chris@909 3798 width: element.getStyle('width'),
Chris@909 3799 height: element.getStyle('height')
Chris@909 3800 });
Chris@909 3801
Chris@909 3802 element.setStyle({
Chris@909 3803 position: 'absolute',
Chris@909 3804 top: offset.top + 'px',
Chris@909 3805 left: offset.left + 'px',
Chris@909 3806 width: layout.get('width') + 'px',
Chris@909 3807 height: layout.get('height') + 'px'
Chris@909 3808 });
Chris@909 3809
Chris@909 3810 return element;
Chris@909 3811 }
Chris@909 3812
Chris@909 3813 function relativize(element) {
Chris@909 3814 element = $(element);
Chris@909 3815 if (Element.getStyle(element, 'position') === 'relative') {
Chris@909 3816 return element;
Chris@909 3817 }
Chris@909 3818
Chris@909 3819 var originalStyles =
Chris@909 3820 element.retrieve('prototype_absolutize_original_styles');
Chris@909 3821
Chris@909 3822 if (originalStyles) element.setStyle(originalStyles);
Chris@909 3823 return element;
Chris@909 3824 }
Chris@909 3825
Chris@909 3826 if (Prototype.Browser.IE) {
Chris@909 3827 getOffsetParent = getOffsetParent.wrap(
Chris@909 3828 function(proceed, element) {
Chris@909 3829 element = $(element);
Chris@909 3830
Chris@909 3831 if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element))
Chris@909 3832 return $(document.body);
Chris@909 3833
Chris@909 3834 var position = element.getStyle('position');
Chris@909 3835 if (position !== 'static') return proceed(element);
Chris@909 3836
Chris@909 3837 element.setStyle({ position: 'relative' });
Chris@909 3838 var value = proceed(element);
Chris@909 3839 element.setStyle({ position: position });
Chris@909 3840 return value;
Chris@909 3841 }
Chris@909 3842 );
Chris@909 3843
Chris@909 3844 positionedOffset = positionedOffset.wrap(function(proceed, element) {
Chris@909 3845 element = $(element);
Chris@909 3846 if (!element.parentNode) return new Element.Offset(0, 0);
Chris@909 3847 var position = element.getStyle('position');
Chris@909 3848 if (position !== 'static') return proceed(element);
Chris@909 3849
Chris@909 3850 var offsetParent = element.getOffsetParent();
Chris@909 3851 if (offsetParent && offsetParent.getStyle('position') === 'fixed')
Chris@909 3852 hasLayout(offsetParent);
Chris@909 3853
Chris@909 3854 element.setStyle({ position: 'relative' });
Chris@909 3855 var value = proceed(element);
Chris@909 3856 element.setStyle({ position: position });
Chris@909 3857 return value;
Chris@909 3858 });
Chris@909 3859 } else if (Prototype.Browser.Webkit) {
Chris@909 3860 cumulativeOffset = function(element) {
Chris@909 3861 element = $(element);
Chris@909 3862 var valueT = 0, valueL = 0;
Chris@909 3863 do {
Chris@909 3864 valueT += element.offsetTop || 0;
Chris@909 3865 valueL += element.offsetLeft || 0;
Chris@909 3866 if (element.offsetParent == document.body)
Chris@909 3867 if (Element.getStyle(element, 'position') == 'absolute') break;
Chris@909 3868
Chris@909 3869 element = element.offsetParent;
Chris@909 3870 } while (element);
Chris@909 3871
Chris@909 3872 return new Element.Offset(valueL, valueT);
Chris@909 3873 };
Chris@909 3874 }
Chris@909 3875
Chris@909 3876
Chris@909 3877 Element.addMethods({
Chris@909 3878 getLayout: getLayout,
Chris@909 3879 measure: measure,
Chris@909 3880 getDimensions: getDimensions,
Chris@909 3881 getOffsetParent: getOffsetParent,
Chris@909 3882 cumulativeOffset: cumulativeOffset,
Chris@909 3883 positionedOffset: positionedOffset,
Chris@909 3884 cumulativeScrollOffset: cumulativeScrollOffset,
Chris@909 3885 viewportOffset: viewportOffset,
Chris@909 3886 absolutize: absolutize,
Chris@909 3887 relativize: relativize
Chris@909 3888 });
Chris@909 3889
Chris@909 3890 function isBody(element) {
Chris@909 3891 return element.nodeName.toUpperCase() === 'BODY';
Chris@909 3892 }
Chris@909 3893
Chris@909 3894 function isHtml(element) {
Chris@909 3895 return element.nodeName.toUpperCase() === 'HTML';
Chris@909 3896 }
Chris@909 3897
Chris@909 3898 function isDocument(element) {
Chris@909 3899 return element.nodeType === Node.DOCUMENT_NODE;
Chris@909 3900 }
Chris@909 3901
Chris@909 3902 function isDetached(element) {
Chris@909 3903 return element !== document.body &&
Chris@909 3904 !Element.descendantOf(element, document.body);
Chris@909 3905 }
Chris@909 3906
Chris@909 3907 if ('getBoundingClientRect' in document.documentElement) {
Chris@909 3908 Element.addMethods({
Chris@909 3909 viewportOffset: function(element) {
Chris@909 3910 element = $(element);
Chris@909 3911 if (isDetached(element)) return new Element.Offset(0, 0);
Chris@909 3912
Chris@909 3913 var rect = element.getBoundingClientRect(),
Chris@909 3914 docEl = document.documentElement;
Chris@909 3915 return new Element.Offset(rect.left - docEl.clientLeft,
Chris@909 3916 rect.top - docEl.clientTop);
Chris@909 3917 }
Chris@909 3918 });
Chris@909 3919 }
Chris@909 3920 })();
Chris@909 3921 window.$$ = function() {
Chris@909 3922 var expression = $A(arguments).join(', ');
Chris@909 3923 return Prototype.Selector.select(expression, document);
Chris@909 3924 };
Chris@909 3925
Chris@909 3926 Prototype.Selector = (function() {
Chris@909 3927
Chris@909 3928 function select() {
Chris@909 3929 throw new Error('Method "Prototype.Selector.select" must be defined.');
Chris@909 3930 }
Chris@909 3931
Chris@909 3932 function match() {
Chris@909 3933 throw new Error('Method "Prototype.Selector.match" must be defined.');
Chris@909 3934 }
Chris@909 3935
Chris@909 3936 function find(elements, expression, index) {
Chris@909 3937 index = index || 0;
Chris@909 3938 var match = Prototype.Selector.match, length = elements.length, matchIndex = 0, i;
Chris@909 3939
Chris@909 3940 for (i = 0; i < length; i++) {
Chris@909 3941 if (match(elements[i], expression) && index == matchIndex++) {
Chris@909 3942 return Element.extend(elements[i]);
Chris@909 3943 }
Chris@909 3944 }
Chris@909 3945 }
Chris@909 3946
Chris@909 3947 function extendElements(elements) {
Chris@909 3948 for (var i = 0, length = elements.length; i < length; i++) {
Chris@909 3949 Element.extend(elements[i]);
Chris@909 3950 }
Chris@909 3951 return elements;
Chris@909 3952 }
Chris@909 3953
Chris@909 3954
Chris@909 3955 var K = Prototype.K;
Chris@909 3956
Chris@909 3957 return {
Chris@909 3958 select: select,
Chris@909 3959 match: match,
Chris@909 3960 find: find,
Chris@909 3961 extendElements: (Element.extend === K) ? K : extendElements,
Chris@909 3962 extendElement: Element.extend
Chris@909 3963 };
Chris@909 3964 })();
Chris@909 3965 Prototype._original_property = window.Sizzle;
Chris@909 3966 /*!
Chris@909 3967 * Sizzle CSS Selector Engine - v1.0
Chris@909 3968 * Copyright 2009, The Dojo Foundation
Chris@909 3969 * Released under the MIT, BSD, and GPL Licenses.
Chris@909 3970 * More information: http://sizzlejs.com/
Chris@909 3971 */
Chris@909 3972 (function(){
Chris@909 3973
Chris@909 3974 var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
Chris@909 3975 done = 0,
Chris@909 3976 toString = Object.prototype.toString,
Chris@909 3977 hasDuplicate = false,
Chris@909 3978 baseHasDuplicate = true;
Chris@909 3979
Chris@909 3980 [0, 0].sort(function(){
Chris@909 3981 baseHasDuplicate = false;
Chris@909 3982 return 0;
Chris@909 3983 });
Chris@909 3984
Chris@909 3985 var Sizzle = function(selector, context, results, seed) {
Chris@909 3986 results = results || [];
Chris@909 3987 var origContext = context = context || document;
Chris@909 3988
Chris@909 3989 if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
Chris@909 3990 return [];
Chris@909 3991 }
Chris@909 3992
Chris@909 3993 if ( !selector || typeof selector !== "string" ) {
Chris@909 3994 return results;
Chris@909 3995 }
Chris@909 3996
Chris@909 3997 var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context),
Chris@909 3998 soFar = selector;
Chris@909 3999
Chris@909 4000 while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) {
Chris@909 4001 soFar = m[3];
Chris@909 4002
Chris@909 4003 parts.push( m[1] );
Chris@909 4004
Chris@909 4005 if ( m[2] ) {
Chris@909 4006 extra = m[3];
Chris@909 4007 break;
Chris@909 4008 }
Chris@909 4009 }
Chris@909 4010
Chris@909 4011 if ( parts.length > 1 && origPOS.exec( selector ) ) {
Chris@909 4012 if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
Chris@909 4013 set = posProcess( parts[0] + parts[1], context );
Chris@909 4014 } else {
Chris@909 4015 set = Expr.relative[ parts[0] ] ?
Chris@909 4016 [ context ] :
Chris@909 4017 Sizzle( parts.shift(), context );
Chris@909 4018
Chris@909 4019 while ( parts.length ) {
Chris@909 4020 selector = parts.shift();
Chris@909 4021
Chris@909 4022 if ( Expr.relative[ selector ] )
Chris@909 4023 selector += parts.shift();
Chris@909 4024
Chris@909 4025 set = posProcess( selector, set );
Chris@909 4026 }
Chris@909 4027 }
Chris@909 4028 } else {
Chris@909 4029 if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
Chris@909 4030 Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
Chris@909 4031 var ret = Sizzle.find( parts.shift(), context, contextXML );
Chris@909 4032 context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];
Chris@909 4033 }
Chris@909 4034
Chris@909 4035 if ( context ) {
Chris@909 4036 var ret = seed ?
Chris@909 4037 { expr: parts.pop(), set: makeArray(seed) } :
Chris@909 4038 Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
Chris@909 4039 set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set;
Chris@909 4040
Chris@909 4041 if ( parts.length > 0 ) {
Chris@909 4042 checkSet = makeArray(set);
Chris@909 4043 } else {
Chris@909 4044 prune = false;
Chris@909 4045 }
Chris@909 4046
Chris@909 4047 while ( parts.length ) {
Chris@909 4048 var cur = parts.pop(), pop = cur;
Chris@909 4049
Chris@909 4050 if ( !Expr.relative[ cur ] ) {
Chris@909 4051 cur = "";
Chris@909 4052 } else {
Chris@909 4053 pop = parts.pop();
Chris@909 4054 }
Chris@909 4055
Chris@909 4056 if ( pop == null ) {
Chris@909 4057 pop = context;
Chris@909 4058 }
Chris@909 4059
Chris@909 4060 Expr.relative[ cur ]( checkSet, pop, contextXML );
Chris@909 4061 }
Chris@909 4062 } else {
Chris@909 4063 checkSet = parts = [];
Chris@909 4064 }
Chris@909 4065 }
Chris@909 4066
Chris@909 4067 if ( !checkSet ) {
Chris@909 4068 checkSet = set;
Chris@909 4069 }
Chris@909 4070
Chris@909 4071 if ( !checkSet ) {
Chris@909 4072 throw "Syntax error, unrecognized expression: " + (cur || selector);
Chris@909 4073 }
Chris@909 4074
Chris@909 4075 if ( toString.call(checkSet) === "[object Array]" ) {
Chris@909 4076 if ( !prune ) {
Chris@909 4077 results.push.apply( results, checkSet );
Chris@909 4078 } else if ( context && context.nodeType === 1 ) {
Chris@909 4079 for ( var i = 0; checkSet[i] != null; i++ ) {
Chris@909 4080 if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
Chris@909 4081 results.push( set[i] );
Chris@909 4082 }
Chris@909 4083 }
Chris@909 4084 } else {
Chris@909 4085 for ( var i = 0; checkSet[i] != null; i++ ) {
Chris@909 4086 if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
Chris@909 4087 results.push( set[i] );
Chris@909 4088 }
Chris@909 4089 }
Chris@909 4090 }
Chris@909 4091 } else {
Chris@909 4092 makeArray( checkSet, results );
Chris@909 4093 }
Chris@909 4094
Chris@909 4095 if ( extra ) {
Chris@909 4096 Sizzle( extra, origContext, results, seed );
Chris@909 4097 Sizzle.uniqueSort( results );
Chris@909 4098 }
Chris@909 4099
Chris@909 4100 return results;
Chris@909 4101 };
Chris@909 4102
Chris@909 4103 Sizzle.uniqueSort = function(results){
Chris@909 4104 if ( sortOrder ) {
Chris@909 4105 hasDuplicate = baseHasDuplicate;
Chris@909 4106 results.sort(sortOrder);
Chris@909 4107
Chris@909 4108 if ( hasDuplicate ) {
Chris@909 4109 for ( var i = 1; i < results.length; i++ ) {
Chris@909 4110 if ( results[i] === results[i-1] ) {
Chris@909 4111 results.splice(i--, 1);
Chris@909 4112 }
Chris@909 4113 }
Chris@909 4114 }
Chris@909 4115 }
Chris@909 4116
Chris@909 4117 return results;
Chris@909 4118 };
Chris@909 4119
Chris@909 4120 Sizzle.matches = function(expr, set){
Chris@909 4121 return Sizzle(expr, null, null, set);
Chris@909 4122 };
Chris@909 4123
Chris@909 4124 Sizzle.find = function(expr, context, isXML){
Chris@909 4125 var set, match;
Chris@909 4126
Chris@909 4127 if ( !expr ) {
Chris@909 4128 return [];
Chris@909 4129 }
Chris@909 4130
Chris@909 4131 for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
Chris@909 4132 var type = Expr.order[i], match;
Chris@909 4133
Chris@909 4134 if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
Chris@909 4135 var left = match[1];
Chris@909 4136 match.splice(1,1);
Chris@909 4137
Chris@909 4138 if ( left.substr( left.length - 1 ) !== "\\" ) {
Chris@909 4139 match[1] = (match[1] || "").replace(/\\/g, "");
Chris@909 4140 set = Expr.find[ type ]( match, context, isXML );
Chris@909 4141 if ( set != null ) {
Chris@909 4142 expr = expr.replace( Expr.match[ type ], "" );
Chris@909 4143 break;
Chris@909 4144 }
Chris@909 4145 }
Chris@909 4146 }
Chris@909 4147 }
Chris@909 4148
Chris@909 4149 if ( !set ) {
Chris@909 4150 set = context.getElementsByTagName("*");
Chris@909 4151 }
Chris@909 4152
Chris@909 4153 return {set: set, expr: expr};
Chris@909 4154 };
Chris@909 4155
Chris@909 4156 Sizzle.filter = function(expr, set, inplace, not){
Chris@909 4157 var old = expr, result = [], curLoop = set, match, anyFound,
Chris@909 4158 isXMLFilter = set && set[0] && isXML(set[0]);
Chris@909 4159
Chris@909 4160 while ( expr && set.length ) {
Chris@909 4161 for ( var type in Expr.filter ) {
Chris@909 4162 if ( (match = Expr.match[ type ].exec( expr )) != null ) {
Chris@909 4163 var filter = Expr.filter[ type ], found, item;
Chris@909 4164 anyFound = false;
Chris@909 4165
Chris@909 4166 if ( curLoop == result ) {
Chris@909 4167 result = [];
Chris@909 4168 }
Chris@909 4169
Chris@909 4170 if ( Expr.preFilter[ type ] ) {
Chris@909 4171 match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
Chris@909 4172
Chris@909 4173 if ( !match ) {
Chris@909 4174 anyFound = found = true;
Chris@909 4175 } else if ( match === true ) {
Chris@909 4176 continue;
Chris@909 4177 }
Chris@909 4178 }
Chris@909 4179
Chris@909 4180 if ( match ) {
Chris@909 4181 for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
Chris@909 4182 if ( item ) {
Chris@909 4183 found = filter( item, match, i, curLoop );
Chris@909 4184 var pass = not ^ !!found;
Chris@909 4185
Chris@909 4186 if ( inplace && found != null ) {
Chris@909 4187 if ( pass ) {
Chris@909 4188 anyFound = true;
Chris@909 4189 } else {
Chris@909 4190 curLoop[i] = false;
Chris@909 4191 }
Chris@909 4192 } else if ( pass ) {
Chris@909 4193 result.push( item );
Chris@909 4194 anyFound = true;
Chris@909 4195 }
Chris@909 4196 }
Chris@909 4197 }
Chris@909 4198 }
Chris@909 4199
Chris@909 4200 if ( found !== undefined ) {
Chris@909 4201 if ( !inplace ) {
Chris@909 4202 curLoop = result;
Chris@909 4203 }
Chris@909 4204
Chris@909 4205 expr = expr.replace( Expr.match[ type ], "" );
Chris@909 4206
Chris@909 4207 if ( !anyFound ) {
Chris@909 4208 return [];
Chris@909 4209 }
Chris@909 4210
Chris@909 4211 break;
Chris@909 4212 }
Chris@909 4213 }
Chris@909 4214 }
Chris@909 4215
Chris@909 4216 if ( expr == old ) {
Chris@909 4217 if ( anyFound == null ) {
Chris@909 4218 throw "Syntax error, unrecognized expression: " + expr;
Chris@909 4219 } else {
Chris@909 4220 break;
Chris@909 4221 }
Chris@909 4222 }
Chris@909 4223
Chris@909 4224 old = expr;
Chris@909 4225 }
Chris@909 4226
Chris@909 4227 return curLoop;
Chris@909 4228 };
Chris@909 4229
Chris@909 4230 var Expr = Sizzle.selectors = {
Chris@909 4231 order: [ "ID", "NAME", "TAG" ],
Chris@909 4232 match: {
Chris@909 4233 ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
Chris@909 4234 CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
Chris@909 4235 NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,
Chris@909 4236 ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
Chris@909 4237 TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,
Chris@909 4238 CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
Chris@909 4239 POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
Chris@909 4240 PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/
Chris@909 4241 },
Chris@909 4242 leftMatch: {},
Chris@909 4243 attrMap: {
Chris@909 4244 "class": "className",
Chris@909 4245 "for": "htmlFor"
Chris@909 4246 },
Chris@909 4247 attrHandle: {
Chris@909 4248 href: function(elem){
Chris@909 4249 return elem.getAttribute("href");
Chris@909 4250 }
Chris@909 4251 },
Chris@909 4252 relative: {
Chris@909 4253 "+": function(checkSet, part, isXML){
Chris@909 4254 var isPartStr = typeof part === "string",
Chris@909 4255 isTag = isPartStr && !/\W/.test(part),
Chris@909 4256 isPartStrNotTag = isPartStr && !isTag;
Chris@909 4257
Chris@909 4258 if ( isTag && !isXML ) {
Chris@909 4259 part = part.toUpperCase();
Chris@909 4260 }
Chris@909 4261
Chris@909 4262 for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
Chris@909 4263 if ( (elem = checkSet[i]) ) {
Chris@909 4264 while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
Chris@909 4265
Chris@909 4266 checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ?
Chris@909 4267 elem || false :
Chris@909 4268 elem === part;
Chris@909 4269 }
Chris@909 4270 }
Chris@909 4271
Chris@909 4272 if ( isPartStrNotTag ) {
Chris@909 4273 Sizzle.filter( part, checkSet, true );
Chris@909 4274 }
Chris@909 4275 },
Chris@909 4276 ">": function(checkSet, part, isXML){
Chris@909 4277 var isPartStr = typeof part === "string";
Chris@909 4278
Chris@909 4279 if ( isPartStr && !/\W/.test(part) ) {
Chris@909 4280 part = isXML ? part : part.toUpperCase();
Chris@909 4281
Chris@909 4282 for ( var i = 0, l = checkSet.length; i < l; i++ ) {
Chris@909 4283 var elem = checkSet[i];
Chris@909 4284 if ( elem ) {
Chris@909 4285 var parent = elem.parentNode;
Chris@909 4286 checkSet[i] = parent.nodeName === part ? parent : false;
Chris@909 4287 }
Chris@909 4288 }
Chris@909 4289 } else {
Chris@909 4290 for ( var i = 0, l = checkSet.length; i < l; i++ ) {
Chris@909 4291 var elem = checkSet[i];
Chris@909 4292 if ( elem ) {
Chris@909 4293 checkSet[i] = isPartStr ?
Chris@909 4294 elem.parentNode :
Chris@909 4295 elem.parentNode === part;
Chris@909 4296 }
Chris@909 4297 }
Chris@909 4298
Chris@909 4299 if ( isPartStr ) {
Chris@909 4300 Sizzle.filter( part, checkSet, true );
Chris@909 4301 }
Chris@909 4302 }
Chris@909 4303 },
Chris@909 4304 "": function(checkSet, part, isXML){
Chris@909 4305 var doneName = done++, checkFn = dirCheck;
Chris@909 4306
Chris@909 4307 if ( !/\W/.test(part) ) {
Chris@909 4308 var nodeCheck = part = isXML ? part : part.toUpperCase();
Chris@909 4309 checkFn = dirNodeCheck;
Chris@909 4310 }
Chris@909 4311
Chris@909 4312 checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
Chris@909 4313 },
Chris@909 4314 "~": function(checkSet, part, isXML){
Chris@909 4315 var doneName = done++, checkFn = dirCheck;
Chris@909 4316
Chris@909 4317 if ( typeof part === "string" && !/\W/.test(part) ) {
Chris@909 4318 var nodeCheck = part = isXML ? part : part.toUpperCase();
Chris@909 4319 checkFn = dirNodeCheck;
Chris@909 4320 }
Chris@909 4321
Chris@909 4322 checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
Chris@909 4323 }
Chris@909 4324 },
Chris@909 4325 find: {
Chris@909 4326 ID: function(match, context, isXML){
Chris@909 4327 if ( typeof context.getElementById !== "undefined" && !isXML ) {
Chris@909 4328 var m = context.getElementById(match[1]);
Chris@909 4329 return m ? [m] : [];
Chris@909 4330 }
Chris@909 4331 },
Chris@909 4332 NAME: function(match, context, isXML){
Chris@909 4333 if ( typeof context.getElementsByName !== "undefined" ) {
Chris@909 4334 var ret = [], results = context.getElementsByName(match[1]);
Chris@909 4335
Chris@909 4336 for ( var i = 0, l = results.length; i < l; i++ ) {
Chris@909 4337 if ( results[i].getAttribute("name") === match[1] ) {
Chris@909 4338 ret.push( results[i] );
Chris@909 4339 }
Chris@909 4340 }
Chris@909 4341
Chris@909 4342 return ret.length === 0 ? null : ret;
Chris@909 4343 }
Chris@909 4344 },
Chris@909 4345 TAG: function(match, context){
Chris@909 4346 return context.getElementsByTagName(match[1]);
Chris@909 4347 }
Chris@909 4348 },
Chris@909 4349 preFilter: {
Chris@909 4350 CLASS: function(match, curLoop, inplace, result, not, isXML){
Chris@909 4351 match = " " + match[1].replace(/\\/g, "") + " ";
Chris@909 4352
Chris@909 4353 if ( isXML ) {
Chris@909 4354 return match;
Chris@909 4355 }
Chris@909 4356
Chris@909 4357 for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
Chris@909 4358 if ( elem ) {
Chris@909 4359 if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) {
Chris@909 4360 if ( !inplace )
Chris@909 4361 result.push( elem );
Chris@909 4362 } else if ( inplace ) {
Chris@909 4363 curLoop[i] = false;
Chris@909 4364 }
Chris@909 4365 }
Chris@909 4366 }
Chris@909 4367
Chris@909 4368 return false;
Chris@909 4369 },
Chris@909 4370 ID: function(match){
Chris@909 4371 return match[1].replace(/\\/g, "");
Chris@909 4372 },
Chris@909 4373 TAG: function(match, curLoop){
Chris@909 4374 for ( var i = 0; curLoop[i] === false; i++ ){}
Chris@909 4375 return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase();
Chris@909 4376 },
Chris@909 4377 CHILD: function(match){
Chris@909 4378 if ( match[1] == "nth" ) {
Chris@909 4379 var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
Chris@909 4380 match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" ||
Chris@909 4381 !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
Chris@909 4382
Chris@909 4383 match[2] = (test[1] + (test[2] || 1)) - 0;
Chris@909 4384 match[3] = test[3] - 0;
Chris@909 4385 }
Chris@909 4386
Chris@909 4387 match[0] = done++;
Chris@909 4388
Chris@909 4389 return match;
Chris@909 4390 },
Chris@909 4391 ATTR: function(match, curLoop, inplace, result, not, isXML){
Chris@909 4392 var name = match[1].replace(/\\/g, "");
Chris@909 4393
Chris@909 4394 if ( !isXML && Expr.attrMap[name] ) {
Chris@909 4395 match[1] = Expr.attrMap[name];
Chris@909 4396 }
Chris@909 4397
Chris@909 4398 if ( match[2] === "~=" ) {
Chris@909 4399 match[4] = " " + match[4] + " ";
Chris@909 4400 }
Chris@909 4401
Chris@909 4402 return match;
Chris@909 4403 },
Chris@909 4404 PSEUDO: function(match, curLoop, inplace, result, not){
Chris@909 4405 if ( match[1] === "not" ) {
Chris@909 4406 if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
Chris@909 4407 match[3] = Sizzle(match[3], null, null, curLoop);
Chris@909 4408 } else {
Chris@909 4409 var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
Chris@909 4410 if ( !inplace ) {
Chris@909 4411 result.push.apply( result, ret );
Chris@909 4412 }
Chris@909 4413 return false;
Chris@909 4414 }
Chris@909 4415 } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
Chris@909 4416 return true;
Chris@909 4417 }
Chris@909 4418
Chris@909 4419 return match;
Chris@909 4420 },
Chris@909 4421 POS: function(match){
Chris@909 4422 match.unshift( true );
Chris@909 4423 return match;
Chris@909 4424 }
Chris@909 4425 },
Chris@909 4426 filters: {
Chris@909 4427 enabled: function(elem){
Chris@909 4428 return elem.disabled === false && elem.type !== "hidden";
Chris@909 4429 },
Chris@909 4430 disabled: function(elem){
Chris@909 4431 return elem.disabled === true;
Chris@909 4432 },
Chris@909 4433 checked: function(elem){
Chris@909 4434 return elem.checked === true;
Chris@909 4435 },
Chris@909 4436 selected: function(elem){
Chris@909 4437 elem.parentNode.selectedIndex;
Chris@909 4438 return elem.selected === true;
Chris@909 4439 },
Chris@909 4440 parent: function(elem){
Chris@909 4441 return !!elem.firstChild;
Chris@909 4442 },
Chris@909 4443 empty: function(elem){
Chris@909 4444 return !elem.firstChild;
Chris@909 4445 },
Chris@909 4446 has: function(elem, i, match){
Chris@909 4447 return !!Sizzle( match[3], elem ).length;
Chris@909 4448 },
Chris@909 4449 header: function(elem){
Chris@909 4450 return /h\d/i.test( elem.nodeName );
Chris@909 4451 },
Chris@909 4452 text: function(elem){
Chris@909 4453 return "text" === elem.type;
Chris@909 4454 },
Chris@909 4455 radio: function(elem){
Chris@909 4456 return "radio" === elem.type;
Chris@909 4457 },
Chris@909 4458 checkbox: function(elem){
Chris@909 4459 return "checkbox" === elem.type;
Chris@909 4460 },
Chris@909 4461 file: function(elem){
Chris@909 4462 return "file" === elem.type;
Chris@909 4463 },
Chris@909 4464 password: function(elem){
Chris@909 4465 return "password" === elem.type;
Chris@909 4466 },
Chris@909 4467 submit: function(elem){
Chris@909 4468 return "submit" === elem.type;
Chris@909 4469 },
Chris@909 4470 image: function(elem){
Chris@909 4471 return "image" === elem.type;
Chris@909 4472 },
Chris@909 4473 reset: function(elem){
Chris@909 4474 return "reset" === elem.type;
Chris@909 4475 },
Chris@909 4476 button: function(elem){
Chris@909 4477 return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON";
Chris@909 4478 },
Chris@909 4479 input: function(elem){
Chris@909 4480 return /input|select|textarea|button/i.test(elem.nodeName);
Chris@909 4481 }
Chris@909 4482 },
Chris@909 4483 setFilters: {
Chris@909 4484 first: function(elem, i){
Chris@909 4485 return i === 0;
Chris@909 4486 },
Chris@909 4487 last: function(elem, i, match, array){
Chris@909 4488 return i === array.length - 1;
Chris@909 4489 },
Chris@909 4490 even: function(elem, i){
Chris@909 4491 return i % 2 === 0;
Chris@909 4492 },
Chris@909 4493 odd: function(elem, i){
Chris@909 4494 return i % 2 === 1;
Chris@909 4495 },
Chris@909 4496 lt: function(elem, i, match){
Chris@909 4497 return i < match[3] - 0;
Chris@909 4498 },
Chris@909 4499 gt: function(elem, i, match){
Chris@909 4500 return i > match[3] - 0;
Chris@909 4501 },
Chris@909 4502 nth: function(elem, i, match){
Chris@909 4503 return match[3] - 0 == i;
Chris@909 4504 },
Chris@909 4505 eq: function(elem, i, match){
Chris@909 4506 return match[3] - 0 == i;
Chris@909 4507 }
Chris@909 4508 },
Chris@909 4509 filter: {
Chris@909 4510 PSEUDO: function(elem, match, i, array){
Chris@909 4511 var name = match[1], filter = Expr.filters[ name ];
Chris@909 4512
Chris@909 4513 if ( filter ) {
Chris@909 4514 return filter( elem, i, match, array );
Chris@909 4515 } else if ( name === "contains" ) {
Chris@909 4516 return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0;
Chris@909 4517 } else if ( name === "not" ) {
Chris@909 4518 var not = match[3];
Chris@909 4519
Chris@909 4520 for ( var i = 0, l = not.length; i < l; i++ ) {
Chris@909 4521 if ( not[i] === elem ) {
Chris@909 4522 return false;
Chris@909 4523 }
Chris@909 4524 }
Chris@909 4525
Chris@909 4526 return true;
Chris@909 4527 }
Chris@909 4528 },
Chris@909 4529 CHILD: function(elem, match){
Chris@909 4530 var type = match[1], node = elem;
Chris@909 4531 switch (type) {
Chris@909 4532 case 'only':
Chris@909 4533 case 'first':
Chris@909 4534 while ( (node = node.previousSibling) ) {
Chris@909 4535 if ( node.nodeType === 1 ) return false;
Chris@909 4536 }
Chris@909 4537 if ( type == 'first') return true;
Chris@909 4538 node = elem;
Chris@909 4539 case 'last':
Chris@909 4540 while ( (node = node.nextSibling) ) {
Chris@909 4541 if ( node.nodeType === 1 ) return false;
Chris@909 4542 }
Chris@909 4543 return true;
Chris@909 4544 case 'nth':
Chris@909 4545 var first = match[2], last = match[3];
Chris@909 4546
Chris@909 4547 if ( first == 1 && last == 0 ) {
Chris@909 4548 return true;
Chris@909 4549 }
Chris@909 4550
Chris@909 4551 var doneName = match[0],
Chris@909 4552 parent = elem.parentNode;
Chris@909 4553
Chris@909 4554 if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
Chris@909 4555 var count = 0;
Chris@909 4556 for ( node = parent.firstChild; node; node = node.nextSibling ) {
Chris@909 4557 if ( node.nodeType === 1 ) {
Chris@909 4558 node.nodeIndex = ++count;
Chris@909 4559 }
Chris@909 4560 }
Chris@909 4561 parent.sizcache = doneName;
Chris@909 4562 }
Chris@909 4563
Chris@909 4564 var diff = elem.nodeIndex - last;
Chris@909 4565 if ( first == 0 ) {
Chris@909 4566 return diff == 0;
Chris@909 4567 } else {
Chris@909 4568 return ( diff % first == 0 && diff / first >= 0 );
Chris@909 4569 }
Chris@909 4570 }
Chris@909 4571 },
Chris@909 4572 ID: function(elem, match){
Chris@909 4573 return elem.nodeType === 1 && elem.getAttribute("id") === match;
Chris@909 4574 },
Chris@909 4575 TAG: function(elem, match){
Chris@909 4576 return (match === "*" && elem.nodeType === 1) || elem.nodeName === match;
Chris@909 4577 },
Chris@909 4578 CLASS: function(elem, match){
Chris@909 4579 return (" " + (elem.className || elem.getAttribute("class")) + " ")
Chris@909 4580 .indexOf( match ) > -1;
Chris@909 4581 },
Chris@909 4582 ATTR: function(elem, match){
Chris@909 4583 var name = match[1],
Chris@909 4584 result = Expr.attrHandle[ name ] ?
Chris@909 4585 Expr.attrHandle[ name ]( elem ) :
Chris@909 4586 elem[ name ] != null ?
Chris@909 4587 elem[ name ] :
Chris@909 4588 elem.getAttribute( name ),
Chris@909 4589 value = result + "",
Chris@909 4590 type = match[2],
Chris@909 4591 check = match[4];
Chris@909 4592
Chris@909 4593 return result == null ?
Chris@909 4594 type === "!=" :
Chris@909 4595 type === "=" ?
Chris@909 4596 value === check :
Chris@909 4597 type === "*=" ?
Chris@909 4598 value.indexOf(check) >= 0 :
Chris@909 4599 type === "~=" ?
Chris@909 4600 (" " + value + " ").indexOf(check) >= 0 :
Chris@909 4601 !check ?
Chris@909 4602 value && result !== false :
Chris@909 4603 type === "!=" ?
Chris@909 4604 value != check :
Chris@909 4605 type === "^=" ?
Chris@909 4606 value.indexOf(check) === 0 :
Chris@909 4607 type === "$=" ?
Chris@909 4608 value.substr(value.length - check.length) === check :
Chris@909 4609 type === "|=" ?
Chris@909 4610 value === check || value.substr(0, check.length + 1) === check + "-" :
Chris@909 4611 false;
Chris@909 4612 },
Chris@909 4613 POS: function(elem, match, i, array){
Chris@909 4614 var name = match[2], filter = Expr.setFilters[ name ];
Chris@909 4615
Chris@909 4616 if ( filter ) {
Chris@909 4617 return filter( elem, i, match, array );
Chris@909 4618 }
Chris@909 4619 }
Chris@909 4620 }
Chris@909 4621 };
Chris@909 4622
Chris@909 4623 var origPOS = Expr.match.POS;
Chris@909 4624
Chris@909 4625 for ( var type in Expr.match ) {
Chris@909 4626 Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
Chris@909 4627 Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source );
Chris@909 4628 }
Chris@909 4629
Chris@909 4630 var makeArray = function(array, results) {
Chris@909 4631 array = Array.prototype.slice.call( array, 0 );
Chris@909 4632
Chris@909 4633 if ( results ) {
Chris@909 4634 results.push.apply( results, array );
Chris@909 4635 return results;
Chris@909 4636 }
Chris@909 4637
Chris@909 4638 return array;
Chris@909 4639 };
Chris@909 4640
Chris@909 4641 try {
Chris@909 4642 Array.prototype.slice.call( document.documentElement.childNodes, 0 );
Chris@909 4643
Chris@909 4644 } catch(e){
Chris@909 4645 makeArray = function(array, results) {
Chris@909 4646 var ret = results || [];
Chris@909 4647
Chris@909 4648 if ( toString.call(array) === "[object Array]" ) {
Chris@909 4649 Array.prototype.push.apply( ret, array );
Chris@909 4650 } else {
Chris@909 4651 if ( typeof array.length === "number" ) {
Chris@909 4652 for ( var i = 0, l = array.length; i < l; i++ ) {
Chris@909 4653 ret.push( array[i] );
Chris@909 4654 }
Chris@909 4655 } else {
Chris@909 4656 for ( var i = 0; array[i]; i++ ) {
Chris@909 4657 ret.push( array[i] );
Chris@909 4658 }
Chris@909 4659 }
Chris@909 4660 }
Chris@909 4661
Chris@909 4662 return ret;
Chris@909 4663 };
Chris@909 4664 }
Chris@909 4665
Chris@909 4666 var sortOrder;
Chris@909 4667
Chris@909 4668 if ( document.documentElement.compareDocumentPosition ) {
Chris@909 4669 sortOrder = function( a, b ) {
Chris@909 4670 if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
Chris@909 4671 if ( a == b ) {
Chris@909 4672 hasDuplicate = true;
Chris@909 4673 }
Chris@909 4674 return 0;
Chris@909 4675 }
Chris@909 4676
Chris@909 4677 var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
Chris@909 4678 if ( ret === 0 ) {
Chris@909 4679 hasDuplicate = true;
Chris@909 4680 }
Chris@909 4681 return ret;
Chris@909 4682 };
Chris@909 4683 } else if ( "sourceIndex" in document.documentElement ) {
Chris@909 4684 sortOrder = function( a, b ) {
Chris@909 4685 if ( !a.sourceIndex || !b.sourceIndex ) {
Chris@909 4686 if ( a == b ) {
Chris@909 4687 hasDuplicate = true;
Chris@909 4688 }
Chris@909 4689 return 0;
Chris@909 4690 }
Chris@909 4691
Chris@909 4692 var ret = a.sourceIndex - b.sourceIndex;
Chris@909 4693 if ( ret === 0 ) {
Chris@909 4694 hasDuplicate = true;
Chris@909 4695 }
Chris@909 4696 return ret;
Chris@909 4697 };
Chris@909 4698 } else if ( document.createRange ) {
Chris@909 4699 sortOrder = function( a, b ) {
Chris@909 4700 if ( !a.ownerDocument || !b.ownerDocument ) {
Chris@909 4701 if ( a == b ) {
Chris@909 4702 hasDuplicate = true;
Chris@909 4703 }
Chris@909 4704 return 0;
Chris@909 4705 }
Chris@909 4706
Chris@909 4707 var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
Chris@909 4708 aRange.setStart(a, 0);
Chris@909 4709 aRange.setEnd(a, 0);
Chris@909 4710 bRange.setStart(b, 0);
Chris@909 4711 bRange.setEnd(b, 0);
Chris@909 4712 var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
Chris@909 4713 if ( ret === 0 ) {
Chris@909 4714 hasDuplicate = true;
Chris@909 4715 }
Chris@909 4716 return ret;
Chris@909 4717 };
Chris@909 4718 }
Chris@909 4719
Chris@909 4720 (function(){
Chris@909 4721 var form = document.createElement("div"),
Chris@909 4722 id = "script" + (new Date).getTime();
Chris@909 4723 form.innerHTML = "<a name='" + id + "'/>";
Chris@909 4724
Chris@909 4725 var root = document.documentElement;
Chris@909 4726 root.insertBefore( form, root.firstChild );
Chris@909 4727
Chris@909 4728 if ( !!document.getElementById( id ) ) {
Chris@909 4729 Expr.find.ID = function(match, context, isXML){
Chris@909 4730 if ( typeof context.getElementById !== "undefined" && !isXML ) {
Chris@909 4731 var m = context.getElementById(match[1]);
Chris@909 4732 return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
Chris@909 4733 }
Chris@909 4734 };
Chris@909 4735
Chris@909 4736 Expr.filter.ID = function(elem, match){
Chris@909 4737 var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
Chris@909 4738 return elem.nodeType === 1 && node && node.nodeValue === match;
Chris@909 4739 };
Chris@909 4740 }
Chris@909 4741
Chris@909 4742 root.removeChild( form );
Chris@909 4743 root = form = null; // release memory in IE
Chris@909 4744 })();
Chris@909 4745
Chris@909 4746 (function(){
Chris@909 4747
Chris@909 4748 var div = document.createElement("div");
Chris@909 4749 div.appendChild( document.createComment("") );
Chris@909 4750
Chris@909 4751 if ( div.getElementsByTagName("*").length > 0 ) {
Chris@909 4752 Expr.find.TAG = function(match, context){
Chris@909 4753 var results = context.getElementsByTagName(match[1]);
Chris@909 4754
Chris@909 4755 if ( match[1] === "*" ) {
Chris@909 4756 var tmp = [];
Chris@909 4757
Chris@909 4758 for ( var i = 0; results[i]; i++ ) {
Chris@909 4759 if ( results[i].nodeType === 1 ) {
Chris@909 4760 tmp.push( results[i] );
Chris@909 4761 }
Chris@909 4762 }
Chris@909 4763
Chris@909 4764 results = tmp;
Chris@909 4765 }
Chris@909 4766
Chris@909 4767 return results;
Chris@909 4768 };
Chris@909 4769 }
Chris@909 4770
Chris@909 4771 div.innerHTML = "<a href='#'></a>";
Chris@909 4772 if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
Chris@909 4773 div.firstChild.getAttribute("href") !== "#" ) {
Chris@909 4774 Expr.attrHandle.href = function(elem){
Chris@909 4775 return elem.getAttribute("href", 2);
Chris@909 4776 };
Chris@909 4777 }
Chris@909 4778
Chris@909 4779 div = null; // release memory in IE
Chris@909 4780 })();
Chris@909 4781
Chris@909 4782 if ( document.querySelectorAll ) (function(){
Chris@909 4783 var oldSizzle = Sizzle, div = document.createElement("div");
Chris@909 4784 div.innerHTML = "<p class='TEST'></p>";
Chris@909 4785
Chris@909 4786 if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
Chris@909 4787 return;
Chris@909 4788 }
Chris@909 4789
Chris@909 4790 Sizzle = function(query, context, extra, seed){
Chris@909 4791 context = context || document;
Chris@909 4792
Chris@909 4793 if ( !seed && context.nodeType === 9 && !isXML(context) ) {
Chris@909 4794 try {
Chris@909 4795 return makeArray( context.querySelectorAll(query), extra );
Chris@909 4796 } catch(e){}
Chris@909 4797 }
Chris@909 4798
Chris@909 4799 return oldSizzle(query, context, extra, seed);
Chris@909 4800 };
Chris@909 4801
Chris@909 4802 for ( var prop in oldSizzle ) {
Chris@909 4803 Sizzle[ prop ] = oldSizzle[ prop ];
Chris@909 4804 }
Chris@909 4805
Chris@909 4806 div = null; // release memory in IE
Chris@909 4807 })();
Chris@909 4808
Chris@909 4809 if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){
Chris@909 4810 var div = document.createElement("div");
Chris@909 4811 div.innerHTML = "<div class='test e'></div><div class='test'></div>";
Chris@909 4812
Chris@909 4813 if ( div.getElementsByClassName("e").length === 0 )
Chris@909 4814 return;
Chris@909 4815
Chris@909 4816 div.lastChild.className = "e";
Chris@909 4817
Chris@909 4818 if ( div.getElementsByClassName("e").length === 1 )
Chris@909 4819 return;
Chris@909 4820
Chris@909 4821 Expr.order.splice(1, 0, "CLASS");
Chris@909 4822 Expr.find.CLASS = function(match, context, isXML) {
Chris@909 4823 if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
Chris@909 4824 return context.getElementsByClassName(match[1]);
Chris@909 4825 }
Chris@909 4826 };
Chris@909 4827
Chris@909 4828 div = null; // release memory in IE
Chris@909 4829 })();
Chris@909 4830
Chris@909 4831 function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
Chris@909 4832 var sibDir = dir == "previousSibling" && !isXML;
Chris@909 4833 for ( var i = 0, l = checkSet.length; i < l; i++ ) {
Chris@909 4834 var elem = checkSet[i];
Chris@909 4835 if ( elem ) {
Chris@909 4836 if ( sibDir && elem.nodeType === 1 ){
Chris@909 4837 elem.sizcache = doneName;
Chris@909 4838 elem.sizset = i;
Chris@909 4839 }
Chris@909 4840 elem = elem[dir];
Chris@909 4841 var match = false;
Chris@909 4842
Chris@909 4843 while ( elem ) {
Chris@909 4844 if ( elem.sizcache === doneName ) {
Chris@909 4845 match = checkSet[elem.sizset];
Chris@909 4846 break;
Chris@909 4847 }
Chris@909 4848
Chris@909 4849 if ( elem.nodeType === 1 && !isXML ){
Chris@909 4850 elem.sizcache = doneName;
Chris@909 4851 elem.sizset = i;
Chris@909 4852 }
Chris@909 4853
Chris@909 4854 if ( elem.nodeName === cur ) {
Chris@909 4855 match = elem;
Chris@909 4856 break;
Chris@909 4857 }
Chris@909 4858
Chris@909 4859 elem = elem[dir];
Chris@909 4860 }
Chris@909 4861
Chris@909 4862 checkSet[i] = match;
Chris@909 4863 }
Chris@909 4864 }
Chris@909 4865 }
Chris@909 4866
Chris@909 4867 function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
Chris@909 4868 var sibDir = dir == "previousSibling" && !isXML;
Chris@909 4869 for ( var i = 0, l = checkSet.length; i < l; i++ ) {
Chris@909 4870 var elem = checkSet[i];
Chris@909 4871 if ( elem ) {
Chris@909 4872 if ( sibDir && elem.nodeType === 1 ) {
Chris@909 4873 elem.sizcache = doneName;
Chris@909 4874 elem.sizset = i;
Chris@909 4875 }
Chris@909 4876 elem = elem[dir];
Chris@909 4877 var match = false;
Chris@909 4878
Chris@909 4879 while ( elem ) {
Chris@909 4880 if ( elem.sizcache === doneName ) {
Chris@909 4881 match = checkSet[elem.sizset];
Chris@909 4882 break;
Chris@909 4883 }
Chris@909 4884
Chris@909 4885 if ( elem.nodeType === 1 ) {
Chris@909 4886 if ( !isXML ) {
Chris@909 4887 elem.sizcache = doneName;
Chris@909 4888 elem.sizset = i;
Chris@909 4889 }
Chris@909 4890 if ( typeof cur !== "string" ) {
Chris@909 4891 if ( elem === cur ) {
Chris@909 4892 match = true;
Chris@909 4893 break;
Chris@909 4894 }
Chris@909 4895
Chris@909 4896 } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
Chris@909 4897 match = elem;
Chris@909 4898 break;
Chris@909 4899 }
Chris@909 4900 }
Chris@909 4901
Chris@909 4902 elem = elem[dir];
Chris@909 4903 }
Chris@909 4904
Chris@909 4905 checkSet[i] = match;
Chris@909 4906 }
Chris@909 4907 }
Chris@909 4908 }
Chris@909 4909
Chris@909 4910 var contains = document.compareDocumentPosition ? function(a, b){
Chris@909 4911 return a.compareDocumentPosition(b) & 16;
Chris@909 4912 } : function(a, b){
Chris@909 4913 return a !== b && (a.contains ? a.contains(b) : true);
Chris@909 4914 };
Chris@909 4915
Chris@909 4916 var isXML = function(elem){
Chris@909 4917 return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
Chris@909 4918 !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML";
Chris@909 4919 };
Chris@909 4920
Chris@909 4921 var posProcess = function(selector, context){
Chris@909 4922 var tmpSet = [], later = "", match,
Chris@909 4923 root = context.nodeType ? [context] : context;
Chris@909 4924
Chris@909 4925 while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
Chris@909 4926 later += match[0];
Chris@909 4927 selector = selector.replace( Expr.match.PSEUDO, "" );
Chris@909 4928 }
Chris@909 4929
Chris@909 4930 selector = Expr.relative[selector] ? selector + "*" : selector;
Chris@909 4931
Chris@909 4932 for ( var i = 0, l = root.length; i < l; i++ ) {
Chris@909 4933 Sizzle( selector, root[i], tmpSet );
Chris@909 4934 }
Chris@909 4935
Chris@909 4936 return Sizzle.filter( later, tmpSet );
Chris@909 4937 };
Chris@909 4938
Chris@909 4939
Chris@909 4940 window.Sizzle = Sizzle;
Chris@909 4941
Chris@909 4942 })();
Chris@909 4943
Chris@909 4944 ;(function(engine) {
Chris@909 4945 var extendElements = Prototype.Selector.extendElements;
Chris@909 4946
Chris@909 4947 function select(selector, scope) {
Chris@909 4948 return extendElements(engine(selector, scope || document));
Chris@909 4949 }
Chris@909 4950
Chris@909 4951 function match(element, selector) {
Chris@909 4952 return engine.matches(selector, [element]).length == 1;
Chris@909 4953 }
Chris@909 4954
Chris@909 4955 Prototype.Selector.engine = engine;
Chris@909 4956 Prototype.Selector.select = select;
Chris@909 4957 Prototype.Selector.match = match;
Chris@909 4958 })(Sizzle);
Chris@909 4959
Chris@909 4960 window.Sizzle = Prototype._original_property;
Chris@909 4961 delete Prototype._original_property;
Chris@909 4962
Chris@909 4963 var Form = {
Chris@909 4964 reset: function(form) {
Chris@909 4965 form = $(form);
Chris@909 4966 form.reset();
Chris@909 4967 return form;
Chris@909 4968 },
Chris@909 4969
Chris@909 4970 serializeElements: function(elements, options) {
Chris@909 4971 if (typeof options != 'object') options = { hash: !!options };
Chris@909 4972 else if (Object.isUndefined(options.hash)) options.hash = true;
Chris@909 4973 var key, value, submitted = false, submit = options.submit, accumulator, initial;
Chris@909 4974
Chris@909 4975 if (options.hash) {
Chris@909 4976 initial = {};
Chris@909 4977 accumulator = function(result, key, value) {
Chris@909 4978 if (key in result) {
Chris@909 4979 if (!Object.isArray(result[key])) result[key] = [result[key]];
Chris@909 4980 result[key].push(value);
Chris@909 4981 } else result[key] = value;
Chris@909 4982 return result;
Chris@909 4983 };
Chris@909 4984 } else {
Chris@909 4985 initial = '';
Chris@909 4986 accumulator = function(result, key, value) {
Chris@909 4987 return result + (result ? '&' : '') + encodeURIComponent(key) + '=' + encodeURIComponent(value);
Chris@909 4988 }
Chris@909 4989 }
Chris@909 4990
Chris@909 4991 return elements.inject(initial, function(result, element) {
Chris@909 4992 if (!element.disabled && element.name) {
Chris@909 4993 key = element.name; value = $(element).getValue();
Chris@909 4994 if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&
Chris@909 4995 submit !== false && (!submit || key == submit) && (submitted = true)))) {
Chris@909 4996 result = accumulator(result, key, value);
Chris@909 4997 }
Chris@909 4998 }
Chris@909 4999 return result;
Chris@909 5000 });
Chris@909 5001 }
Chris@909 5002 };
Chris@909 5003
Chris@909 5004 Form.Methods = {
Chris@909 5005 serialize: function(form, options) {
Chris@909 5006 return Form.serializeElements(Form.getElements(form), options);
Chris@909 5007 },
Chris@909 5008
Chris@909 5009 getElements: function(form) {
Chris@909 5010 var elements = $(form).getElementsByTagName('*'),
Chris@909 5011 element,
Chris@909 5012 arr = [ ],
Chris@909 5013 serializers = Form.Element.Serializers;
Chris@909 5014 for (var i = 0; element = elements[i]; i++) {
Chris@909 5015 arr.push(element);
Chris@909 5016 }
Chris@909 5017 return arr.inject([], function(elements, child) {
Chris@909 5018 if (serializers[child.tagName.toLowerCase()])
Chris@909 5019 elements.push(Element.extend(child));
Chris@909 5020 return elements;
Chris@909 5021 })
Chris@909 5022 },
Chris@909 5023
Chris@909 5024 getInputs: function(form, typeName, name) {
Chris@909 5025 form = $(form);
Chris@909 5026 var inputs = form.getElementsByTagName('input');
Chris@909 5027
Chris@909 5028 if (!typeName && !name) return $A(inputs).map(Element.extend);
Chris@909 5029
Chris@909 5030 for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
Chris@909 5031 var input = inputs[i];
Chris@909 5032 if ((typeName && input.type != typeName) || (name && input.name != name))
Chris@909 5033 continue;
Chris@909 5034 matchingInputs.push(Element.extend(input));
Chris@909 5035 }
Chris@909 5036
Chris@909 5037 return matchingInputs;
Chris@909 5038 },
Chris@909 5039
Chris@909 5040 disable: function(form) {
Chris@909 5041 form = $(form);
Chris@909 5042 Form.getElements(form).invoke('disable');
Chris@909 5043 return form;
Chris@909 5044 },
Chris@909 5045
Chris@909 5046 enable: function(form) {
Chris@909 5047 form = $(form);
Chris@909 5048 Form.getElements(form).invoke('enable');
Chris@909 5049 return form;
Chris@909 5050 },
Chris@909 5051
Chris@909 5052 findFirstElement: function(form) {
Chris@909 5053 var elements = $(form).getElements().findAll(function(element) {
Chris@909 5054 return 'hidden' != element.type && !element.disabled;
Chris@909 5055 });
Chris@909 5056 var firstByIndex = elements.findAll(function(element) {
Chris@909 5057 return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
Chris@909 5058 }).sortBy(function(element) { return element.tabIndex }).first();
Chris@909 5059
Chris@909 5060 return firstByIndex ? firstByIndex : elements.find(function(element) {
Chris@909 5061 return /^(?:input|select|textarea)$/i.test(element.tagName);
Chris@909 5062 });
Chris@909 5063 },
Chris@909 5064
Chris@909 5065 focusFirstElement: function(form) {
Chris@909 5066 form = $(form);
Chris@909 5067 var element = form.findFirstElement();
Chris@909 5068 if (element) element.activate();
Chris@909 5069 return form;
Chris@909 5070 },
Chris@909 5071
Chris@909 5072 request: function(form, options) {
Chris@909 5073 form = $(form), options = Object.clone(options || { });
Chris@909 5074
Chris@909 5075 var params = options.parameters, action = form.readAttribute('action') || '';
Chris@909 5076 if (action.blank()) action = window.location.href;
Chris@909 5077 options.parameters = form.serialize(true);
Chris@909 5078
Chris@909 5079 if (params) {
Chris@909 5080 if (Object.isString(params)) params = params.toQueryParams();
Chris@909 5081 Object.extend(options.parameters, params);
Chris@909 5082 }
Chris@909 5083
Chris@909 5084 if (form.hasAttribute('method') && !options.method)
Chris@909 5085 options.method = form.method;
Chris@909 5086
Chris@909 5087 return new Ajax.Request(action, options);
Chris@909 5088 }
Chris@909 5089 };
Chris@909 5090
Chris@909 5091 /*--------------------------------------------------------------------------*/
Chris@909 5092
Chris@909 5093
Chris@909 5094 Form.Element = {
Chris@909 5095 focus: function(element) {
Chris@909 5096 $(element).focus();
Chris@909 5097 return element;
Chris@909 5098 },
Chris@909 5099
Chris@909 5100 select: function(element) {
Chris@909 5101 $(element).select();
Chris@909 5102 return element;
Chris@909 5103 }
Chris@909 5104 };
Chris@909 5105
Chris@909 5106 Form.Element.Methods = {
Chris@909 5107
Chris@909 5108 serialize: function(element) {
Chris@909 5109 element = $(element);
Chris@909 5110 if (!element.disabled && element.name) {
Chris@909 5111 var value = element.getValue();
Chris@909 5112 if (value != undefined) {
Chris@909 5113 var pair = { };
Chris@909 5114 pair[element.name] = value;
Chris@909 5115 return Object.toQueryString(pair);
Chris@909 5116 }
Chris@909 5117 }
Chris@909 5118 return '';
Chris@909 5119 },
Chris@909 5120
Chris@909 5121 getValue: function(element) {
Chris@909 5122 element = $(element);
Chris@909 5123 var method = element.tagName.toLowerCase();
Chris@909 5124 return Form.Element.Serializers[method](element);
Chris@909 5125 },
Chris@909 5126
Chris@909 5127 setValue: function(element, value) {
Chris@909 5128 element = $(element);
Chris@909 5129 var method = element.tagName.toLowerCase();
Chris@909 5130 Form.Element.Serializers[method](element, value);
Chris@909 5131 return element;
Chris@909 5132 },
Chris@909 5133
Chris@909 5134 clear: function(element) {
Chris@909 5135 $(element).value = '';
Chris@909 5136 return element;
Chris@909 5137 },
Chris@909 5138
Chris@909 5139 present: function(element) {
Chris@909 5140 return $(element).value != '';
Chris@909 5141 },
Chris@909 5142
Chris@909 5143 activate: function(element) {
Chris@909 5144 element = $(element);
Chris@909 5145 try {
Chris@909 5146 element.focus();
Chris@909 5147 if (element.select && (element.tagName.toLowerCase() != 'input' ||
Chris@909 5148 !(/^(?:button|reset|submit)$/i.test(element.type))))
Chris@909 5149 element.select();
Chris@909 5150 } catch (e) { }
Chris@909 5151 return element;
Chris@909 5152 },
Chris@909 5153
Chris@909 5154 disable: function(element) {
Chris@909 5155 element = $(element);
Chris@909 5156 element.disabled = true;
Chris@909 5157 return element;
Chris@909 5158 },
Chris@909 5159
Chris@909 5160 enable: function(element) {
Chris@909 5161 element = $(element);
Chris@909 5162 element.disabled = false;
Chris@909 5163 return element;
Chris@909 5164 }
Chris@909 5165 };
Chris@909 5166
Chris@909 5167 /*--------------------------------------------------------------------------*/
Chris@909 5168
Chris@909 5169 var Field = Form.Element;
Chris@909 5170
Chris@909 5171 var $F = Form.Element.Methods.getValue;
Chris@909 5172
Chris@909 5173 /*--------------------------------------------------------------------------*/
Chris@909 5174
Chris@909 5175 Form.Element.Serializers = (function() {
Chris@909 5176 function input(element, value) {
Chris@909 5177 switch (element.type.toLowerCase()) {
Chris@909 5178 case 'checkbox':
Chris@909 5179 case 'radio':
Chris@909 5180 return inputSelector(element, value);
Chris@909 5181 default:
Chris@909 5182 return valueSelector(element, value);
Chris@909 5183 }
Chris@909 5184 }
Chris@909 5185
Chris@909 5186 function inputSelector(element, value) {
Chris@909 5187 if (Object.isUndefined(value))
Chris@909 5188 return element.checked ? element.value : null;
Chris@909 5189 else element.checked = !!value;
Chris@909 5190 }
Chris@909 5191
Chris@909 5192 function valueSelector(element, value) {
Chris@909 5193 if (Object.isUndefined(value)) return element.value;
Chris@909 5194 else element.value = value;
Chris@909 5195 }
Chris@909 5196
Chris@909 5197 function select(element, value) {
Chris@909 5198 if (Object.isUndefined(value))
Chris@909 5199 return (element.type === 'select-one' ? selectOne : selectMany)(element);
Chris@909 5200
Chris@909 5201 var opt, currentValue, single = !Object.isArray(value);
Chris@909 5202 for (var i = 0, length = element.length; i < length; i++) {
Chris@909 5203 opt = element.options[i];
Chris@909 5204 currentValue = this.optionValue(opt);
Chris@909 5205 if (single) {
Chris@909 5206 if (currentValue == value) {
Chris@909 5207 opt.selected = true;
Chris@909 5208 return;
Chris@909 5209 }
Chris@909 5210 }
Chris@909 5211 else opt.selected = value.include(currentValue);
Chris@909 5212 }
Chris@909 5213 }
Chris@909 5214
Chris@909 5215 function selectOne(element) {
Chris@909 5216 var index = element.selectedIndex;
Chris@909 5217 return index >= 0 ? optionValue(element.options[index]) : null;
Chris@909 5218 }
Chris@909 5219
Chris@909 5220 function selectMany(element) {
Chris@909 5221 var values, length = element.length;
Chris@909 5222 if (!length) return null;
Chris@909 5223
Chris@909 5224 for (var i = 0, values = []; i < length; i++) {
Chris@909 5225 var opt = element.options[i];
Chris@909 5226 if (opt.selected) values.push(optionValue(opt));
Chris@909 5227 }
Chris@909 5228 return values;
Chris@909 5229 }
Chris@909 5230
Chris@909 5231 function optionValue(opt) {
Chris@909 5232 return Element.hasAttribute(opt, 'value') ? opt.value : opt.text;
Chris@909 5233 }
Chris@909 5234
Chris@909 5235 return {
Chris@909 5236 input: input,
Chris@909 5237 inputSelector: inputSelector,
Chris@909 5238 textarea: valueSelector,
Chris@909 5239 select: select,
Chris@909 5240 selectOne: selectOne,
Chris@909 5241 selectMany: selectMany,
Chris@909 5242 optionValue: optionValue,
Chris@909 5243 button: valueSelector
Chris@909 5244 };
Chris@909 5245 })();
Chris@909 5246
Chris@909 5247 /*--------------------------------------------------------------------------*/
Chris@909 5248
Chris@909 5249
Chris@909 5250 Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
Chris@909 5251 initialize: function($super, element, frequency, callback) {
Chris@909 5252 $super(callback, frequency);
Chris@909 5253 this.element = $(element);
Chris@909 5254 this.lastValue = this.getValue();
Chris@909 5255 },
Chris@909 5256
Chris@909 5257 execute: function() {
Chris@909 5258 var value = this.getValue();
Chris@909 5259 if (Object.isString(this.lastValue) && Object.isString(value) ?
Chris@909 5260 this.lastValue != value : String(this.lastValue) != String(value)) {
Chris@909 5261 this.callback(this.element, value);
Chris@909 5262 this.lastValue = value;
Chris@909 5263 }
Chris@909 5264 }
Chris@909 5265 });
Chris@909 5266
Chris@909 5267 Form.Element.Observer = Class.create(Abstract.TimedObserver, {
Chris@909 5268 getValue: function() {
Chris@909 5269 return Form.Element.getValue(this.element);
Chris@909 5270 }
Chris@909 5271 });
Chris@909 5272
Chris@909 5273 Form.Observer = Class.create(Abstract.TimedObserver, {
Chris@909 5274 getValue: function() {
Chris@909 5275 return Form.serialize(this.element);
Chris@909 5276 }
Chris@909 5277 });
Chris@909 5278
Chris@909 5279 /*--------------------------------------------------------------------------*/
Chris@909 5280
Chris@909 5281 Abstract.EventObserver = Class.create({
Chris@909 5282 initialize: function(element, callback) {
Chris@909 5283 this.element = $(element);
Chris@909 5284 this.callback = callback;
Chris@909 5285
Chris@909 5286 this.lastValue = this.getValue();
Chris@909 5287 if (this.element.tagName.toLowerCase() == 'form')
Chris@909 5288 this.registerFormCallbacks();
Chris@909 5289 else
Chris@909 5290 this.registerCallback(this.element);
Chris@909 5291 },
Chris@909 5292
Chris@909 5293 onElementEvent: function() {
Chris@909 5294 var value = this.getValue();
Chris@909 5295 if (this.lastValue != value) {
Chris@909 5296 this.callback(this.element, value);
Chris@909 5297 this.lastValue = value;
Chris@909 5298 }
Chris@909 5299 },
Chris@909 5300
Chris@909 5301 registerFormCallbacks: function() {
Chris@909 5302 Form.getElements(this.element).each(this.registerCallback, this);
Chris@909 5303 },
Chris@909 5304
Chris@909 5305 registerCallback: function(element) {
Chris@909 5306 if (element.type) {
Chris@909 5307 switch (element.type.toLowerCase()) {
Chris@909 5308 case 'checkbox':
Chris@909 5309 case 'radio':
Chris@909 5310 Event.observe(element, 'click', this.onElementEvent.bind(this));
Chris@909 5311 break;
Chris@909 5312 default:
Chris@909 5313 Event.observe(element, 'change', this.onElementEvent.bind(this));
Chris@909 5314 break;
Chris@909 5315 }
Chris@909 5316 }
Chris@909 5317 }
Chris@909 5318 });
Chris@909 5319
Chris@909 5320 Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
Chris@909 5321 getValue: function() {
Chris@909 5322 return Form.Element.getValue(this.element);
Chris@909 5323 }
Chris@909 5324 });
Chris@909 5325
Chris@909 5326 Form.EventObserver = Class.create(Abstract.EventObserver, {
Chris@909 5327 getValue: function() {
Chris@909 5328 return Form.serialize(this.element);
Chris@909 5329 }
Chris@909 5330 });
Chris@909 5331 (function() {
Chris@909 5332
Chris@909 5333 var Event = {
Chris@909 5334 KEY_BACKSPACE: 8,
Chris@909 5335 KEY_TAB: 9,
Chris@909 5336 KEY_RETURN: 13,
Chris@909 5337 KEY_ESC: 27,
Chris@909 5338 KEY_LEFT: 37,
Chris@909 5339 KEY_UP: 38,
Chris@909 5340 KEY_RIGHT: 39,
Chris@909 5341 KEY_DOWN: 40,
Chris@909 5342 KEY_DELETE: 46,
Chris@909 5343 KEY_HOME: 36,
Chris@909 5344 KEY_END: 35,
Chris@909 5345 KEY_PAGEUP: 33,
Chris@909 5346 KEY_PAGEDOWN: 34,
Chris@909 5347 KEY_INSERT: 45,
Chris@909 5348
Chris@909 5349 cache: {}
Chris@909 5350 };
Chris@909 5351
Chris@909 5352 var docEl = document.documentElement;
Chris@909 5353 var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl
Chris@909 5354 && 'onmouseleave' in docEl;
Chris@909 5355
Chris@909 5356
Chris@909 5357
Chris@909 5358 var isIELegacyEvent = function(event) { return false; };
Chris@909 5359
Chris@909 5360 if (window.attachEvent) {
Chris@909 5361 if (window.addEventListener) {
Chris@909 5362 isIELegacyEvent = function(event) {
Chris@909 5363 return !(event instanceof window.Event);
Chris@909 5364 };
Chris@909 5365 } else {
Chris@909 5366 isIELegacyEvent = function(event) { return true; };
Chris@909 5367 }
Chris@909 5368 }
Chris@909 5369
Chris@909 5370 var _isButton;
Chris@909 5371
Chris@909 5372 function _isButtonForDOMEvents(event, code) {
Chris@909 5373 return event.which ? (event.which === code + 1) : (event.button === code);
Chris@909 5374 }
Chris@909 5375
Chris@909 5376 var legacyButtonMap = { 0: 1, 1: 4, 2: 2 };
Chris@909 5377 function _isButtonForLegacyEvents(event, code) {
Chris@909 5378 return event.button === legacyButtonMap[code];
Chris@909 5379 }
Chris@909 5380
Chris@909 5381 function _isButtonForWebKit(event, code) {
Chris@909 5382 switch (code) {
Chris@909 5383 case 0: return event.which == 1 && !event.metaKey;
Chris@909 5384 case 1: return event.which == 2 || (event.which == 1 && event.metaKey);
Chris@909 5385 case 2: return event.which == 3;
Chris@909 5386 default: return false;
Chris@909 5387 }
Chris@909 5388 }
Chris@909 5389
Chris@909 5390 if (window.attachEvent) {
Chris@909 5391 if (!window.addEventListener) {
Chris@909 5392 _isButton = _isButtonForLegacyEvents;
Chris@909 5393 } else {
Chris@909 5394 _isButton = function(event, code) {
Chris@909 5395 return isIELegacyEvent(event) ? _isButtonForLegacyEvents(event, code) :
Chris@909 5396 _isButtonForDOMEvents(event, code);
Chris@909 5397 }
Chris@909 5398 }
Chris@909 5399 } else if (Prototype.Browser.WebKit) {
Chris@909 5400 _isButton = _isButtonForWebKit;
Chris@909 5401 } else {
Chris@909 5402 _isButton = _isButtonForDOMEvents;
Chris@909 5403 }
Chris@909 5404
Chris@909 5405 function isLeftClick(event) { return _isButton(event, 0) }
Chris@909 5406
Chris@909 5407 function isMiddleClick(event) { return _isButton(event, 1) }
Chris@909 5408
Chris@909 5409 function isRightClick(event) { return _isButton(event, 2) }
Chris@909 5410
Chris@909 5411 function element(event) {
Chris@909 5412 event = Event.extend(event);
Chris@909 5413
Chris@909 5414 var node = event.target, type = event.type,
Chris@909 5415 currentTarget = event.currentTarget;
Chris@909 5416
Chris@909 5417 if (currentTarget && currentTarget.tagName) {
Chris@909 5418 if (type === 'load' || type === 'error' ||
Chris@909 5419 (type === 'click' && currentTarget.tagName.toLowerCase() === 'input'
Chris@909 5420 && currentTarget.type === 'radio'))
Chris@909 5421 node = currentTarget;
Chris@909 5422 }
Chris@909 5423
Chris@909 5424 if (node.nodeType == Node.TEXT_NODE)
Chris@909 5425 node = node.parentNode;
Chris@909 5426
Chris@909 5427 return Element.extend(node);
Chris@909 5428 }
Chris@909 5429
Chris@909 5430 function findElement(event, expression) {
Chris@909 5431 var element = Event.element(event);
Chris@909 5432
Chris@909 5433 if (!expression) return element;
Chris@909 5434 while (element) {
Chris@909 5435 if (Object.isElement(element) && Prototype.Selector.match(element, expression)) {
Chris@909 5436 return Element.extend(element);
Chris@909 5437 }
Chris@909 5438 element = element.parentNode;
Chris@909 5439 }
Chris@909 5440 }
Chris@909 5441
Chris@909 5442 function pointer(event) {
Chris@909 5443 return { x: pointerX(event), y: pointerY(event) };
Chris@909 5444 }
Chris@909 5445
Chris@909 5446 function pointerX(event) {
Chris@909 5447 var docElement = document.documentElement,
Chris@909 5448 body = document.body || { scrollLeft: 0 };
Chris@909 5449
Chris@909 5450 return event.pageX || (event.clientX +
Chris@909 5451 (docElement.scrollLeft || body.scrollLeft) -
Chris@909 5452 (docElement.clientLeft || 0));
Chris@909 5453 }
Chris@909 5454
Chris@909 5455 function pointerY(event) {
Chris@909 5456 var docElement = document.documentElement,
Chris@909 5457 body = document.body || { scrollTop: 0 };
Chris@909 5458
Chris@909 5459 return event.pageY || (event.clientY +
Chris@909 5460 (docElement.scrollTop || body.scrollTop) -
Chris@909 5461 (docElement.clientTop || 0));
Chris@909 5462 }
Chris@909 5463
Chris@909 5464
Chris@909 5465 function stop(event) {
Chris@909 5466 Event.extend(event);
Chris@909 5467 event.preventDefault();
Chris@909 5468 event.stopPropagation();
Chris@909 5469
Chris@909 5470 event.stopped = true;
Chris@909 5471 }
Chris@909 5472
Chris@909 5473
Chris@909 5474 Event.Methods = {
Chris@909 5475 isLeftClick: isLeftClick,
Chris@909 5476 isMiddleClick: isMiddleClick,
Chris@909 5477 isRightClick: isRightClick,
Chris@909 5478
Chris@909 5479 element: element,
Chris@909 5480 findElement: findElement,
Chris@909 5481
Chris@909 5482 pointer: pointer,
Chris@909 5483 pointerX: pointerX,
Chris@909 5484 pointerY: pointerY,
Chris@909 5485
Chris@909 5486 stop: stop
Chris@909 5487 };
Chris@909 5488
Chris@909 5489 var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
Chris@909 5490 m[name] = Event.Methods[name].methodize();
Chris@909 5491 return m;
Chris@909 5492 });
Chris@909 5493
Chris@909 5494 if (window.attachEvent) {
Chris@909 5495 function _relatedTarget(event) {
Chris@909 5496 var element;
Chris@909 5497 switch (event.type) {
Chris@909 5498 case 'mouseover':
Chris@909 5499 case 'mouseenter':
Chris@909 5500 element = event.fromElement;
Chris@909 5501 break;
Chris@909 5502 case 'mouseout':
Chris@909 5503 case 'mouseleave':
Chris@909 5504 element = event.toElement;
Chris@909 5505 break;
Chris@909 5506 default:
Chris@909 5507 return null;
Chris@909 5508 }
Chris@909 5509 return Element.extend(element);
Chris@909 5510 }
Chris@909 5511
Chris@909 5512 var additionalMethods = {
Chris@909 5513 stopPropagation: function() { this.cancelBubble = true },
Chris@909 5514 preventDefault: function() { this.returnValue = false },
Chris@909 5515 inspect: function() { return '[object Event]' }
Chris@909 5516 };
Chris@909 5517
Chris@909 5518 Event.extend = function(event, element) {
Chris@909 5519 if (!event) return false;
Chris@909 5520
Chris@909 5521 if (!isIELegacyEvent(event)) return event;
Chris@909 5522
Chris@909 5523 if (event._extendedByPrototype) return event;
Chris@909 5524 event._extendedByPrototype = Prototype.emptyFunction;
Chris@909 5525
Chris@909 5526 var pointer = Event.pointer(event);
Chris@909 5527
Chris@909 5528 Object.extend(event, {
Chris@909 5529 target: event.srcElement || element,
Chris@909 5530 relatedTarget: _relatedTarget(event),
Chris@909 5531 pageX: pointer.x,
Chris@909 5532 pageY: pointer.y
Chris@909 5533 });
Chris@909 5534
Chris@909 5535 Object.extend(event, methods);
Chris@909 5536 Object.extend(event, additionalMethods);
Chris@909 5537
Chris@909 5538 return event;
Chris@909 5539 };
Chris@909 5540 } else {
Chris@909 5541 Event.extend = Prototype.K;
Chris@909 5542 }
Chris@909 5543
Chris@909 5544 if (window.addEventListener) {
Chris@909 5545 Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__;
Chris@909 5546 Object.extend(Event.prototype, methods);
Chris@909 5547 }
Chris@909 5548
Chris@909 5549 function _createResponder(element, eventName, handler) {
Chris@909 5550 var registry = Element.retrieve(element, 'prototype_event_registry');
Chris@909 5551
Chris@909 5552 if (Object.isUndefined(registry)) {
Chris@909 5553 CACHE.push(element);
Chris@909 5554 registry = Element.retrieve(element, 'prototype_event_registry', $H());
Chris@909 5555 }
Chris@909 5556
Chris@909 5557 var respondersForEvent = registry.get(eventName);
Chris@909 5558 if (Object.isUndefined(respondersForEvent)) {
Chris@909 5559 respondersForEvent = [];
Chris@909 5560 registry.set(eventName, respondersForEvent);
Chris@909 5561 }
Chris@909 5562
Chris@909 5563 if (respondersForEvent.pluck('handler').include(handler)) return false;
Chris@909 5564
Chris@909 5565 var responder;
Chris@909 5566 if (eventName.include(":")) {
Chris@909 5567 responder = function(event) {
Chris@909 5568 if (Object.isUndefined(event.eventName))
Chris@909 5569 return false;
Chris@909 5570
Chris@909 5571 if (event.eventName !== eventName)
Chris@909 5572 return false;
Chris@909 5573
Chris@909 5574 Event.extend(event, element);
Chris@909 5575 handler.call(element, event);
Chris@909 5576 };
Chris@909 5577 } else {
Chris@909 5578 if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED &&
Chris@909 5579 (eventName === "mouseenter" || eventName === "mouseleave")) {
Chris@909 5580 if (eventName === "mouseenter" || eventName === "mouseleave") {
Chris@909 5581 responder = function(event) {
Chris@909 5582 Event.extend(event, element);
Chris@909 5583
Chris@909 5584 var parent = event.relatedTarget;
Chris@909 5585 while (parent && parent !== element) {
Chris@909 5586 try { parent = parent.parentNode; }
Chris@909 5587 catch(e) { parent = element; }
Chris@909 5588 }
Chris@909 5589
Chris@909 5590 if (parent === element) return;
Chris@909 5591
Chris@909 5592 handler.call(element, event);
Chris@909 5593 };
Chris@909 5594 }
Chris@909 5595 } else {
Chris@909 5596 responder = function(event) {
Chris@909 5597 Event.extend(event, element);
Chris@909 5598 handler.call(element, event);
Chris@909 5599 };
Chris@909 5600 }
Chris@909 5601 }
Chris@909 5602
Chris@909 5603 responder.handler = handler;
Chris@909 5604 respondersForEvent.push(responder);
Chris@909 5605 return responder;
Chris@909 5606 }
Chris@909 5607
Chris@909 5608 function _destroyCache() {
Chris@909 5609 for (var i = 0, length = CACHE.length; i < length; i++) {
Chris@909 5610 Event.stopObserving(CACHE[i]);
Chris@909 5611 CACHE[i] = null;
Chris@909 5612 }
Chris@909 5613 }
Chris@909 5614
Chris@909 5615 var CACHE = [];
Chris@909 5616
Chris@909 5617 if (Prototype.Browser.IE)
Chris@909 5618 window.attachEvent('onunload', _destroyCache);
Chris@909 5619
Chris@909 5620 if (Prototype.Browser.WebKit)
Chris@909 5621 window.addEventListener('unload', Prototype.emptyFunction, false);
Chris@909 5622
Chris@909 5623
Chris@909 5624 var _getDOMEventName = Prototype.K,
Chris@909 5625 translations = { mouseenter: "mouseover", mouseleave: "mouseout" };
Chris@909 5626
Chris@909 5627 if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED) {
Chris@909 5628 _getDOMEventName = function(eventName) {
Chris@909 5629 return (translations[eventName] || eventName);
Chris@909 5630 };
Chris@909 5631 }
Chris@909 5632
Chris@909 5633 function observe(element, eventName, handler) {
Chris@909 5634 element = $(element);
Chris@909 5635
Chris@909 5636 var responder = _createResponder(element, eventName, handler);
Chris@909 5637
Chris@909 5638 if (!responder) return element;
Chris@909 5639
Chris@909 5640 if (eventName.include(':')) {
Chris@909 5641 if (element.addEventListener)
Chris@909 5642 element.addEventListener("dataavailable", responder, false);
Chris@909 5643 else {
Chris@909 5644 element.attachEvent("ondataavailable", responder);
Chris@909 5645 element.attachEvent("onlosecapture", responder);
Chris@909 5646 }
Chris@909 5647 } else {
Chris@909 5648 var actualEventName = _getDOMEventName(eventName);
Chris@909 5649
Chris@909 5650 if (element.addEventListener)
Chris@909 5651 element.addEventListener(actualEventName, responder, false);
Chris@909 5652 else
Chris@909 5653 element.attachEvent("on" + actualEventName, responder);
Chris@909 5654 }
Chris@909 5655
Chris@909 5656 return element;
Chris@909 5657 }
Chris@909 5658
Chris@909 5659 function stopObserving(element, eventName, handler) {
Chris@909 5660 element = $(element);
Chris@909 5661
Chris@909 5662 var registry = Element.retrieve(element, 'prototype_event_registry');
Chris@909 5663 if (!registry) return element;
Chris@909 5664
Chris@909 5665 if (!eventName) {
Chris@909 5666 registry.each( function(pair) {
Chris@909 5667 var eventName = pair.key;
Chris@909 5668 stopObserving(element, eventName);
Chris@909 5669 });
Chris@909 5670 return element;
Chris@909 5671 }
Chris@909 5672
Chris@909 5673 var responders = registry.get(eventName);
Chris@909 5674 if (!responders) return element;
Chris@909 5675
Chris@909 5676 if (!handler) {
Chris@909 5677 responders.each(function(r) {
Chris@909 5678 stopObserving(element, eventName, r.handler);
Chris@909 5679 });
Chris@909 5680 return element;
Chris@909 5681 }
Chris@909 5682
Chris@909 5683 var i = responders.length, responder;
Chris@909 5684 while (i--) {
Chris@909 5685 if (responders[i].handler === handler) {
Chris@909 5686 responder = responders[i];
Chris@909 5687 break;
Chris@909 5688 }
Chris@909 5689 }
Chris@909 5690 if (!responder) return element;
Chris@909 5691
Chris@909 5692 if (eventName.include(':')) {
Chris@909 5693 if (element.removeEventListener)
Chris@909 5694 element.removeEventListener("dataavailable", responder, false);
Chris@909 5695 else {
Chris@909 5696 element.detachEvent("ondataavailable", responder);
Chris@909 5697 element.detachEvent("onlosecapture", responder);
Chris@909 5698 }
Chris@909 5699 } else {
Chris@909 5700 var actualEventName = _getDOMEventName(eventName);
Chris@909 5701 if (element.removeEventListener)
Chris@909 5702 element.removeEventListener(actualEventName, responder, false);
Chris@909 5703 else
Chris@909 5704 element.detachEvent('on' + actualEventName, responder);
Chris@909 5705 }
Chris@909 5706
Chris@909 5707 registry.set(eventName, responders.without(responder));
Chris@909 5708
Chris@909 5709 return element;
Chris@909 5710 }
Chris@909 5711
Chris@909 5712 function fire(element, eventName, memo, bubble) {
Chris@909 5713 element = $(element);
Chris@909 5714
Chris@909 5715 if (Object.isUndefined(bubble))
Chris@909 5716 bubble = true;
Chris@909 5717
Chris@909 5718 if (element == document && document.createEvent && !element.dispatchEvent)
Chris@909 5719 element = document.documentElement;
Chris@909 5720
Chris@909 5721 var event;
Chris@909 5722 if (document.createEvent) {
Chris@909 5723 event = document.createEvent('HTMLEvents');
Chris@909 5724 event.initEvent('dataavailable', bubble, true);
Chris@909 5725 } else {
Chris@909 5726 event = document.createEventObject();
Chris@909 5727 event.eventType = bubble ? 'ondataavailable' : 'onlosecapture';
Chris@909 5728 }
Chris@909 5729
Chris@909 5730 event.eventName = eventName;
Chris@909 5731 event.memo = memo || { };
Chris@909 5732
Chris@909 5733 if (document.createEvent)
Chris@909 5734 element.dispatchEvent(event);
Chris@909 5735 else
Chris@909 5736 element.fireEvent(event.eventType, event);
Chris@909 5737
Chris@909 5738 return Event.extend(event);
Chris@909 5739 }
Chris@909 5740
Chris@909 5741 Event.Handler = Class.create({
Chris@909 5742 initialize: function(element, eventName, selector, callback) {
Chris@909 5743 this.element = $(element);
Chris@909 5744 this.eventName = eventName;
Chris@909 5745 this.selector = selector;
Chris@909 5746 this.callback = callback;
Chris@909 5747 this.handler = this.handleEvent.bind(this);
Chris@909 5748 },
Chris@909 5749
Chris@909 5750 start: function() {
Chris@909 5751 Event.observe(this.element, this.eventName, this.handler);
Chris@909 5752 return this;
Chris@909 5753 },
Chris@909 5754
Chris@909 5755 stop: function() {
Chris@909 5756 Event.stopObserving(this.element, this.eventName, this.handler);
Chris@909 5757 return this;
Chris@909 5758 },
Chris@909 5759
Chris@909 5760 handleEvent: function(event) {
Chris@909 5761 var element = Event.findElement(event, this.selector);
Chris@909 5762 if (element) this.callback.call(this.element, event, element);
Chris@909 5763 }
Chris@909 5764 });
Chris@909 5765
Chris@909 5766 function on(element, eventName, selector, callback) {
Chris@909 5767 element = $(element);
Chris@909 5768 if (Object.isFunction(selector) && Object.isUndefined(callback)) {
Chris@909 5769 callback = selector, selector = null;
Chris@909 5770 }
Chris@909 5771
Chris@909 5772 return new Event.Handler(element, eventName, selector, callback).start();
Chris@909 5773 }
Chris@909 5774
Chris@909 5775 Object.extend(Event, Event.Methods);
Chris@909 5776
Chris@909 5777 Object.extend(Event, {
Chris@909 5778 fire: fire,
Chris@909 5779 observe: observe,
Chris@909 5780 stopObserving: stopObserving,
Chris@909 5781 on: on
Chris@909 5782 });
Chris@909 5783
Chris@909 5784 Element.addMethods({
Chris@909 5785 fire: fire,
Chris@909 5786
Chris@909 5787 observe: observe,
Chris@909 5788
Chris@909 5789 stopObserving: stopObserving,
Chris@909 5790
Chris@909 5791 on: on
Chris@909 5792 });
Chris@909 5793
Chris@909 5794 Object.extend(document, {
Chris@909 5795 fire: fire.methodize(),
Chris@909 5796
Chris@909 5797 observe: observe.methodize(),
Chris@909 5798
Chris@909 5799 stopObserving: stopObserving.methodize(),
Chris@909 5800
Chris@909 5801 on: on.methodize(),
Chris@909 5802
Chris@909 5803 loaded: false
Chris@909 5804 });
Chris@909 5805
Chris@909 5806 if (window.Event) Object.extend(window.Event, Event);
Chris@909 5807 else window.Event = Event;
Chris@909 5808 })();
Chris@909 5809
Chris@909 5810 (function() {
Chris@909 5811 /* Support for the DOMContentLoaded event is based on work by Dan Webb,
Chris@909 5812 Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */
Chris@909 5813
Chris@909 5814 var timer;
Chris@909 5815
Chris@909 5816 function fireContentLoadedEvent() {
Chris@909 5817 if (document.loaded) return;
Chris@909 5818 if (timer) window.clearTimeout(timer);
Chris@909 5819 document.loaded = true;
Chris@909 5820 document.fire('dom:loaded');
Chris@909 5821 }
Chris@909 5822
Chris@909 5823 function checkReadyState() {
Chris@909 5824 if (document.readyState === 'complete') {
Chris@909 5825 document.stopObserving('readystatechange', checkReadyState);
Chris@909 5826 fireContentLoadedEvent();
Chris@909 5827 }
Chris@909 5828 }
Chris@909 5829
Chris@909 5830 function pollDoScroll() {
Chris@909 5831 try { document.documentElement.doScroll('left'); }
Chris@909 5832 catch(e) {
Chris@909 5833 timer = pollDoScroll.defer();
Chris@909 5834 return;
Chris@909 5835 }
Chris@909 5836 fireContentLoadedEvent();
Chris@909 5837 }
Chris@909 5838
Chris@909 5839 if (document.addEventListener) {
Chris@909 5840 document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
Chris@909 5841 } else {
Chris@909 5842 document.observe('readystatechange', checkReadyState);
Chris@909 5843 if (window == top)
Chris@909 5844 timer = pollDoScroll.defer();
Chris@909 5845 }
Chris@909 5846
Chris@909 5847 Event.observe(window, 'load', fireContentLoadedEvent);
Chris@909 5848 })();
Chris@909 5849
Chris@909 5850 Element.addMethods();
Chris@909 5851
Chris@909 5852 /*------------------------------- DEPRECATED -------------------------------*/
Chris@909 5853
Chris@909 5854 Hash.toQueryString = Object.toQueryString;
Chris@909 5855
Chris@909 5856 var Toggle = { display: Element.toggle };
Chris@909 5857
Chris@909 5858 Element.Methods.childOf = Element.Methods.descendantOf;
Chris@909 5859
Chris@909 5860 var Insertion = {
Chris@909 5861 Before: function(element, content) {
Chris@909 5862 return Element.insert(element, {before:content});
Chris@909 5863 },
Chris@909 5864
Chris@909 5865 Top: function(element, content) {
Chris@909 5866 return Element.insert(element, {top:content});
Chris@909 5867 },
Chris@909 5868
Chris@909 5869 Bottom: function(element, content) {
Chris@909 5870 return Element.insert(element, {bottom:content});
Chris@909 5871 },
Chris@909 5872
Chris@909 5873 After: function(element, content) {
Chris@909 5874 return Element.insert(element, {after:content});
Chris@909 5875 }
Chris@909 5876 };
Chris@909 5877
Chris@909 5878 var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
Chris@909 5879
Chris@909 5880 var Position = {
Chris@909 5881 includeScrollOffsets: false,
Chris@909 5882
Chris@909 5883 prepare: function() {
Chris@909 5884 this.deltaX = window.pageXOffset
Chris@909 5885 || document.documentElement.scrollLeft
Chris@909 5886 || document.body.scrollLeft
Chris@909 5887 || 0;
Chris@909 5888 this.deltaY = window.pageYOffset
Chris@909 5889 || document.documentElement.scrollTop
Chris@909 5890 || document.body.scrollTop
Chris@909 5891 || 0;
Chris@909 5892 },
Chris@909 5893
Chris@909 5894 within: function(element, x, y) {
Chris@909 5895 if (this.includeScrollOffsets)
Chris@909 5896 return this.withinIncludingScrolloffsets(element, x, y);
Chris@909 5897 this.xcomp = x;
Chris@909 5898 this.ycomp = y;
Chris@909 5899 this.offset = Element.cumulativeOffset(element);
Chris@909 5900
Chris@909 5901 return (y >= this.offset[1] &&
Chris@909 5902 y < this.offset[1] + element.offsetHeight &&
Chris@909 5903 x >= this.offset[0] &&
Chris@909 5904 x < this.offset[0] + element.offsetWidth);
Chris@909 5905 },
Chris@909 5906
Chris@909 5907 withinIncludingScrolloffsets: function(element, x, y) {
Chris@909 5908 var offsetcache = Element.cumulativeScrollOffset(element);
Chris@909 5909
Chris@909 5910 this.xcomp = x + offsetcache[0] - this.deltaX;
Chris@909 5911 this.ycomp = y + offsetcache[1] - this.deltaY;
Chris@909 5912 this.offset = Element.cumulativeOffset(element);
Chris@909 5913
Chris@909 5914 return (this.ycomp >= this.offset[1] &&
Chris@909 5915 this.ycomp < this.offset[1] + element.offsetHeight &&
Chris@909 5916 this.xcomp >= this.offset[0] &&
Chris@909 5917 this.xcomp < this.offset[0] + element.offsetWidth);
Chris@909 5918 },
Chris@909 5919
Chris@909 5920 overlap: function(mode, element) {
Chris@909 5921 if (!mode) return 0;
Chris@909 5922 if (mode == 'vertical')
Chris@909 5923 return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
Chris@909 5924 element.offsetHeight;
Chris@909 5925 if (mode == 'horizontal')
Chris@909 5926 return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
Chris@909 5927 element.offsetWidth;
Chris@909 5928 },
Chris@909 5929
Chris@909 5930
Chris@909 5931 cumulativeOffset: Element.Methods.cumulativeOffset,
Chris@909 5932
Chris@909 5933 positionedOffset: Element.Methods.positionedOffset,
Chris@909 5934
Chris@909 5935 absolutize: function(element) {
Chris@909 5936 Position.prepare();
Chris@909 5937 return Element.absolutize(element);
Chris@909 5938 },
Chris@909 5939
Chris@909 5940 relativize: function(element) {
Chris@909 5941 Position.prepare();
Chris@909 5942 return Element.relativize(element);
Chris@909 5943 },
Chris@909 5944
Chris@909 5945 realOffset: Element.Methods.cumulativeScrollOffset,
Chris@909 5946
Chris@909 5947 offsetParent: Element.Methods.getOffsetParent,
Chris@909 5948
Chris@909 5949 page: Element.Methods.viewportOffset,
Chris@909 5950
Chris@909 5951 clone: function(source, target, options) {
Chris@909 5952 options = options || { };
Chris@909 5953 return Element.clonePosition(target, source, options);
Chris@909 5954 }
Chris@909 5955 };
Chris@909 5956
Chris@909 5957 /*--------------------------------------------------------------------------*/
Chris@909 5958
Chris@909 5959 if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
Chris@909 5960 function iter(name) {
Chris@909 5961 return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
Chris@909 5962 }
Chris@909 5963
Chris@909 5964 instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
Chris@909 5965 function(element, className) {
Chris@909 5966 className = className.toString().strip();
Chris@909 5967 var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
Chris@909 5968 return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
Chris@909 5969 } : function(element, className) {
Chris@909 5970 className = className.toString().strip();
Chris@909 5971 var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
Chris@909 5972 if (!classNames && !className) return elements;
Chris@909 5973
Chris@909 5974 var nodes = $(element).getElementsByTagName('*');
Chris@909 5975 className = ' ' + className + ' ';
Chris@909 5976
Chris@909 5977 for (var i = 0, child, cn; child = nodes[i]; i++) {
Chris@909 5978 if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
Chris@909 5979 (classNames && classNames.all(function(name) {
Chris@909 5980 return !name.toString().blank() && cn.include(' ' + name + ' ');
Chris@909 5981 }))))
Chris@909 5982 elements.push(Element.extend(child));
Chris@909 5983 }
Chris@909 5984 return elements;
Chris@909 5985 };
Chris@909 5986
Chris@909 5987 return function(className, parentElement) {
Chris@909 5988 return $(parentElement || document.body).getElementsByClassName(className);
Chris@909 5989 };
Chris@909 5990 }(Element.Methods);
Chris@909 5991
Chris@909 5992 /*--------------------------------------------------------------------------*/
Chris@909 5993
Chris@909 5994 Element.ClassNames = Class.create();
Chris@909 5995 Element.ClassNames.prototype = {
Chris@909 5996 initialize: function(element) {
Chris@909 5997 this.element = $(element);
Chris@909 5998 },
Chris@909 5999
Chris@909 6000 _each: function(iterator) {
Chris@909 6001 this.element.className.split(/\s+/).select(function(name) {
Chris@909 6002 return name.length > 0;
Chris@909 6003 })._each(iterator);
Chris@909 6004 },
Chris@909 6005
Chris@909 6006 set: function(className) {
Chris@909 6007 this.element.className = className;
Chris@909 6008 },
Chris@909 6009
Chris@909 6010 add: function(classNameToAdd) {
Chris@909 6011 if (this.include(classNameToAdd)) return;
Chris@909 6012 this.set($A(this).concat(classNameToAdd).join(' '));
Chris@909 6013 },
Chris@909 6014
Chris@909 6015 remove: function(classNameToRemove) {
Chris@909 6016 if (!this.include(classNameToRemove)) return;
Chris@909 6017 this.set($A(this).without(classNameToRemove).join(' '));
Chris@909 6018 },
Chris@909 6019
Chris@909 6020 toString: function() {
Chris@909 6021 return $A(this).join(' ');
Chris@909 6022 }
Chris@909 6023 };
Chris@909 6024
Chris@909 6025 Object.extend(Element.ClassNames.prototype, Enumerable);
Chris@909 6026
Chris@909 6027 /*--------------------------------------------------------------------------*/
Chris@909 6028
Chris@909 6029 (function() {
Chris@909 6030 window.Selector = Class.create({
Chris@909 6031 initialize: function(expression) {
Chris@909 6032 this.expression = expression.strip();
Chris@909 6033 },
Chris@909 6034
Chris@909 6035 findElements: function(rootElement) {
Chris@909 6036 return Prototype.Selector.select(this.expression, rootElement);
Chris@909 6037 },
Chris@909 6038
Chris@909 6039 match: function(element) {
Chris@909 6040 return Prototype.Selector.match(element, this.expression);
Chris@909 6041 },
Chris@909 6042
Chris@909 6043 toString: function() {
Chris@909 6044 return this.expression;
Chris@909 6045 },
Chris@909 6046
Chris@909 6047 inspect: function() {
Chris@909 6048 return "#<Selector: " + this.expression + ">";
Chris@909 6049 }
Chris@909 6050 });
Chris@909 6051
Chris@909 6052 Object.extend(Selector, {
Chris@909 6053 matchElements: function(elements, expression) {
Chris@909 6054 var match = Prototype.Selector.match,
Chris@909 6055 results = [];
Chris@909 6056
Chris@909 6057 for (var i = 0, length = elements.length; i < length; i++) {
Chris@909 6058 var element = elements[i];
Chris@909 6059 if (match(element, expression)) {
Chris@909 6060 results.push(Element.extend(element));
Chris@909 6061 }
Chris@909 6062 }
Chris@909 6063 return results;
Chris@909 6064 },
Chris@909 6065
Chris@909 6066 findElement: function(elements, expression, index) {
Chris@909 6067 index = index || 0;
Chris@909 6068 var matchIndex = 0, element;
Chris@909 6069 for (var i = 0, length = elements.length; i < length; i++) {
Chris@909 6070 element = elements[i];
Chris@909 6071 if (Prototype.Selector.match(element, expression) && index === matchIndex++) {
Chris@909 6072 return Element.extend(element);
Chris@909 6073 }
Chris@909 6074 }
Chris@909 6075 },
Chris@909 6076
Chris@909 6077 findChildElements: function(element, expressions) {
Chris@909 6078 var selector = expressions.toArray().join(', ');
Chris@909 6079 return Prototype.Selector.select(selector, element || document);
Chris@909 6080 }
Chris@909 6081 });
Chris@909 6082 })();