bivouac 0.1.4 → 0.1.5

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