static 0.1.0 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3277 @@
1
+ /* Prototype JavaScript framework, version 1.5.1.1
2
+ * (c) 2005-2007 Sam Stephenson
3
+ *
4
+ * Prototype is freely distributable under the terms of an MIT-style license.
5
+ * For details, see the Prototype web site: http://www.prototypejs.org/
6
+ *
7
+ /*--------------------------------------------------------------------------*/
8
+
9
+ var Prototype = {
10
+ Version: '1.5.1.1',
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
+ },
18
+
19
+ BrowserFeatures: {
20
+ XPath: !!document.evaluate,
21
+ ElementExtensions: !!window.HTMLElement,
22
+ SpecificElementExtensions:
23
+ (document.createElement('div').__proto__ !==
24
+ document.createElement('form').__proto__)
25
+ },
26
+
27
+ ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
28
+ JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
29
+
30
+ emptyFunction: function() { },
31
+ K: function(x) { return x }
32
+ }
33
+
34
+ var Class = {
35
+ create: function() {
36
+ return function() {
37
+ this.initialize.apply(this, arguments);
38
+ }
39
+ }
40
+ }
41
+
42
+ var Abstract = new Object();
43
+
44
+ Object.extend = function(destination, source) {
45
+ for (var property in source) {
46
+ destination[property] = source[property];
47
+ }
48
+ return destination;
49
+ }
50
+
51
+ Object.extend(Object, {
52
+ inspect: function(object) {
53
+ try {
54
+ if (object === undefined) return 'undefined';
55
+ if (object === null) return 'null';
56
+ return object.inspect ? object.inspect() : object.toString();
57
+ } catch (e) {
58
+ if (e instanceof RangeError) return '...';
59
+ throw e;
60
+ }
61
+ },
62
+
63
+ toJSON: function(object) {
64
+ var type = typeof object;
65
+ switch(type) {
66
+ case 'undefined':
67
+ case 'function':
68
+ case 'unknown': return;
69
+ case 'boolean': return object.toString();
70
+ }
71
+ if (object === null) return 'null';
72
+ if (object.toJSON) return object.toJSON();
73
+ if (object.ownerDocument === document) return;
74
+ var results = [];
75
+ for (var property in object) {
76
+ var value = Object.toJSON(object[property]);
77
+ if (value !== undefined)
78
+ results.push(property.toJSON() + ': ' + value);
79
+ }
80
+ return '{' + results.join(', ') + '}';
81
+ },
82
+
83
+ keys: function(object) {
84
+ var keys = [];
85
+ for (var property in object)
86
+ keys.push(property);
87
+ return keys;
88
+ },
89
+
90
+ values: function(object) {
91
+ var values = [];
92
+ for (var property in object)
93
+ values.push(object[property]);
94
+ return values;
95
+ },
96
+
97
+ clone: function(object) {
98
+ return Object.extend({}, object);
99
+ }
100
+ });
101
+
102
+ Function.prototype.bind = function() {
103
+ var __method = this, args = $A(arguments), object = args.shift();
104
+ return function() {
105
+ return __method.apply(object, args.concat($A(arguments)));
106
+ }
107
+ }
108
+
109
+ Function.prototype.bindAsEventListener = function(object) {
110
+ var __method = this, args = $A(arguments), object = args.shift();
111
+ return function(event) {
112
+ return __method.apply(object, [event || window.event].concat(args));
113
+ }
114
+ }
115
+
116
+ Object.extend(Number.prototype, {
117
+ toColorPart: function() {
118
+ return this.toPaddedString(2, 16);
119
+ },
120
+
121
+ succ: function() {
122
+ return this + 1;
123
+ },
124
+
125
+ times: function(iterator) {
126
+ $R(0, this, true).each(iterator);
127
+ return this;
128
+ },
129
+
130
+ toPaddedString: function(length, radix) {
131
+ var string = this.toString(radix || 10);
132
+ return '0'.times(length - string.length) + string;
133
+ },
134
+
135
+ toJSON: function() {
136
+ return isFinite(this) ? this.toString() : 'null';
137
+ }
138
+ });
139
+
140
+ Date.prototype.toJSON = function() {
141
+ return '"' + this.getFullYear() + '-' +
142
+ (this.getMonth() + 1).toPaddedString(2) + '-' +
143
+ this.getDate().toPaddedString(2) + 'T' +
144
+ this.getHours().toPaddedString(2) + ':' +
145
+ this.getMinutes().toPaddedString(2) + ':' +
146
+ this.getSeconds().toPaddedString(2) + '"';
147
+ };
148
+
149
+ var Try = {
150
+ these: function() {
151
+ var returnValue;
152
+
153
+ for (var i = 0, length = arguments.length; i < length; i++) {
154
+ var lambda = arguments[i];
155
+ try {
156
+ returnValue = lambda();
157
+ break;
158
+ } catch (e) {}
159
+ }
160
+
161
+ return returnValue;
162
+ }
163
+ }
164
+
165
+ /*--------------------------------------------------------------------------*/
166
+
167
+ var PeriodicalExecuter = Class.create();
168
+ PeriodicalExecuter.prototype = {
169
+ initialize: function(callback, frequency) {
170
+ this.callback = callback;
171
+ this.frequency = frequency;
172
+ this.currentlyExecuting = false;
173
+
174
+ this.registerCallback();
175
+ },
176
+
177
+ registerCallback: function() {
178
+ this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
179
+ },
180
+
181
+ stop: function() {
182
+ if (!this.timer) return;
183
+ clearInterval(this.timer);
184
+ this.timer = null;
185
+ },
186
+
187
+ onTimerEvent: function() {
188
+ if (!this.currentlyExecuting) {
189
+ try {
190
+ this.currentlyExecuting = true;
191
+ this.callback(this);
192
+ } finally {
193
+ this.currentlyExecuting = false;
194
+ }
195
+ }
196
+ }
197
+ }
198
+ Object.extend(String, {
199
+ interpret: function(value) {
200
+ return value == null ? '' : String(value);
201
+ },
202
+ specialChar: {
203
+ '\b': '\\b',
204
+ '\t': '\\t',
205
+ '\n': '\\n',
206
+ '\f': '\\f',
207
+ '\r': '\\r',
208
+ '\\': '\\\\'
209
+ }
210
+ });
211
+
212
+ Object.extend(String.prototype, {
213
+ gsub: function(pattern, replacement) {
214
+ var result = '', source = this, match;
215
+ replacement = arguments.callee.prepareReplacement(replacement);
216
+
217
+ while (source.length > 0) {
218
+ if (match = source.match(pattern)) {
219
+ result += source.slice(0, match.index);
220
+ result += String.interpret(replacement(match));
221
+ source = source.slice(match.index + match[0].length);
222
+ } else {
223
+ result += source, source = '';
224
+ }
225
+ }
226
+ return result;
227
+ },
228
+
229
+ sub: function(pattern, replacement, count) {
230
+ replacement = this.gsub.prepareReplacement(replacement);
231
+ count = count === undefined ? 1 : count;
232
+
233
+ return this.gsub(pattern, function(match) {
234
+ if (--count < 0) return match[0];
235
+ return replacement(match);
236
+ });
237
+ },
238
+
239
+ scan: function(pattern, iterator) {
240
+ this.gsub(pattern, iterator);
241
+ return this;
242
+ },
243
+
244
+ truncate: function(length, truncation) {
245
+ length = length || 30;
246
+ truncation = truncation === undefined ? '...' : truncation;
247
+ return this.length > length ?
248
+ this.slice(0, length - truncation.length) + truncation : this;
249
+ },
250
+
251
+ strip: function() {
252
+ return this.replace(/^\s+/, '').replace(/\s+$/, '');
253
+ },
254
+
255
+ stripTags: function() {
256
+ return this.replace(/<\/?[^>]+>/gi, '');
257
+ },
258
+
259
+ stripScripts: function() {
260
+ return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
261
+ },
262
+
263
+ extractScripts: function() {
264
+ var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
265
+ var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
266
+ return (this.match(matchAll) || []).map(function(scriptTag) {
267
+ return (scriptTag.match(matchOne) || ['', ''])[1];
268
+ });
269
+ },
270
+
271
+ evalScripts: function() {
272
+ return this.extractScripts().map(function(script) { return eval(script) });
273
+ },
274
+
275
+ escapeHTML: function() {
276
+ var self = arguments.callee;
277
+ self.text.data = this;
278
+ return self.div.innerHTML;
279
+ },
280
+
281
+ unescapeHTML: function() {
282
+ var div = document.createElement('div');
283
+ div.innerHTML = this.stripTags();
284
+ return div.childNodes[0] ? (div.childNodes.length > 1 ?
285
+ $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
286
+ div.childNodes[0].nodeValue) : '';
287
+ },
288
+
289
+ toQueryParams: function(separator) {
290
+ var match = this.strip().match(/([^?#]*)(#.*)?$/);
291
+ if (!match) return {};
292
+
293
+ return match[1].split(separator || '&').inject({}, function(hash, pair) {
294
+ if ((pair = pair.split('='))[0]) {
295
+ var key = decodeURIComponent(pair.shift());
296
+ var value = pair.length > 1 ? pair.join('=') : pair[0];
297
+ if (value != undefined) value = decodeURIComponent(value);
298
+
299
+ if (key in hash) {
300
+ if (hash[key].constructor != Array) hash[key] = [hash[key]];
301
+ hash[key].push(value);
302
+ }
303
+ else hash[key] = value;
304
+ }
305
+ return hash;
306
+ });
307
+ },
308
+
309
+ toArray: function() {
310
+ return this.split('');
311
+ },
312
+
313
+ succ: function() {
314
+ return this.slice(0, this.length - 1) +
315
+ String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
316
+ },
317
+
318
+ times: function(count) {
319
+ var result = '';
320
+ for (var i = 0; i < count; i++) result += this;
321
+ return result;
322
+ },
323
+
324
+ camelize: function() {
325
+ var parts = this.split('-'), len = parts.length;
326
+ if (len == 1) return parts[0];
327
+
328
+ var camelized = this.charAt(0) == '-'
329
+ ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
330
+ : parts[0];
331
+
332
+ for (var i = 1; i < len; i++)
333
+ camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
334
+
335
+ return camelized;
336
+ },
337
+
338
+ capitalize: function() {
339
+ return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
340
+ },
341
+
342
+ underscore: function() {
343
+ return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
344
+ },
345
+
346
+ dasherize: function() {
347
+ return this.gsub(/_/,'-');
348
+ },
349
+
350
+ inspect: function(useDoubleQuotes) {
351
+ var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
352
+ var character = String.specialChar[match[0]];
353
+ return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
354
+ });
355
+ if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
356
+ return "'" + escapedString.replace(/'/g, '\\\'') + "'";
357
+ },
358
+
359
+ toJSON: function() {
360
+ return this.inspect(true);
361
+ },
362
+
363
+ unfilterJSON: function(filter) {
364
+ return this.sub(filter || Prototype.JSONFilter, '#{1}');
365
+ },
366
+
367
+ isJSON: function() {
368
+ var str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
369
+ return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
370
+ },
371
+
372
+ evalJSON: function(sanitize) {
373
+ var json = this.unfilterJSON();
374
+ try {
375
+ if (!sanitize || json.isJSON()) return eval('(' + json + ')');
376
+ } catch (e) { }
377
+ throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
378
+ },
379
+
380
+ include: function(pattern) {
381
+ return this.indexOf(pattern) > -1;
382
+ },
383
+
384
+ startsWith: function(pattern) {
385
+ return this.indexOf(pattern) === 0;
386
+ },
387
+
388
+ endsWith: function(pattern) {
389
+ var d = this.length - pattern.length;
390
+ return d >= 0 && this.lastIndexOf(pattern) === d;
391
+ },
392
+
393
+ empty: function() {
394
+ return this == '';
395
+ },
396
+
397
+ blank: function() {
398
+ return /^\s*$/.test(this);
399
+ }
400
+ });
401
+
402
+ if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
403
+ escapeHTML: function() {
404
+ return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
405
+ },
406
+ unescapeHTML: function() {
407
+ return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
408
+ }
409
+ });
410
+
411
+ String.prototype.gsub.prepareReplacement = function(replacement) {
412
+ if (typeof replacement == 'function') return replacement;
413
+ var template = new Template(replacement);
414
+ return function(match) { return template.evaluate(match) };
415
+ }
416
+
417
+ String.prototype.parseQuery = String.prototype.toQueryParams;
418
+
419
+ Object.extend(String.prototype.escapeHTML, {
420
+ div: document.createElement('div'),
421
+ text: document.createTextNode('')
422
+ });
423
+
424
+ with (String.prototype.escapeHTML) div.appendChild(text);
425
+
426
+ var Template = Class.create();
427
+ Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
428
+ Template.prototype = {
429
+ initialize: function(template, pattern) {
430
+ this.template = template.toString();
431
+ this.pattern = pattern || Template.Pattern;
432
+ },
433
+
434
+ evaluate: function(object) {
435
+ return this.template.gsub(this.pattern, function(match) {
436
+ var before = match[1];
437
+ if (before == '\\') return match[2];
438
+ return before + String.interpret(object[match[3]]);
439
+ });
440
+ }
441
+ }
442
+
443
+ var $break = {}, $continue = new Error('"throw $continue" is deprecated, use "return" instead');
444
+
445
+ var Enumerable = {
446
+ each: function(iterator) {
447
+ var index = 0;
448
+ try {
449
+ this._each(function(value) {
450
+ iterator(value, index++);
451
+ });
452
+ } catch (e) {
453
+ if (e != $break) throw e;
454
+ }
455
+ return this;
456
+ },
457
+
458
+ eachSlice: function(number, iterator) {
459
+ var index = -number, slices = [], array = this.toArray();
460
+ while ((index += number) < array.length)
461
+ slices.push(array.slice(index, index+number));
462
+ return slices.map(iterator);
463
+ },
464
+
465
+ all: function(iterator) {
466
+ var result = true;
467
+ this.each(function(value, index) {
468
+ result = result && !!(iterator || Prototype.K)(value, index);
469
+ if (!result) throw $break;
470
+ });
471
+ return result;
472
+ },
473
+
474
+ any: function(iterator) {
475
+ var result = false;
476
+ this.each(function(value, index) {
477
+ if (result = !!(iterator || Prototype.K)(value, index))
478
+ throw $break;
479
+ });
480
+ return result;
481
+ },
482
+
483
+ collect: function(iterator) {
484
+ var results = [];
485
+ this.each(function(value, index) {
486
+ results.push((iterator || Prototype.K)(value, index));
487
+ });
488
+ return results;
489
+ },
490
+
491
+ detect: function(iterator) {
492
+ var result;
493
+ this.each(function(value, index) {
494
+ if (iterator(value, index)) {
495
+ result = value;
496
+ throw $break;
497
+ }
498
+ });
499
+ return result;
500
+ },
501
+
502
+ findAll: function(iterator) {
503
+ var results = [];
504
+ this.each(function(value, index) {
505
+ if (iterator(value, index))
506
+ results.push(value);
507
+ });
508
+ return results;
509
+ },
510
+
511
+ grep: function(pattern, iterator) {
512
+ var results = [];
513
+ this.each(function(value, index) {
514
+ var stringValue = value.toString();
515
+ if (stringValue.match(pattern))
516
+ results.push((iterator || Prototype.K)(value, index));
517
+ })
518
+ return results;
519
+ },
520
+
521
+ include: function(object) {
522
+ var found = false;
523
+ this.each(function(value) {
524
+ if (value == object) {
525
+ found = true;
526
+ throw $break;
527
+ }
528
+ });
529
+ return found;
530
+ },
531
+
532
+ inGroupsOf: function(number, fillWith) {
533
+ fillWith = fillWith === undefined ? null : fillWith;
534
+ return this.eachSlice(number, function(slice) {
535
+ while(slice.length < number) slice.push(fillWith);
536
+ return slice;
537
+ });
538
+ },
539
+
540
+ inject: function(memo, iterator) {
541
+ this.each(function(value, index) {
542
+ memo = iterator(memo, value, index);
543
+ });
544
+ return memo;
545
+ },
546
+
547
+ invoke: function(method) {
548
+ var args = $A(arguments).slice(1);
549
+ return this.map(function(value) {
550
+ return value[method].apply(value, args);
551
+ });
552
+ },
553
+
554
+ max: function(iterator) {
555
+ var result;
556
+ this.each(function(value, index) {
557
+ value = (iterator || Prototype.K)(value, index);
558
+ if (result == undefined || value >= result)
559
+ result = value;
560
+ });
561
+ return result;
562
+ },
563
+
564
+ min: function(iterator) {
565
+ var result;
566
+ this.each(function(value, index) {
567
+ value = (iterator || Prototype.K)(value, index);
568
+ if (result == undefined || value < result)
569
+ result = value;
570
+ });
571
+ return result;
572
+ },
573
+
574
+ partition: function(iterator) {
575
+ var trues = [], falses = [];
576
+ this.each(function(value, index) {
577
+ ((iterator || Prototype.K)(value, index) ?
578
+ trues : falses).push(value);
579
+ });
580
+ return [trues, falses];
581
+ },
582
+
583
+ pluck: function(property) {
584
+ var results = [];
585
+ this.each(function(value, index) {
586
+ results.push(value[property]);
587
+ });
588
+ return results;
589
+ },
590
+
591
+ reject: function(iterator) {
592
+ var results = [];
593
+ this.each(function(value, index) {
594
+ if (!iterator(value, index))
595
+ results.push(value);
596
+ });
597
+ return results;
598
+ },
599
+
600
+ sortBy: function(iterator) {
601
+ return this.map(function(value, index) {
602
+ return {value: value, criteria: iterator(value, index)};
603
+ }).sort(function(left, right) {
604
+ var a = left.criteria, b = right.criteria;
605
+ return a < b ? -1 : a > b ? 1 : 0;
606
+ }).pluck('value');
607
+ },
608
+
609
+ toArray: function() {
610
+ return this.map();
611
+ },
612
+
613
+ zip: function() {
614
+ var iterator = Prototype.K, args = $A(arguments);
615
+ if (typeof args.last() == 'function')
616
+ iterator = args.pop();
617
+
618
+ var collections = [this].concat(args).map($A);
619
+ return this.map(function(value, index) {
620
+ return iterator(collections.pluck(index));
621
+ });
622
+ },
623
+
624
+ size: function() {
625
+ return this.toArray().length;
626
+ },
627
+
628
+ inspect: function() {
629
+ return '#<Enumerable:' + this.toArray().inspect() + '>';
630
+ }
631
+ }
632
+
633
+ Object.extend(Enumerable, {
634
+ map: Enumerable.collect,
635
+ find: Enumerable.detect,
636
+ select: Enumerable.findAll,
637
+ member: Enumerable.include,
638
+ entries: Enumerable.toArray
639
+ });
640
+ var $A = Array.from = function(iterable) {
641
+ if (!iterable) return [];
642
+ if (iterable.toArray) {
643
+ return iterable.toArray();
644
+ } else {
645
+ var results = [];
646
+ for (var i = 0, length = iterable.length; i < length; i++)
647
+ results.push(iterable[i]);
648
+ return results;
649
+ }
650
+ }
651
+
652
+ if (Prototype.Browser.WebKit) {
653
+ $A = Array.from = function(iterable) {
654
+ if (!iterable) return [];
655
+ if (!(typeof iterable == 'function' && iterable == '[object NodeList]') &&
656
+ iterable.toArray) {
657
+ return iterable.toArray();
658
+ } else {
659
+ var results = [];
660
+ for (var i = 0, length = iterable.length; i < length; i++)
661
+ results.push(iterable[i]);
662
+ return results;
663
+ }
664
+ }
665
+ }
666
+
667
+ Object.extend(Array.prototype, Enumerable);
668
+
669
+ if (!Array.prototype._reverse)
670
+ Array.prototype._reverse = Array.prototype.reverse;
671
+
672
+ Object.extend(Array.prototype, {
673
+ _each: function(iterator) {
674
+ for (var i = 0, length = this.length; i < length; i++)
675
+ iterator(this[i]);
676
+ },
677
+
678
+ clear: function() {
679
+ this.length = 0;
680
+ return this;
681
+ },
682
+
683
+ first: function() {
684
+ return this[0];
685
+ },
686
+
687
+ last: function() {
688
+ return this[this.length - 1];
689
+ },
690
+
691
+ compact: function() {
692
+ return this.select(function(value) {
693
+ return value != null;
694
+ });
695
+ },
696
+
697
+ flatten: function() {
698
+ return this.inject([], function(array, value) {
699
+ return array.concat(value && value.constructor == Array ?
700
+ value.flatten() : [value]);
701
+ });
702
+ },
703
+
704
+ without: function() {
705
+ var values = $A(arguments);
706
+ return this.select(function(value) {
707
+ return !values.include(value);
708
+ });
709
+ },
710
+
711
+ indexOf: function(object) {
712
+ for (var i = 0, length = this.length; i < length; i++)
713
+ if (this[i] == object) return i;
714
+ return -1;
715
+ },
716
+
717
+ reverse: function(inline) {
718
+ return (inline !== false ? this : this.toArray())._reverse();
719
+ },
720
+
721
+ reduce: function() {
722
+ return this.length > 1 ? this : this[0];
723
+ },
724
+
725
+ uniq: function(sorted) {
726
+ return this.inject([], function(array, value, index) {
727
+ if (0 == index || (sorted ? array.last() != value : !array.include(value)))
728
+ array.push(value);
729
+ return array;
730
+ });
731
+ },
732
+
733
+ clone: function() {
734
+ return [].concat(this);
735
+ },
736
+
737
+ size: function() {
738
+ return this.length;
739
+ },
740
+
741
+ inspect: function() {
742
+ return '[' + this.map(Object.inspect).join(', ') + ']';
743
+ },
744
+
745
+ toJSON: function() {
746
+ var results = [];
747
+ this.each(function(object) {
748
+ var value = Object.toJSON(object);
749
+ if (value !== undefined) results.push(value);
750
+ });
751
+ return '[' + results.join(', ') + ']';
752
+ }
753
+ });
754
+
755
+ Array.prototype.toArray = Array.prototype.clone;
756
+
757
+ function $w(string) {
758
+ string = string.strip();
759
+ return string ? string.split(/\s+/) : [];
760
+ }
761
+
762
+ if (Prototype.Browser.Opera){
763
+ Array.prototype.concat = function() {
764
+ var array = [];
765
+ for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
766
+ for (var i = 0, length = arguments.length; i < length; i++) {
767
+ if (arguments[i].constructor == Array) {
768
+ for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
769
+ array.push(arguments[i][j]);
770
+ } else {
771
+ array.push(arguments[i]);
772
+ }
773
+ }
774
+ return array;
775
+ }
776
+ }
777
+ var Hash = function(object) {
778
+ if (object instanceof Hash) this.merge(object);
779
+ else Object.extend(this, object || {});
780
+ };
781
+
782
+ Object.extend(Hash, {
783
+ toQueryString: function(obj) {
784
+ var parts = [];
785
+ parts.add = arguments.callee.addPair;
786
+
787
+ this.prototype._each.call(obj, function(pair) {
788
+ if (!pair.key) return;
789
+ var value = pair.value;
790
+
791
+ if (value && typeof value == 'object') {
792
+ if (value.constructor == Array) value.each(function(value) {
793
+ parts.add(pair.key, value);
794
+ });
795
+ return;
796
+ }
797
+ parts.add(pair.key, value);
798
+ });
799
+
800
+ return parts.join('&');
801
+ },
802
+
803
+ toJSON: function(object) {
804
+ var results = [];
805
+ this.prototype._each.call(object, function(pair) {
806
+ var value = Object.toJSON(pair.value);
807
+ if (value !== undefined) results.push(pair.key.toJSON() + ': ' + value);
808
+ });
809
+ return '{' + results.join(', ') + '}';
810
+ }
811
+ });
812
+
813
+ Hash.toQueryString.addPair = function(key, value, prefix) {
814
+ key = encodeURIComponent(key);
815
+ if (value === undefined) this.push(key);
816
+ else this.push(key + '=' + (value == null ? '' : encodeURIComponent(value)));
817
+ }
818
+
819
+ Object.extend(Hash.prototype, Enumerable);
820
+ Object.extend(Hash.prototype, {
821
+ _each: function(iterator) {
822
+ for (var key in this) {
823
+ var value = this[key];
824
+ if (value && value == Hash.prototype[key]) continue;
825
+
826
+ var pair = [key, value];
827
+ pair.key = key;
828
+ pair.value = value;
829
+ iterator(pair);
830
+ }
831
+ },
832
+
833
+ keys: function() {
834
+ return this.pluck('key');
835
+ },
836
+
837
+ values: function() {
838
+ return this.pluck('value');
839
+ },
840
+
841
+ merge: function(hash) {
842
+ return $H(hash).inject(this, function(mergedHash, pair) {
843
+ mergedHash[pair.key] = pair.value;
844
+ return mergedHash;
845
+ });
846
+ },
847
+
848
+ remove: function() {
849
+ var result;
850
+ for(var i = 0, length = arguments.length; i < length; i++) {
851
+ var value = this[arguments[i]];
852
+ if (value !== undefined){
853
+ if (result === undefined) result = value;
854
+ else {
855
+ if (result.constructor != Array) result = [result];
856
+ result.push(value)
857
+ }
858
+ }
859
+ delete this[arguments[i]];
860
+ }
861
+ return result;
862
+ },
863
+
864
+ toQueryString: function() {
865
+ return Hash.toQueryString(this);
866
+ },
867
+
868
+ inspect: function() {
869
+ return '#<Hash:{' + this.map(function(pair) {
870
+ return pair.map(Object.inspect).join(': ');
871
+ }).join(', ') + '}>';
872
+ },
873
+
874
+ toJSON: function() {
875
+ return Hash.toJSON(this);
876
+ }
877
+ });
878
+
879
+ function $H(object) {
880
+ if (object instanceof Hash) return object;
881
+ return new Hash(object);
882
+ };
883
+
884
+ // Safari iterates over shadowed properties
885
+ if (function() {
886
+ var i = 0, Test = function(value) { this.key = value };
887
+ Test.prototype.key = 'foo';
888
+ for (var property in new Test('bar')) i++;
889
+ return i > 1;
890
+ }()) Hash.prototype._each = function(iterator) {
891
+ var cache = [];
892
+ for (var key in this) {
893
+ var value = this[key];
894
+ if ((value && value == Hash.prototype[key]) || cache.include(key)) continue;
895
+ cache.push(key);
896
+ var pair = [key, value];
897
+ pair.key = key;
898
+ pair.value = value;
899
+ iterator(pair);
900
+ }
901
+ };
902
+ ObjectRange = Class.create();
903
+ Object.extend(ObjectRange.prototype, Enumerable);
904
+ Object.extend(ObjectRange.prototype, {
905
+ initialize: function(start, end, exclusive) {
906
+ this.start = start;
907
+ this.end = end;
908
+ this.exclusive = exclusive;
909
+ },
910
+
911
+ _each: function(iterator) {
912
+ var value = this.start;
913
+ while (this.include(value)) {
914
+ iterator(value);
915
+ value = value.succ();
916
+ }
917
+ },
918
+
919
+ include: function(value) {
920
+ if (value < this.start)
921
+ return false;
922
+ if (this.exclusive)
923
+ return value < this.end;
924
+ return value <= this.end;
925
+ }
926
+ });
927
+
928
+ var $R = function(start, end, exclusive) {
929
+ return new ObjectRange(start, end, exclusive);
930
+ }
931
+
932
+ var Ajax = {
933
+ getTransport: function() {
934
+ return Try.these(
935
+ function() {return new XMLHttpRequest()},
936
+ function() {return new ActiveXObject('Msxml2.XMLHTTP')},
937
+ function() {return new ActiveXObject('Microsoft.XMLHTTP')}
938
+ ) || false;
939
+ },
940
+
941
+ activeRequestCount: 0
942
+ }
943
+
944
+ Ajax.Responders = {
945
+ responders: [],
946
+
947
+ _each: function(iterator) {
948
+ this.responders._each(iterator);
949
+ },
950
+
951
+ register: function(responder) {
952
+ if (!this.include(responder))
953
+ this.responders.push(responder);
954
+ },
955
+
956
+ unregister: function(responder) {
957
+ this.responders = this.responders.without(responder);
958
+ },
959
+
960
+ dispatch: function(callback, request, transport, json) {
961
+ this.each(function(responder) {
962
+ if (typeof responder[callback] == 'function') {
963
+ try {
964
+ responder[callback].apply(responder, [request, transport, json]);
965
+ } catch (e) {}
966
+ }
967
+ });
968
+ }
969
+ };
970
+
971
+ Object.extend(Ajax.Responders, Enumerable);
972
+
973
+ Ajax.Responders.register({
974
+ onCreate: function() {
975
+ Ajax.activeRequestCount++;
976
+ },
977
+ onComplete: function() {
978
+ Ajax.activeRequestCount--;
979
+ }
980
+ });
981
+
982
+ Ajax.Base = function() {};
983
+ Ajax.Base.prototype = {
984
+ setOptions: function(options) {
985
+ this.options = {
986
+ method: 'post',
987
+ asynchronous: true,
988
+ contentType: 'application/x-www-form-urlencoded',
989
+ encoding: 'UTF-8',
990
+ parameters: ''
991
+ }
992
+ Object.extend(this.options, options || {});
993
+
994
+ this.options.method = this.options.method.toLowerCase();
995
+ if (typeof this.options.parameters == 'string')
996
+ this.options.parameters = this.options.parameters.toQueryParams();
997
+ }
998
+ }
999
+
1000
+ Ajax.Request = Class.create();
1001
+ Ajax.Request.Events =
1002
+ ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
1003
+
1004
+ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
1005
+ _complete: false,
1006
+
1007
+ initialize: function(url, options) {
1008
+ this.transport = Ajax.getTransport();
1009
+ this.setOptions(options);
1010
+ this.request(url);
1011
+ },
1012
+
1013
+ request: function(url) {
1014
+ this.url = url;
1015
+ this.method = this.options.method;
1016
+ var params = Object.clone(this.options.parameters);
1017
+
1018
+ if (!['get', 'post'].include(this.method)) {
1019
+ // simulate other verbs over post
1020
+ params['_method'] = this.method;
1021
+ this.method = 'post';
1022
+ }
1023
+
1024
+ this.parameters = params;
1025
+
1026
+ if (params = Hash.toQueryString(params)) {
1027
+ // when GET, append parameters to URL
1028
+ if (this.method == 'get')
1029
+ this.url += (this.url.include('?') ? '&' : '?') + params;
1030
+ else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
1031
+ params += '&_=';
1032
+ }
1033
+
1034
+ try {
1035
+ if (this.options.onCreate) this.options.onCreate(this.transport);
1036
+ Ajax.Responders.dispatch('onCreate', this, this.transport);
1037
+
1038
+ this.transport.open(this.method.toUpperCase(), this.url,
1039
+ this.options.asynchronous);
1040
+
1041
+ if (this.options.asynchronous)
1042
+ setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
1043
+
1044
+ this.transport.onreadystatechange = this.onStateChange.bind(this);
1045
+ this.setRequestHeaders();
1046
+
1047
+ this.body = this.method == 'post' ? (this.options.postBody || params) : null;
1048
+ this.transport.send(this.body);
1049
+
1050
+ /* Force Firefox to handle ready state 4 for synchronous requests */
1051
+ if (!this.options.asynchronous && this.transport.overrideMimeType)
1052
+ this.onStateChange();
1053
+
1054
+ }
1055
+ catch (e) {
1056
+ this.dispatchException(e);
1057
+ }
1058
+ },
1059
+
1060
+ onStateChange: function() {
1061
+ var readyState = this.transport.readyState;
1062
+ if (readyState > 1 && !((readyState == 4) && this._complete))
1063
+ this.respondToReadyState(this.transport.readyState);
1064
+ },
1065
+
1066
+ setRequestHeaders: function() {
1067
+ var headers = {
1068
+ 'X-Requested-With': 'XMLHttpRequest',
1069
+ 'X-Prototype-Version': Prototype.Version,
1070
+ 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
1071
+ };
1072
+
1073
+ if (this.method == 'post') {
1074
+ headers['Content-type'] = this.options.contentType +
1075
+ (this.options.encoding ? '; charset=' + this.options.encoding : '');
1076
+
1077
+ /* Force "Connection: close" for older Mozilla browsers to work
1078
+ * around a bug where XMLHttpRequest sends an incorrect
1079
+ * Content-length header. See Mozilla Bugzilla #246651.
1080
+ */
1081
+ if (this.transport.overrideMimeType &&
1082
+ (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
1083
+ headers['Connection'] = 'close';
1084
+ }
1085
+
1086
+ // user-defined headers
1087
+ if (typeof this.options.requestHeaders == 'object') {
1088
+ var extras = this.options.requestHeaders;
1089
+
1090
+ if (typeof extras.push == 'function')
1091
+ for (var i = 0, length = extras.length; i < length; i += 2)
1092
+ headers[extras[i]] = extras[i+1];
1093
+ else
1094
+ $H(extras).each(function(pair) { headers[pair.key] = pair.value });
1095
+ }
1096
+
1097
+ for (var name in headers)
1098
+ this.transport.setRequestHeader(name, headers[name]);
1099
+ },
1100
+
1101
+ success: function() {
1102
+ return !this.transport.status
1103
+ || (this.transport.status >= 200 && this.transport.status < 300);
1104
+ },
1105
+
1106
+ respondToReadyState: function(readyState) {
1107
+ var state = Ajax.Request.Events[readyState];
1108
+ var transport = this.transport, json = this.evalJSON();
1109
+
1110
+ if (state == 'Complete') {
1111
+ try {
1112
+ this._complete = true;
1113
+ (this.options['on' + this.transport.status]
1114
+ || this.options['on' + (this.success() ? 'Success' : 'Failure')]
1115
+ || Prototype.emptyFunction)(transport, json);
1116
+ } catch (e) {
1117
+ this.dispatchException(e);
1118
+ }
1119
+
1120
+ var contentType = this.getHeader('Content-type');
1121
+ if (contentType && contentType.strip().
1122
+ match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
1123
+ this.evalResponse();
1124
+ }
1125
+
1126
+ try {
1127
+ (this.options['on' + state] || Prototype.emptyFunction)(transport, json);
1128
+ Ajax.Responders.dispatch('on' + state, this, transport, json);
1129
+ } catch (e) {
1130
+ this.dispatchException(e);
1131
+ }
1132
+
1133
+ if (state == 'Complete') {
1134
+ // avoid memory leak in MSIE: clean up
1135
+ this.transport.onreadystatechange = Prototype.emptyFunction;
1136
+ }
1137
+ },
1138
+
1139
+ getHeader: function(name) {
1140
+ try {
1141
+ return this.transport.getResponseHeader(name);
1142
+ } catch (e) { return null }
1143
+ },
1144
+
1145
+ evalJSON: function() {
1146
+ try {
1147
+ var json = this.getHeader('X-JSON');
1148
+ return json ? json.evalJSON() : null;
1149
+ } catch (e) { return null }
1150
+ },
1151
+
1152
+ evalResponse: function() {
1153
+ try {
1154
+ return eval((this.transport.responseText || '').unfilterJSON());
1155
+ } catch (e) {
1156
+ this.dispatchException(e);
1157
+ }
1158
+ },
1159
+
1160
+ dispatchException: function(exception) {
1161
+ (this.options.onException || Prototype.emptyFunction)(this, exception);
1162
+ Ajax.Responders.dispatch('onException', this, exception);
1163
+ }
1164
+ });
1165
+
1166
+ Ajax.Updater = Class.create();
1167
+
1168
+ Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
1169
+ initialize: function(container, url, options) {
1170
+ this.container = {
1171
+ success: (container.success || container),
1172
+ failure: (container.failure || (container.success ? null : container))
1173
+ }
1174
+
1175
+ this.transport = Ajax.getTransport();
1176
+ this.setOptions(options);
1177
+
1178
+ var onComplete = this.options.onComplete || Prototype.emptyFunction;
1179
+ this.options.onComplete = (function(transport, param) {
1180
+ this.updateContent();
1181
+ onComplete(transport, param);
1182
+ }).bind(this);
1183
+
1184
+ this.request(url);
1185
+ },
1186
+
1187
+ updateContent: function() {
1188
+ var receiver = this.container[this.success() ? 'success' : 'failure'];
1189
+ var response = this.transport.responseText;
1190
+
1191
+ if (!this.options.evalScripts) response = response.stripScripts();
1192
+
1193
+ if (receiver = $(receiver)) {
1194
+ if (this.options.insertion)
1195
+ new this.options.insertion(receiver, response);
1196
+ else
1197
+ receiver.update(response);
1198
+ }
1199
+
1200
+ if (this.success()) {
1201
+ if (this.onComplete)
1202
+ setTimeout(this.onComplete.bind(this), 10);
1203
+ }
1204
+ }
1205
+ });
1206
+
1207
+ Ajax.PeriodicalUpdater = Class.create();
1208
+ Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
1209
+ initialize: function(container, url, options) {
1210
+ this.setOptions(options);
1211
+ this.onComplete = this.options.onComplete;
1212
+
1213
+ this.frequency = (this.options.frequency || 2);
1214
+ this.decay = (this.options.decay || 1);
1215
+
1216
+ this.updater = {};
1217
+ this.container = container;
1218
+ this.url = url;
1219
+
1220
+ this.start();
1221
+ },
1222
+
1223
+ start: function() {
1224
+ this.options.onComplete = this.updateComplete.bind(this);
1225
+ this.onTimerEvent();
1226
+ },
1227
+
1228
+ stop: function() {
1229
+ this.updater.options.onComplete = undefined;
1230
+ clearTimeout(this.timer);
1231
+ (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
1232
+ },
1233
+
1234
+ updateComplete: function(request) {
1235
+ if (this.options.decay) {
1236
+ this.decay = (request.responseText == this.lastText ?
1237
+ this.decay * this.options.decay : 1);
1238
+
1239
+ this.lastText = request.responseText;
1240
+ }
1241
+ this.timer = setTimeout(this.onTimerEvent.bind(this),
1242
+ this.decay * this.frequency * 1000);
1243
+ },
1244
+
1245
+ onTimerEvent: function() {
1246
+ this.updater = new Ajax.Updater(this.container, this.url, this.options);
1247
+ }
1248
+ });
1249
+ function $(element) {
1250
+ if (arguments.length > 1) {
1251
+ for (var i = 0, elements = [], length = arguments.length; i < length; i++)
1252
+ elements.push($(arguments[i]));
1253
+ return elements;
1254
+ }
1255
+ if (typeof element == 'string')
1256
+ element = document.getElementById(element);
1257
+ return Element.extend(element);
1258
+ }
1259
+
1260
+ if (Prototype.BrowserFeatures.XPath) {
1261
+ document._getElementsByXPath = function(expression, parentElement) {
1262
+ var results = [];
1263
+ var query = document.evaluate(expression, $(parentElement) || document,
1264
+ null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
1265
+ for (var i = 0, length = query.snapshotLength; i < length; i++)
1266
+ results.push(query.snapshotItem(i));
1267
+ return results;
1268
+ };
1269
+
1270
+ document.getElementsByClassName = function(className, parentElement) {
1271
+ var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
1272
+ return document._getElementsByXPath(q, parentElement);
1273
+ }
1274
+
1275
+ } else document.getElementsByClassName = function(className, parentElement) {
1276
+ var children = ($(parentElement) || document.body).getElementsByTagName('*');
1277
+ var elements = [], child, pattern = new RegExp("(^|\\s)" + className + "(\\s|$)");
1278
+ for (var i = 0, length = children.length; i < length; i++) {
1279
+ child = children[i];
1280
+ var elementClassName = child.className;
1281
+ if (elementClassName.length == 0) continue;
1282
+ if (elementClassName == className || elementClassName.match(pattern))
1283
+ elements.push(Element.extend(child));
1284
+ }
1285
+ return elements;
1286
+ };
1287
+
1288
+ /*--------------------------------------------------------------------------*/
1289
+
1290
+ if (!window.Element) var Element = {};
1291
+
1292
+ Element.extend = function(element) {
1293
+ var F = Prototype.BrowserFeatures;
1294
+ if (!element || !element.tagName || element.nodeType == 3 ||
1295
+ element._extended || F.SpecificElementExtensions || element == window)
1296
+ return element;
1297
+
1298
+ var methods = {}, tagName = element.tagName, cache = Element.extend.cache,
1299
+ T = Element.Methods.ByTag;
1300
+
1301
+ // extend methods for all tags (Safari doesn't need this)
1302
+ if (!F.ElementExtensions) {
1303
+ Object.extend(methods, Element.Methods),
1304
+ Object.extend(methods, Element.Methods.Simulated);
1305
+ }
1306
+
1307
+ // extend methods for specific tags
1308
+ if (T[tagName]) Object.extend(methods, T[tagName]);
1309
+
1310
+ for (var property in methods) {
1311
+ var value = methods[property];
1312
+ if (typeof value == 'function' && !(property in element))
1313
+ element[property] = cache.findOrStore(value);
1314
+ }
1315
+
1316
+ element._extended = Prototype.emptyFunction;
1317
+ return element;
1318
+ };
1319
+
1320
+ Element.extend.cache = {
1321
+ findOrStore: function(value) {
1322
+ return this[value] = this[value] || function() {
1323
+ return value.apply(null, [this].concat($A(arguments)));
1324
+ }
1325
+ }
1326
+ };
1327
+
1328
+ Element.Methods = {
1329
+ visible: function(element) {
1330
+ return $(element).style.display != 'none';
1331
+ },
1332
+
1333
+ toggle: function(element) {
1334
+ element = $(element);
1335
+ Element[Element.visible(element) ? 'hide' : 'show'](element);
1336
+ return element;
1337
+ },
1338
+
1339
+ hide: function(element) {
1340
+ $(element).style.display = 'none';
1341
+ return element;
1342
+ },
1343
+
1344
+ show: function(element) {
1345
+ $(element).style.display = '';
1346
+ return element;
1347
+ },
1348
+
1349
+ remove: function(element) {
1350
+ element = $(element);
1351
+ element.parentNode.removeChild(element);
1352
+ return element;
1353
+ },
1354
+
1355
+ update: function(element, html) {
1356
+ html = typeof html == 'undefined' ? '' : html.toString();
1357
+ $(element).innerHTML = html.stripScripts();
1358
+ setTimeout(function() {html.evalScripts()}, 10);
1359
+ return element;
1360
+ },
1361
+
1362
+ replace: function(element, html) {
1363
+ element = $(element);
1364
+ html = typeof html == 'undefined' ? '' : html.toString();
1365
+ if (element.outerHTML) {
1366
+ element.outerHTML = html.stripScripts();
1367
+ } else {
1368
+ var range = element.ownerDocument.createRange();
1369
+ range.selectNodeContents(element);
1370
+ element.parentNode.replaceChild(
1371
+ range.createContextualFragment(html.stripScripts()), element);
1372
+ }
1373
+ setTimeout(function() {html.evalScripts()}, 10);
1374
+ return element;
1375
+ },
1376
+
1377
+ inspect: function(element) {
1378
+ element = $(element);
1379
+ var result = '<' + element.tagName.toLowerCase();
1380
+ $H({'id': 'id', 'className': 'class'}).each(function(pair) {
1381
+ var property = pair.first(), attribute = pair.last();
1382
+ var value = (element[property] || '').toString();
1383
+ if (value) result += ' ' + attribute + '=' + value.inspect(true);
1384
+ });
1385
+ return result + '>';
1386
+ },
1387
+
1388
+ recursivelyCollect: function(element, property) {
1389
+ element = $(element);
1390
+ var elements = [];
1391
+ while (element = element[property])
1392
+ if (element.nodeType == 1)
1393
+ elements.push(Element.extend(element));
1394
+ return elements;
1395
+ },
1396
+
1397
+ ancestors: function(element) {
1398
+ return $(element).recursivelyCollect('parentNode');
1399
+ },
1400
+
1401
+ descendants: function(element) {
1402
+ return $A($(element).getElementsByTagName('*')).each(Element.extend);
1403
+ },
1404
+
1405
+ firstDescendant: function(element) {
1406
+ element = $(element).firstChild;
1407
+ while (element && element.nodeType != 1) element = element.nextSibling;
1408
+ return $(element);
1409
+ },
1410
+
1411
+ immediateDescendants: function(element) {
1412
+ if (!(element = $(element).firstChild)) return [];
1413
+ while (element && element.nodeType != 1) element = element.nextSibling;
1414
+ if (element) return [element].concat($(element).nextSiblings());
1415
+ return [];
1416
+ },
1417
+
1418
+ previousSiblings: function(element) {
1419
+ return $(element).recursivelyCollect('previousSibling');
1420
+ },
1421
+
1422
+ nextSiblings: function(element) {
1423
+ return $(element).recursivelyCollect('nextSibling');
1424
+ },
1425
+
1426
+ siblings: function(element) {
1427
+ element = $(element);
1428
+ return element.previousSiblings().reverse().concat(element.nextSiblings());
1429
+ },
1430
+
1431
+ match: function(element, selector) {
1432
+ if (typeof selector == 'string')
1433
+ selector = new Selector(selector);
1434
+ return selector.match($(element));
1435
+ },
1436
+
1437
+ up: function(element, expression, index) {
1438
+ element = $(element);
1439
+ if (arguments.length == 1) return $(element.parentNode);
1440
+ var ancestors = element.ancestors();
1441
+ return expression ? Selector.findElement(ancestors, expression, index) :
1442
+ ancestors[index || 0];
1443
+ },
1444
+
1445
+ down: function(element, expression, index) {
1446
+ element = $(element);
1447
+ if (arguments.length == 1) return element.firstDescendant();
1448
+ var descendants = element.descendants();
1449
+ return expression ? Selector.findElement(descendants, expression, index) :
1450
+ descendants[index || 0];
1451
+ },
1452
+
1453
+ previous: function(element, expression, index) {
1454
+ element = $(element);
1455
+ if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
1456
+ var previousSiblings = element.previousSiblings();
1457
+ return expression ? Selector.findElement(previousSiblings, expression, index) :
1458
+ previousSiblings[index || 0];
1459
+ },
1460
+
1461
+ next: function(element, expression, index) {
1462
+ element = $(element);
1463
+ if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
1464
+ var nextSiblings = element.nextSiblings();
1465
+ return expression ? Selector.findElement(nextSiblings, expression, index) :
1466
+ nextSiblings[index || 0];
1467
+ },
1468
+
1469
+ getElementsBySelector: function() {
1470
+ var args = $A(arguments), element = $(args.shift());
1471
+ return Selector.findChildElements(element, args);
1472
+ },
1473
+
1474
+ getElementsByClassName: function(element, className) {
1475
+ return document.getElementsByClassName(className, element);
1476
+ },
1477
+
1478
+ readAttribute: function(element, name) {
1479
+ element = $(element);
1480
+ if (Prototype.Browser.IE) {
1481
+ if (!element.attributes) return null;
1482
+ var t = Element._attributeTranslations;
1483
+ if (t.values[name]) return t.values[name](element, name);
1484
+ if (t.names[name]) name = t.names[name];
1485
+ var attribute = element.attributes[name];
1486
+ return attribute ? attribute.nodeValue : null;
1487
+ }
1488
+ return element.getAttribute(name);
1489
+ },
1490
+
1491
+ getHeight: function(element) {
1492
+ return $(element).getDimensions().height;
1493
+ },
1494
+
1495
+ getWidth: function(element) {
1496
+ return $(element).getDimensions().width;
1497
+ },
1498
+
1499
+ classNames: function(element) {
1500
+ return new Element.ClassNames(element);
1501
+ },
1502
+
1503
+ hasClassName: function(element, className) {
1504
+ if (!(element = $(element))) return;
1505
+ var elementClassName = element.className;
1506
+ if (elementClassName.length == 0) return false;
1507
+ if (elementClassName == className ||
1508
+ elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
1509
+ return true;
1510
+ return false;
1511
+ },
1512
+
1513
+ addClassName: function(element, className) {
1514
+ if (!(element = $(element))) return;
1515
+ Element.classNames(element).add(className);
1516
+ return element;
1517
+ },
1518
+
1519
+ removeClassName: function(element, className) {
1520
+ if (!(element = $(element))) return;
1521
+ Element.classNames(element).remove(className);
1522
+ return element;
1523
+ },
1524
+
1525
+ toggleClassName: function(element, className) {
1526
+ if (!(element = $(element))) return;
1527
+ Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
1528
+ return element;
1529
+ },
1530
+
1531
+ observe: function() {
1532
+ Event.observe.apply(Event, arguments);
1533
+ return $A(arguments).first();
1534
+ },
1535
+
1536
+ stopObserving: function() {
1537
+ Event.stopObserving.apply(Event, arguments);
1538
+ return $A(arguments).first();
1539
+ },
1540
+
1541
+ // removes whitespace-only text node children
1542
+ cleanWhitespace: function(element) {
1543
+ element = $(element);
1544
+ var node = element.firstChild;
1545
+ while (node) {
1546
+ var nextNode = node.nextSibling;
1547
+ if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
1548
+ element.removeChild(node);
1549
+ node = nextNode;
1550
+ }
1551
+ return element;
1552
+ },
1553
+
1554
+ empty: function(element) {
1555
+ return $(element).innerHTML.blank();
1556
+ },
1557
+
1558
+ descendantOf: function(element, ancestor) {
1559
+ element = $(element), ancestor = $(ancestor);
1560
+ while (element = element.parentNode)
1561
+ if (element == ancestor) return true;
1562
+ return false;
1563
+ },
1564
+
1565
+ scrollTo: function(element) {
1566
+ element = $(element);
1567
+ var pos = Position.cumulativeOffset(element);
1568
+ window.scrollTo(pos[0], pos[1]);
1569
+ return element;
1570
+ },
1571
+
1572
+ getStyle: function(element, style) {
1573
+ element = $(element);
1574
+ style = style == 'float' ? 'cssFloat' : style.camelize();
1575
+ var value = element.style[style];
1576
+ if (!value) {
1577
+ var css = document.defaultView.getComputedStyle(element, null);
1578
+ value = css ? css[style] : null;
1579
+ }
1580
+ if (style == 'opacity') return value ? parseFloat(value) : 1.0;
1581
+ return value == 'auto' ? null : value;
1582
+ },
1583
+
1584
+ getOpacity: function(element) {
1585
+ return $(element).getStyle('opacity');
1586
+ },
1587
+
1588
+ setStyle: function(element, styles, camelized) {
1589
+ element = $(element);
1590
+ var elementStyle = element.style;
1591
+
1592
+ for (var property in styles)
1593
+ if (property == 'opacity') element.setOpacity(styles[property])
1594
+ else
1595
+ elementStyle[(property == 'float' || property == 'cssFloat') ?
1596
+ (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') :
1597
+ (camelized ? property : property.camelize())] = styles[property];
1598
+
1599
+ return element;
1600
+ },
1601
+
1602
+ setOpacity: function(element, value) {
1603
+ element = $(element);
1604
+ element.style.opacity = (value == 1 || value === '') ? '' :
1605
+ (value < 0.00001) ? 0 : value;
1606
+ return element;
1607
+ },
1608
+
1609
+ getDimensions: function(element) {
1610
+ element = $(element);
1611
+ var display = $(element).getStyle('display');
1612
+ if (display != 'none' && display != null) // Safari bug
1613
+ return {width: element.offsetWidth, height: element.offsetHeight};
1614
+
1615
+ // All *Width and *Height properties give 0 on elements with display none,
1616
+ // so enable the element temporarily
1617
+ var els = element.style;
1618
+ var originalVisibility = els.visibility;
1619
+ var originalPosition = els.position;
1620
+ var originalDisplay = els.display;
1621
+ els.visibility = 'hidden';
1622
+ els.position = 'absolute';
1623
+ els.display = 'block';
1624
+ var originalWidth = element.clientWidth;
1625
+ var originalHeight = element.clientHeight;
1626
+ els.display = originalDisplay;
1627
+ els.position = originalPosition;
1628
+ els.visibility = originalVisibility;
1629
+ return {width: originalWidth, height: originalHeight};
1630
+ },
1631
+
1632
+ makePositioned: function(element) {
1633
+ element = $(element);
1634
+ var pos = Element.getStyle(element, 'position');
1635
+ if (pos == 'static' || !pos) {
1636
+ element._madePositioned = true;
1637
+ element.style.position = 'relative';
1638
+ // Opera returns the offset relative to the positioning context, when an
1639
+ // element is position relative but top and left have not been defined
1640
+ if (window.opera) {
1641
+ element.style.top = 0;
1642
+ element.style.left = 0;
1643
+ }
1644
+ }
1645
+ return element;
1646
+ },
1647
+
1648
+ undoPositioned: function(element) {
1649
+ element = $(element);
1650
+ if (element._madePositioned) {
1651
+ element._madePositioned = undefined;
1652
+ element.style.position =
1653
+ element.style.top =
1654
+ element.style.left =
1655
+ element.style.bottom =
1656
+ element.style.right = '';
1657
+ }
1658
+ return element;
1659
+ },
1660
+
1661
+ makeClipping: function(element) {
1662
+ element = $(element);
1663
+ if (element._overflow) return element;
1664
+ element._overflow = element.style.overflow || 'auto';
1665
+ if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
1666
+ element.style.overflow = 'hidden';
1667
+ return element;
1668
+ },
1669
+
1670
+ undoClipping: function(element) {
1671
+ element = $(element);
1672
+ if (!element._overflow) return element;
1673
+ element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
1674
+ element._overflow = null;
1675
+ return element;
1676
+ }
1677
+ };
1678
+
1679
+ Object.extend(Element.Methods, {
1680
+ childOf: Element.Methods.descendantOf,
1681
+ childElements: Element.Methods.immediateDescendants
1682
+ });
1683
+
1684
+ if (Prototype.Browser.Opera) {
1685
+ Element.Methods._getStyle = Element.Methods.getStyle;
1686
+ Element.Methods.getStyle = function(element, style) {
1687
+ switch(style) {
1688
+ case 'left':
1689
+ case 'top':
1690
+ case 'right':
1691
+ case 'bottom':
1692
+ if (Element._getStyle(element, 'position') == 'static') return null;
1693
+ default: return Element._getStyle(element, style);
1694
+ }
1695
+ };
1696
+ }
1697
+ else if (Prototype.Browser.IE) {
1698
+ Element.Methods.getStyle = function(element, style) {
1699
+ element = $(element);
1700
+ style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
1701
+ var value = element.style[style];
1702
+ if (!value && element.currentStyle) value = element.currentStyle[style];
1703
+
1704
+ if (style == 'opacity') {
1705
+ if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
1706
+ if (value[1]) return parseFloat(value[1]) / 100;
1707
+ return 1.0;
1708
+ }
1709
+
1710
+ if (value == 'auto') {
1711
+ if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
1712
+ return element['offset'+style.capitalize()] + 'px';
1713
+ return null;
1714
+ }
1715
+ return value;
1716
+ };
1717
+
1718
+ Element.Methods.setOpacity = function(element, value) {
1719
+ element = $(element);
1720
+ var filter = element.getStyle('filter'), style = element.style;
1721
+ if (value == 1 || value === '') {
1722
+ style.filter = filter.replace(/alpha\([^\)]*\)/gi,'');
1723
+ return element;
1724
+ } else if (value < 0.00001) value = 0;
1725
+ style.filter = filter.replace(/alpha\([^\)]*\)/gi, '') +
1726
+ 'alpha(opacity=' + (value * 100) + ')';
1727
+ return element;
1728
+ };
1729
+
1730
+ // IE is missing .innerHTML support for TABLE-related elements
1731
+ Element.Methods.update = function(element, html) {
1732
+ element = $(element);
1733
+ html = typeof html == 'undefined' ? '' : html.toString();
1734
+ var tagName = element.tagName.toUpperCase();
1735
+ if (['THEAD','TBODY','TR','TD'].include(tagName)) {
1736
+ var div = document.createElement('div');
1737
+ switch (tagName) {
1738
+ case 'THEAD':
1739
+ case 'TBODY':
1740
+ div.innerHTML = '<table><tbody>' + html.stripScripts() + '</tbody></table>';
1741
+ depth = 2;
1742
+ break;
1743
+ case 'TR':
1744
+ div.innerHTML = '<table><tbody><tr>' + html.stripScripts() + '</tr></tbody></table>';
1745
+ depth = 3;
1746
+ break;
1747
+ case 'TD':
1748
+ div.innerHTML = '<table><tbody><tr><td>' + html.stripScripts() + '</td></tr></tbody></table>';
1749
+ depth = 4;
1750
+ }
1751
+ $A(element.childNodes).each(function(node) { element.removeChild(node) });
1752
+ depth.times(function() { div = div.firstChild });
1753
+ $A(div.childNodes).each(function(node) { element.appendChild(node) });
1754
+ } else {
1755
+ element.innerHTML = html.stripScripts();
1756
+ }
1757
+ setTimeout(function() { html.evalScripts() }, 10);
1758
+ return element;
1759
+ }
1760
+ }
1761
+ else if (Prototype.Browser.Gecko) {
1762
+ Element.Methods.setOpacity = function(element, value) {
1763
+ element = $(element);
1764
+ element.style.opacity = (value == 1) ? 0.999999 :
1765
+ (value === '') ? '' : (value < 0.00001) ? 0 : value;
1766
+ return element;
1767
+ };
1768
+ }
1769
+
1770
+ Element._attributeTranslations = {
1771
+ names: {
1772
+ colspan: "colSpan",
1773
+ rowspan: "rowSpan",
1774
+ valign: "vAlign",
1775
+ datetime: "dateTime",
1776
+ accesskey: "accessKey",
1777
+ tabindex: "tabIndex",
1778
+ enctype: "encType",
1779
+ maxlength: "maxLength",
1780
+ readonly: "readOnly",
1781
+ longdesc: "longDesc"
1782
+ },
1783
+ values: {
1784
+ _getAttr: function(element, attribute) {
1785
+ return element.getAttribute(attribute, 2);
1786
+ },
1787
+ _flag: function(element, attribute) {
1788
+ return $(element).hasAttribute(attribute) ? attribute : null;
1789
+ },
1790
+ style: function(element) {
1791
+ return element.style.cssText.toLowerCase();
1792
+ },
1793
+ title: function(element) {
1794
+ var node = element.getAttributeNode('title');
1795
+ return node.specified ? node.nodeValue : null;
1796
+ }
1797
+ }
1798
+ };
1799
+
1800
+ (function() {
1801
+ Object.extend(this, {
1802
+ href: this._getAttr,
1803
+ src: this._getAttr,
1804
+ type: this._getAttr,
1805
+ disabled: this._flag,
1806
+ checked: this._flag,
1807
+ readonly: this._flag,
1808
+ multiple: this._flag
1809
+ });
1810
+ }).call(Element._attributeTranslations.values);
1811
+
1812
+ Element.Methods.Simulated = {
1813
+ hasAttribute: function(element, attribute) {
1814
+ var t = Element._attributeTranslations, node;
1815
+ attribute = t.names[attribute] || attribute;
1816
+ node = $(element).getAttributeNode(attribute);
1817
+ return node && node.specified;
1818
+ }
1819
+ };
1820
+
1821
+ Element.Methods.ByTag = {};
1822
+
1823
+ Object.extend(Element, Element.Methods);
1824
+
1825
+ if (!Prototype.BrowserFeatures.ElementExtensions &&
1826
+ document.createElement('div').__proto__) {
1827
+ window.HTMLElement = {};
1828
+ window.HTMLElement.prototype = document.createElement('div').__proto__;
1829
+ Prototype.BrowserFeatures.ElementExtensions = true;
1830
+ }
1831
+
1832
+ Element.hasAttribute = function(element, attribute) {
1833
+ if (element.hasAttribute) return element.hasAttribute(attribute);
1834
+ return Element.Methods.Simulated.hasAttribute(element, attribute);
1835
+ };
1836
+
1837
+ Element.addMethods = function(methods) {
1838
+ var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
1839
+
1840
+ if (!methods) {
1841
+ Object.extend(Form, Form.Methods);
1842
+ Object.extend(Form.Element, Form.Element.Methods);
1843
+ Object.extend(Element.Methods.ByTag, {
1844
+ "FORM": Object.clone(Form.Methods),
1845
+ "INPUT": Object.clone(Form.Element.Methods),
1846
+ "SELECT": Object.clone(Form.Element.Methods),
1847
+ "TEXTAREA": Object.clone(Form.Element.Methods)
1848
+ });
1849
+ }
1850
+
1851
+ if (arguments.length == 2) {
1852
+ var tagName = methods;
1853
+ methods = arguments[1];
1854
+ }
1855
+
1856
+ if (!tagName) Object.extend(Element.Methods, methods || {});
1857
+ else {
1858
+ if (tagName.constructor == Array) tagName.each(extend);
1859
+ else extend(tagName);
1860
+ }
1861
+
1862
+ function extend(tagName) {
1863
+ tagName = tagName.toUpperCase();
1864
+ if (!Element.Methods.ByTag[tagName])
1865
+ Element.Methods.ByTag[tagName] = {};
1866
+ Object.extend(Element.Methods.ByTag[tagName], methods);
1867
+ }
1868
+
1869
+ function copy(methods, destination, onlyIfAbsent) {
1870
+ onlyIfAbsent = onlyIfAbsent || false;
1871
+ var cache = Element.extend.cache;
1872
+ for (var property in methods) {
1873
+ var value = methods[property];
1874
+ if (!onlyIfAbsent || !(property in destination))
1875
+ destination[property] = cache.findOrStore(value);
1876
+ }
1877
+ }
1878
+
1879
+ function findDOMClass(tagName) {
1880
+ var klass;
1881
+ var trans = {
1882
+ "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
1883
+ "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
1884
+ "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
1885
+ "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
1886
+ "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
1887
+ "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
1888
+ "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
1889
+ "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
1890
+ "FrameSet", "IFRAME": "IFrame"
1891
+ };
1892
+ if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
1893
+ if (window[klass]) return window[klass];
1894
+ klass = 'HTML' + tagName + 'Element';
1895
+ if (window[klass]) return window[klass];
1896
+ klass = 'HTML' + tagName.capitalize() + 'Element';
1897
+ if (window[klass]) return window[klass];
1898
+
1899
+ window[klass] = {};
1900
+ window[klass].prototype = document.createElement(tagName).__proto__;
1901
+ return window[klass];
1902
+ }
1903
+
1904
+ if (F.ElementExtensions) {
1905
+ copy(Element.Methods, HTMLElement.prototype);
1906
+ copy(Element.Methods.Simulated, HTMLElement.prototype, true);
1907
+ }
1908
+
1909
+ if (F.SpecificElementExtensions) {
1910
+ for (var tag in Element.Methods.ByTag) {
1911
+ var klass = findDOMClass(tag);
1912
+ if (typeof klass == "undefined") continue;
1913
+ copy(T[tag], klass.prototype);
1914
+ }
1915
+ }
1916
+
1917
+ Object.extend(Element, Element.Methods);
1918
+ delete Element.ByTag;
1919
+ };
1920
+
1921
+ var Toggle = { display: Element.toggle };
1922
+
1923
+ /*--------------------------------------------------------------------------*/
1924
+
1925
+ Abstract.Insertion = function(adjacency) {
1926
+ this.adjacency = adjacency;
1927
+ }
1928
+
1929
+ Abstract.Insertion.prototype = {
1930
+ initialize: function(element, content) {
1931
+ this.element = $(element);
1932
+ this.content = content.stripScripts();
1933
+
1934
+ if (this.adjacency && this.element.insertAdjacentHTML) {
1935
+ try {
1936
+ this.element.insertAdjacentHTML(this.adjacency, this.content);
1937
+ } catch (e) {
1938
+ var tagName = this.element.tagName.toUpperCase();
1939
+ if (['TBODY', 'TR'].include(tagName)) {
1940
+ this.insertContent(this.contentFromAnonymousTable());
1941
+ } else {
1942
+ throw e;
1943
+ }
1944
+ }
1945
+ } else {
1946
+ this.range = this.element.ownerDocument.createRange();
1947
+ if (this.initializeRange) this.initializeRange();
1948
+ this.insertContent([this.range.createContextualFragment(this.content)]);
1949
+ }
1950
+
1951
+ setTimeout(function() {content.evalScripts()}, 10);
1952
+ },
1953
+
1954
+ contentFromAnonymousTable: function() {
1955
+ var div = document.createElement('div');
1956
+ div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
1957
+ return $A(div.childNodes[0].childNodes[0].childNodes);
1958
+ }
1959
+ }
1960
+
1961
+ var Insertion = new Object();
1962
+
1963
+ Insertion.Before = Class.create();
1964
+ Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
1965
+ initializeRange: function() {
1966
+ this.range.setStartBefore(this.element);
1967
+ },
1968
+
1969
+ insertContent: function(fragments) {
1970
+ fragments.each((function(fragment) {
1971
+ this.element.parentNode.insertBefore(fragment, this.element);
1972
+ }).bind(this));
1973
+ }
1974
+ });
1975
+
1976
+ Insertion.Top = Class.create();
1977
+ Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
1978
+ initializeRange: function() {
1979
+ this.range.selectNodeContents(this.element);
1980
+ this.range.collapse(true);
1981
+ },
1982
+
1983
+ insertContent: function(fragments) {
1984
+ fragments.reverse(false).each((function(fragment) {
1985
+ this.element.insertBefore(fragment, this.element.firstChild);
1986
+ }).bind(this));
1987
+ }
1988
+ });
1989
+
1990
+ Insertion.Bottom = Class.create();
1991
+ Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
1992
+ initializeRange: function() {
1993
+ this.range.selectNodeContents(this.element);
1994
+ this.range.collapse(this.element);
1995
+ },
1996
+
1997
+ insertContent: function(fragments) {
1998
+ fragments.each((function(fragment) {
1999
+ this.element.appendChild(fragment);
2000
+ }).bind(this));
2001
+ }
2002
+ });
2003
+
2004
+ Insertion.After = Class.create();
2005
+ Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
2006
+ initializeRange: function() {
2007
+ this.range.setStartAfter(this.element);
2008
+ },
2009
+
2010
+ insertContent: function(fragments) {
2011
+ fragments.each((function(fragment) {
2012
+ this.element.parentNode.insertBefore(fragment,
2013
+ this.element.nextSibling);
2014
+ }).bind(this));
2015
+ }
2016
+ });
2017
+
2018
+ /*--------------------------------------------------------------------------*/
2019
+
2020
+ Element.ClassNames = Class.create();
2021
+ Element.ClassNames.prototype = {
2022
+ initialize: function(element) {
2023
+ this.element = $(element);
2024
+ },
2025
+
2026
+ _each: function(iterator) {
2027
+ this.element.className.split(/\s+/).select(function(name) {
2028
+ return name.length > 0;
2029
+ })._each(iterator);
2030
+ },
2031
+
2032
+ set: function(className) {
2033
+ this.element.className = className;
2034
+ },
2035
+
2036
+ add: function(classNameToAdd) {
2037
+ if (this.include(classNameToAdd)) return;
2038
+ this.set($A(this).concat(classNameToAdd).join(' '));
2039
+ },
2040
+
2041
+ remove: function(classNameToRemove) {
2042
+ if (!this.include(classNameToRemove)) return;
2043
+ this.set($A(this).without(classNameToRemove).join(' '));
2044
+ },
2045
+
2046
+ toString: function() {
2047
+ return $A(this).join(' ');
2048
+ }
2049
+ };
2050
+
2051
+ Object.extend(Element.ClassNames.prototype, Enumerable);
2052
+ /* Portions of the Selector class are derived from Jack Slocum’s DomQuery,
2053
+ * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
2054
+ * license. Please see http://www.yui-ext.com/ for more information. */
2055
+
2056
+ var Selector = Class.create();
2057
+
2058
+ Selector.prototype = {
2059
+ initialize: function(expression) {
2060
+ this.expression = expression.strip();
2061
+ this.compileMatcher();
2062
+ },
2063
+
2064
+ compileMatcher: function() {
2065
+ // Selectors with namespaced attributes can't use the XPath version
2066
+ if (Prototype.BrowserFeatures.XPath && !(/\[[\w-]*?:/).test(this.expression))
2067
+ return this.compileXPathMatcher();
2068
+
2069
+ var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
2070
+ c = Selector.criteria, le, p, m;
2071
+
2072
+ if (Selector._cache[e]) {
2073
+ this.matcher = Selector._cache[e]; return;
2074
+ }
2075
+ this.matcher = ["this.matcher = function(root) {",
2076
+ "var r = root, h = Selector.handlers, c = false, n;"];
2077
+
2078
+ while (e && le != e && (/\S/).test(e)) {
2079
+ le = e;
2080
+ for (var i in ps) {
2081
+ p = ps[i];
2082
+ if (m = e.match(p)) {
2083
+ this.matcher.push(typeof c[i] == 'function' ? c[i](m) :
2084
+ new Template(c[i]).evaluate(m));
2085
+ e = e.replace(m[0], '');
2086
+ break;
2087
+ }
2088
+ }
2089
+ }
2090
+
2091
+ this.matcher.push("return h.unique(n);\n}");
2092
+ eval(this.matcher.join('\n'));
2093
+ Selector._cache[this.expression] = this.matcher;
2094
+ },
2095
+
2096
+ compileXPathMatcher: function() {
2097
+ var e = this.expression, ps = Selector.patterns,
2098
+ x = Selector.xpath, le, m;
2099
+
2100
+ if (Selector._cache[e]) {
2101
+ this.xpath = Selector._cache[e]; return;
2102
+ }
2103
+
2104
+ this.matcher = ['.//*'];
2105
+ while (e && le != e && (/\S/).test(e)) {
2106
+ le = e;
2107
+ for (var i in ps) {
2108
+ if (m = e.match(ps[i])) {
2109
+ this.matcher.push(typeof x[i] == 'function' ? x[i](m) :
2110
+ new Template(x[i]).evaluate(m));
2111
+ e = e.replace(m[0], '');
2112
+ break;
2113
+ }
2114
+ }
2115
+ }
2116
+
2117
+ this.xpath = this.matcher.join('');
2118
+ Selector._cache[this.expression] = this.xpath;
2119
+ },
2120
+
2121
+ findElements: function(root) {
2122
+ root = root || document;
2123
+ if (this.xpath) return document._getElementsByXPath(this.xpath, root);
2124
+ return this.matcher(root);
2125
+ },
2126
+
2127
+ match: function(element) {
2128
+ return this.findElements(document).include(element);
2129
+ },
2130
+
2131
+ toString: function() {
2132
+ return this.expression;
2133
+ },
2134
+
2135
+ inspect: function() {
2136
+ return "#<Selector:" + this.expression.inspect() + ">";
2137
+ }
2138
+ };
2139
+
2140
+ Object.extend(Selector, {
2141
+ _cache: {},
2142
+
2143
+ xpath: {
2144
+ descendant: "//*",
2145
+ child: "/*",
2146
+ adjacent: "/following-sibling::*[1]",
2147
+ laterSibling: '/following-sibling::*',
2148
+ tagName: function(m) {
2149
+ if (m[1] == '*') return '';
2150
+ return "[local-name()='" + m[1].toLowerCase() +
2151
+ "' or local-name()='" + m[1].toUpperCase() + "']";
2152
+ },
2153
+ className: "[contains(concat(' ', @class, ' '), ' #{1} ')]",
2154
+ id: "[@id='#{1}']",
2155
+ attrPresence: "[@#{1}]",
2156
+ attr: function(m) {
2157
+ m[3] = m[5] || m[6];
2158
+ return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
2159
+ },
2160
+ pseudo: function(m) {
2161
+ var h = Selector.xpath.pseudos[m[1]];
2162
+ if (!h) return '';
2163
+ if (typeof h === 'function') return h(m);
2164
+ return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
2165
+ },
2166
+ operators: {
2167
+ '=': "[@#{1}='#{3}']",
2168
+ '!=': "[@#{1}!='#{3}']",
2169
+ '^=': "[starts-with(@#{1}, '#{3}')]",
2170
+ '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
2171
+ '*=': "[contains(@#{1}, '#{3}')]",
2172
+ '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
2173
+ '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
2174
+ },
2175
+ pseudos: {
2176
+ 'first-child': '[not(preceding-sibling::*)]',
2177
+ 'last-child': '[not(following-sibling::*)]',
2178
+ 'only-child': '[not(preceding-sibling::* or following-sibling::*)]',
2179
+ 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
2180
+ 'checked': "[@checked]",
2181
+ 'disabled': "[@disabled]",
2182
+ 'enabled': "[not(@disabled)]",
2183
+ 'not': function(m) {
2184
+ var e = m[6], p = Selector.patterns,
2185
+ x = Selector.xpath, le, m, v;
2186
+
2187
+ var exclusion = [];
2188
+ while (e && le != e && (/\S/).test(e)) {
2189
+ le = e;
2190
+ for (var i in p) {
2191
+ if (m = e.match(p[i])) {
2192
+ v = typeof x[i] == 'function' ? x[i](m) : new Template(x[i]).evaluate(m);
2193
+ exclusion.push("(" + v.substring(1, v.length - 1) + ")");
2194
+ e = e.replace(m[0], '');
2195
+ break;
2196
+ }
2197
+ }
2198
+ }
2199
+ return "[not(" + exclusion.join(" and ") + ")]";
2200
+ },
2201
+ 'nth-child': function(m) {
2202
+ return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
2203
+ },
2204
+ 'nth-last-child': function(m) {
2205
+ return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
2206
+ },
2207
+ 'nth-of-type': function(m) {
2208
+ return Selector.xpath.pseudos.nth("position() ", m);
2209
+ },
2210
+ 'nth-last-of-type': function(m) {
2211
+ return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
2212
+ },
2213
+ 'first-of-type': function(m) {
2214
+ m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
2215
+ },
2216
+ 'last-of-type': function(m) {
2217
+ m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
2218
+ },
2219
+ 'only-of-type': function(m) {
2220
+ var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
2221
+ },
2222
+ nth: function(fragment, m) {
2223
+ var mm, formula = m[6], predicate;
2224
+ if (formula == 'even') formula = '2n+0';
2225
+ if (formula == 'odd') formula = '2n+1';
2226
+ if (mm = formula.match(/^(\d+)$/)) // digit only
2227
+ return '[' + fragment + "= " + mm[1] + ']';
2228
+ if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
2229
+ if (mm[1] == "-") mm[1] = -1;
2230
+ var a = mm[1] ? Number(mm[1]) : 1;
2231
+ var b = mm[2] ? Number(mm[2]) : 0;
2232
+ predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
2233
+ "((#{fragment} - #{b}) div #{a} >= 0)]";
2234
+ return new Template(predicate).evaluate({
2235
+ fragment: fragment, a: a, b: b });
2236
+ }
2237
+ }
2238
+ }
2239
+ },
2240
+
2241
+ criteria: {
2242
+ tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
2243
+ className: 'n = h.className(n, r, "#{1}", c); c = false;',
2244
+ id: 'n = h.id(n, r, "#{1}", c); c = false;',
2245
+ attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
2246
+ attr: function(m) {
2247
+ m[3] = (m[5] || m[6]);
2248
+ return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
2249
+ },
2250
+ pseudo: function(m) {
2251
+ if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
2252
+ return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
2253
+ },
2254
+ descendant: 'c = "descendant";',
2255
+ child: 'c = "child";',
2256
+ adjacent: 'c = "adjacent";',
2257
+ laterSibling: 'c = "laterSibling";'
2258
+ },
2259
+
2260
+ patterns: {
2261
+ // combinators must be listed first
2262
+ // (and descendant needs to be last combinator)
2263
+ laterSibling: /^\s*~\s*/,
2264
+ child: /^\s*>\s*/,
2265
+ adjacent: /^\s*\+\s*/,
2266
+ descendant: /^\s/,
2267
+
2268
+ // selectors follow
2269
+ tagName: /^\s*(\*|[\w\-]+)(\b|$)?/,
2270
+ id: /^#([\w\-\*]+)(\b|$)/,
2271
+ className: /^\.([\w\-\*]+)(\b|$)/,
2272
+ pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|\s|(?=:))/,
2273
+ attrPresence: /^\[([\w]+)\]/,
2274
+ attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\]]*?)\4|([^'"][^\]]*?)))?\]/
2275
+ },
2276
+
2277
+ handlers: {
2278
+ // UTILITY FUNCTIONS
2279
+ // joins two collections
2280
+ concat: function(a, b) {
2281
+ for (var i = 0, node; node = b[i]; i++)
2282
+ a.push(node);
2283
+ return a;
2284
+ },
2285
+
2286
+ // marks an array of nodes for counting
2287
+ mark: function(nodes) {
2288
+ for (var i = 0, node; node = nodes[i]; i++)
2289
+ node._counted = true;
2290
+ return nodes;
2291
+ },
2292
+
2293
+ unmark: function(nodes) {
2294
+ for (var i = 0, node; node = nodes[i]; i++)
2295
+ node._counted = undefined;
2296
+ return nodes;
2297
+ },
2298
+
2299
+ // mark each child node with its position (for nth calls)
2300
+ // "ofType" flag indicates whether we're indexing for nth-of-type
2301
+ // rather than nth-child
2302
+ index: function(parentNode, reverse, ofType) {
2303
+ parentNode._counted = true;
2304
+ if (reverse) {
2305
+ for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
2306
+ node = nodes[i];
2307
+ if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
2308
+ }
2309
+ } else {
2310
+ for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
2311
+ if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
2312
+ }
2313
+ },
2314
+
2315
+ // filters out duplicates and extends all nodes
2316
+ unique: function(nodes) {
2317
+ if (nodes.length == 0) return nodes;
2318
+ var results = [], n;
2319
+ for (var i = 0, l = nodes.length; i < l; i++)
2320
+ if (!(n = nodes[i])._counted) {
2321
+ n._counted = true;
2322
+ results.push(Element.extend(n));
2323
+ }
2324
+ return Selector.handlers.unmark(results);
2325
+ },
2326
+
2327
+ // COMBINATOR FUNCTIONS
2328
+ descendant: function(nodes) {
2329
+ var h = Selector.handlers;
2330
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
2331
+ h.concat(results, node.getElementsByTagName('*'));
2332
+ return results;
2333
+ },
2334
+
2335
+ child: function(nodes) {
2336
+ var h = Selector.handlers;
2337
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
2338
+ for (var j = 0, children = [], child; child = node.childNodes[j]; j++)
2339
+ if (child.nodeType == 1 && child.tagName != '!') results.push(child);
2340
+ }
2341
+ return results;
2342
+ },
2343
+
2344
+ adjacent: function(nodes) {
2345
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
2346
+ var next = this.nextElementSibling(node);
2347
+ if (next) results.push(next);
2348
+ }
2349
+ return results;
2350
+ },
2351
+
2352
+ laterSibling: function(nodes) {
2353
+ var h = Selector.handlers;
2354
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
2355
+ h.concat(results, Element.nextSiblings(node));
2356
+ return results;
2357
+ },
2358
+
2359
+ nextElementSibling: function(node) {
2360
+ while (node = node.nextSibling)
2361
+ if (node.nodeType == 1) return node;
2362
+ return null;
2363
+ },
2364
+
2365
+ previousElementSibling: function(node) {
2366
+ while (node = node.previousSibling)
2367
+ if (node.nodeType == 1) return node;
2368
+ return null;
2369
+ },
2370
+
2371
+ // TOKEN FUNCTIONS
2372
+ tagName: function(nodes, root, tagName, combinator) {
2373
+ tagName = tagName.toUpperCase();
2374
+ var results = [], h = Selector.handlers;
2375
+ if (nodes) {
2376
+ if (combinator) {
2377
+ // fastlane for ordinary descendant combinators
2378
+ if (combinator == "descendant") {
2379
+ for (var i = 0, node; node = nodes[i]; i++)
2380
+ h.concat(results, node.getElementsByTagName(tagName));
2381
+ return results;
2382
+ } else nodes = this[combinator](nodes);
2383
+ if (tagName == "*") return nodes;
2384
+ }
2385
+ for (var i = 0, node; node = nodes[i]; i++)
2386
+ if (node.tagName.toUpperCase() == tagName) results.push(node);
2387
+ return results;
2388
+ } else return root.getElementsByTagName(tagName);
2389
+ },
2390
+
2391
+ id: function(nodes, root, id, combinator) {
2392
+ var targetNode = $(id), h = Selector.handlers;
2393
+ if (!nodes && root == document) return targetNode ? [targetNode] : [];
2394
+ if (nodes) {
2395
+ if (combinator) {
2396
+ if (combinator == 'child') {
2397
+ for (var i = 0, node; node = nodes[i]; i++)
2398
+ if (targetNode.parentNode == node) return [targetNode];
2399
+ } else if (combinator == 'descendant') {
2400
+ for (var i = 0, node; node = nodes[i]; i++)
2401
+ if (Element.descendantOf(targetNode, node)) return [targetNode];
2402
+ } else if (combinator == 'adjacent') {
2403
+ for (var i = 0, node; node = nodes[i]; i++)
2404
+ if (Selector.handlers.previousElementSibling(targetNode) == node)
2405
+ return [targetNode];
2406
+ } else nodes = h[combinator](nodes);
2407
+ }
2408
+ for (var i = 0, node; node = nodes[i]; i++)
2409
+ if (node == targetNode) return [targetNode];
2410
+ return [];
2411
+ }
2412
+ return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
2413
+ },
2414
+
2415
+ className: function(nodes, root, className, combinator) {
2416
+ if (nodes && combinator) nodes = this[combinator](nodes);
2417
+ return Selector.handlers.byClassName(nodes, root, className);
2418
+ },
2419
+
2420
+ byClassName: function(nodes, root, className) {
2421
+ if (!nodes) nodes = Selector.handlers.descendant([root]);
2422
+ var needle = ' ' + className + ' ';
2423
+ for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
2424
+ nodeClassName = node.className;
2425
+ if (nodeClassName.length == 0) continue;
2426
+ if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
2427
+ results.push(node);
2428
+ }
2429
+ return results;
2430
+ },
2431
+
2432
+ attrPresence: function(nodes, root, attr) {
2433
+ var results = [];
2434
+ for (var i = 0, node; node = nodes[i]; i++)
2435
+ if (Element.hasAttribute(node, attr)) results.push(node);
2436
+ return results;
2437
+ },
2438
+
2439
+ attr: function(nodes, root, attr, value, operator) {
2440
+ if (!nodes) nodes = root.getElementsByTagName("*");
2441
+ var handler = Selector.operators[operator], results = [];
2442
+ for (var i = 0, node; node = nodes[i]; i++) {
2443
+ var nodeValue = Element.readAttribute(node, attr);
2444
+ if (nodeValue === null) continue;
2445
+ if (handler(nodeValue, value)) results.push(node);
2446
+ }
2447
+ return results;
2448
+ },
2449
+
2450
+ pseudo: function(nodes, name, value, root, combinator) {
2451
+ if (nodes && combinator) nodes = this[combinator](nodes);
2452
+ if (!nodes) nodes = root.getElementsByTagName("*");
2453
+ return Selector.pseudos[name](nodes, value, root);
2454
+ }
2455
+ },
2456
+
2457
+ pseudos: {
2458
+ 'first-child': function(nodes, value, root) {
2459
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
2460
+ if (Selector.handlers.previousElementSibling(node)) continue;
2461
+ results.push(node);
2462
+ }
2463
+ return results;
2464
+ },
2465
+ 'last-child': function(nodes, value, root) {
2466
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
2467
+ if (Selector.handlers.nextElementSibling(node)) continue;
2468
+ results.push(node);
2469
+ }
2470
+ return results;
2471
+ },
2472
+ 'only-child': function(nodes, value, root) {
2473
+ var h = Selector.handlers;
2474
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
2475
+ if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
2476
+ results.push(node);
2477
+ return results;
2478
+ },
2479
+ 'nth-child': function(nodes, formula, root) {
2480
+ return Selector.pseudos.nth(nodes, formula, root);
2481
+ },
2482
+ 'nth-last-child': function(nodes, formula, root) {
2483
+ return Selector.pseudos.nth(nodes, formula, root, true);
2484
+ },
2485
+ 'nth-of-type': function(nodes, formula, root) {
2486
+ return Selector.pseudos.nth(nodes, formula, root, false, true);
2487
+ },
2488
+ 'nth-last-of-type': function(nodes, formula, root) {
2489
+ return Selector.pseudos.nth(nodes, formula, root, true, true);
2490
+ },
2491
+ 'first-of-type': function(nodes, formula, root) {
2492
+ return Selector.pseudos.nth(nodes, "1", root, false, true);
2493
+ },
2494
+ 'last-of-type': function(nodes, formula, root) {
2495
+ return Selector.pseudos.nth(nodes, "1", root, true, true);
2496
+ },
2497
+ 'only-of-type': function(nodes, formula, root) {
2498
+ var p = Selector.pseudos;
2499
+ return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
2500
+ },
2501
+
2502
+ // handles the an+b logic
2503
+ getIndices: function(a, b, total) {
2504
+ if (a == 0) return b > 0 ? [b] : [];
2505
+ return $R(1, total).inject([], function(memo, i) {
2506
+ if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
2507
+ return memo;
2508
+ });
2509
+ },
2510
+
2511
+ // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
2512
+ nth: function(nodes, formula, root, reverse, ofType) {
2513
+ if (nodes.length == 0) return [];
2514
+ if (formula == 'even') formula = '2n+0';
2515
+ if (formula == 'odd') formula = '2n+1';
2516
+ var h = Selector.handlers, results = [], indexed = [], m;
2517
+ h.mark(nodes);
2518
+ for (var i = 0, node; node = nodes[i]; i++) {
2519
+ if (!node.parentNode._counted) {
2520
+ h.index(node.parentNode, reverse, ofType);
2521
+ indexed.push(node.parentNode);
2522
+ }
2523
+ }
2524
+ if (formula.match(/^\d+$/)) { // just a number
2525
+ formula = Number(formula);
2526
+ for (var i = 0, node; node = nodes[i]; i++)
2527
+ if (node.nodeIndex == formula) results.push(node);
2528
+ } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
2529
+ if (m[1] == "-") m[1] = -1;
2530
+ var a = m[1] ? Number(m[1]) : 1;
2531
+ var b = m[2] ? Number(m[2]) : 0;
2532
+ var indices = Selector.pseudos.getIndices(a, b, nodes.length);
2533
+ for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
2534
+ for (var j = 0; j < l; j++)
2535
+ if (node.nodeIndex == indices[j]) results.push(node);
2536
+ }
2537
+ }
2538
+ h.unmark(nodes);
2539
+ h.unmark(indexed);
2540
+ return results;
2541
+ },
2542
+
2543
+ 'empty': function(nodes, value, root) {
2544
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
2545
+ // IE treats comments as element nodes
2546
+ if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
2547
+ results.push(node);
2548
+ }
2549
+ return results;
2550
+ },
2551
+
2552
+ 'not': function(nodes, selector, root) {
2553
+ var h = Selector.handlers, selectorType, m;
2554
+ var exclusions = new Selector(selector).findElements(root);
2555
+ h.mark(exclusions);
2556
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
2557
+ if (!node._counted) results.push(node);
2558
+ h.unmark(exclusions);
2559
+ return results;
2560
+ },
2561
+
2562
+ 'enabled': function(nodes, value, root) {
2563
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
2564
+ if (!node.disabled) results.push(node);
2565
+ return results;
2566
+ },
2567
+
2568
+ 'disabled': function(nodes, value, root) {
2569
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
2570
+ if (node.disabled) results.push(node);
2571
+ return results;
2572
+ },
2573
+
2574
+ 'checked': function(nodes, value, root) {
2575
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
2576
+ if (node.checked) results.push(node);
2577
+ return results;
2578
+ }
2579
+ },
2580
+
2581
+ operators: {
2582
+ '=': function(nv, v) { return nv == v; },
2583
+ '!=': function(nv, v) { return nv != v; },
2584
+ '^=': function(nv, v) { return nv.startsWith(v); },
2585
+ '$=': function(nv, v) { return nv.endsWith(v); },
2586
+ '*=': function(nv, v) { return nv.include(v); },
2587
+ '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
2588
+ '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
2589
+ },
2590
+
2591
+ matchElements: function(elements, expression) {
2592
+ var matches = new Selector(expression).findElements(), h = Selector.handlers;
2593
+ h.mark(matches);
2594
+ for (var i = 0, results = [], element; element = elements[i]; i++)
2595
+ if (element._counted) results.push(element);
2596
+ h.unmark(matches);
2597
+ return results;
2598
+ },
2599
+
2600
+ findElement: function(elements, expression, index) {
2601
+ if (typeof expression == 'number') {
2602
+ index = expression; expression = false;
2603
+ }
2604
+ return Selector.matchElements(elements, expression || '*')[index || 0];
2605
+ },
2606
+
2607
+ findChildElements: function(element, expressions) {
2608
+ var exprs = expressions.join(','), expressions = [];
2609
+ exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
2610
+ expressions.push(m[1].strip());
2611
+ });
2612
+ var results = [], h = Selector.handlers;
2613
+ for (var i = 0, l = expressions.length, selector; i < l; i++) {
2614
+ selector = new Selector(expressions[i].strip());
2615
+ h.concat(results, selector.findElements(element));
2616
+ }
2617
+ return (l > 1) ? h.unique(results) : results;
2618
+ }
2619
+ });
2620
+
2621
+ function $$() {
2622
+ return Selector.findChildElements(document, $A(arguments));
2623
+ }
2624
+ var Form = {
2625
+ reset: function(form) {
2626
+ $(form).reset();
2627
+ return form;
2628
+ },
2629
+
2630
+ serializeElements: function(elements, getHash) {
2631
+ var data = elements.inject({}, function(result, element) {
2632
+ if (!element.disabled && element.name) {
2633
+ var key = element.name, value = $(element).getValue();
2634
+ if (value != null) {
2635
+ if (key in result) {
2636
+ if (result[key].constructor != Array) result[key] = [result[key]];
2637
+ result[key].push(value);
2638
+ }
2639
+ else result[key] = value;
2640
+ }
2641
+ }
2642
+ return result;
2643
+ });
2644
+
2645
+ return getHash ? data : Hash.toQueryString(data);
2646
+ }
2647
+ };
2648
+
2649
+ Form.Methods = {
2650
+ serialize: function(form, getHash) {
2651
+ return Form.serializeElements(Form.getElements(form), getHash);
2652
+ },
2653
+
2654
+ getElements: function(form) {
2655
+ return $A($(form).getElementsByTagName('*')).inject([],
2656
+ function(elements, child) {
2657
+ if (Form.Element.Serializers[child.tagName.toLowerCase()])
2658
+ elements.push(Element.extend(child));
2659
+ return elements;
2660
+ }
2661
+ );
2662
+ },
2663
+
2664
+ getInputs: function(form, typeName, name) {
2665
+ form = $(form);
2666
+ var inputs = form.getElementsByTagName('input');
2667
+
2668
+ if (!typeName && !name) return $A(inputs).map(Element.extend);
2669
+
2670
+ for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
2671
+ var input = inputs[i];
2672
+ if ((typeName && input.type != typeName) || (name && input.name != name))
2673
+ continue;
2674
+ matchingInputs.push(Element.extend(input));
2675
+ }
2676
+
2677
+ return matchingInputs;
2678
+ },
2679
+
2680
+ disable: function(form) {
2681
+ form = $(form);
2682
+ Form.getElements(form).invoke('disable');
2683
+ return form;
2684
+ },
2685
+
2686
+ enable: function(form) {
2687
+ form = $(form);
2688
+ Form.getElements(form).invoke('enable');
2689
+ return form;
2690
+ },
2691
+
2692
+ findFirstElement: function(form) {
2693
+ return $(form).getElements().find(function(element) {
2694
+ return element.type != 'hidden' && !element.disabled &&
2695
+ ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
2696
+ });
2697
+ },
2698
+
2699
+ focusFirstElement: function(form) {
2700
+ form = $(form);
2701
+ form.findFirstElement().activate();
2702
+ return form;
2703
+ },
2704
+
2705
+ request: function(form, options) {
2706
+ form = $(form), options = Object.clone(options || {});
2707
+
2708
+ var params = options.parameters;
2709
+ options.parameters = form.serialize(true);
2710
+
2711
+ if (params) {
2712
+ if (typeof params == 'string') params = params.toQueryParams();
2713
+ Object.extend(options.parameters, params);
2714
+ }
2715
+
2716
+ if (form.hasAttribute('method') && !options.method)
2717
+ options.method = form.method;
2718
+
2719
+ return new Ajax.Request(form.readAttribute('action'), options);
2720
+ }
2721
+ }
2722
+
2723
+ /*--------------------------------------------------------------------------*/
2724
+
2725
+ Form.Element = {
2726
+ focus: function(element) {
2727
+ $(element).focus();
2728
+ return element;
2729
+ },
2730
+
2731
+ select: function(element) {
2732
+ $(element).select();
2733
+ return element;
2734
+ }
2735
+ }
2736
+
2737
+ Form.Element.Methods = {
2738
+ serialize: function(element) {
2739
+ element = $(element);
2740
+ if (!element.disabled && element.name) {
2741
+ var value = element.getValue();
2742
+ if (value != undefined) {
2743
+ var pair = {};
2744
+ pair[element.name] = value;
2745
+ return Hash.toQueryString(pair);
2746
+ }
2747
+ }
2748
+ return '';
2749
+ },
2750
+
2751
+ getValue: function(element) {
2752
+ element = $(element);
2753
+ var method = element.tagName.toLowerCase();
2754
+ return Form.Element.Serializers[method](element);
2755
+ },
2756
+
2757
+ clear: function(element) {
2758
+ $(element).value = '';
2759
+ return element;
2760
+ },
2761
+
2762
+ present: function(element) {
2763
+ return $(element).value != '';
2764
+ },
2765
+
2766
+ activate: function(element) {
2767
+ element = $(element);
2768
+ try {
2769
+ element.focus();
2770
+ if (element.select && (element.tagName.toLowerCase() != 'input' ||
2771
+ !['button', 'reset', 'submit'].include(element.type)))
2772
+ element.select();
2773
+ } catch (e) {}
2774
+ return element;
2775
+ },
2776
+
2777
+ disable: function(element) {
2778
+ element = $(element);
2779
+ element.blur();
2780
+ element.disabled = true;
2781
+ return element;
2782
+ },
2783
+
2784
+ enable: function(element) {
2785
+ element = $(element);
2786
+ element.disabled = false;
2787
+ return element;
2788
+ }
2789
+ }
2790
+
2791
+ /*--------------------------------------------------------------------------*/
2792
+
2793
+ var Field = Form.Element;
2794
+ var $F = Form.Element.Methods.getValue;
2795
+
2796
+ /*--------------------------------------------------------------------------*/
2797
+
2798
+ Form.Element.Serializers = {
2799
+ input: function(element) {
2800
+ switch (element.type.toLowerCase()) {
2801
+ case 'checkbox':
2802
+ case 'radio':
2803
+ return Form.Element.Serializers.inputSelector(element);
2804
+ default:
2805
+ return Form.Element.Serializers.textarea(element);
2806
+ }
2807
+ },
2808
+
2809
+ inputSelector: function(element) {
2810
+ return element.checked ? element.value : null;
2811
+ },
2812
+
2813
+ textarea: function(element) {
2814
+ return element.value;
2815
+ },
2816
+
2817
+ select: function(element) {
2818
+ return this[element.type == 'select-one' ?
2819
+ 'selectOne' : 'selectMany'](element);
2820
+ },
2821
+
2822
+ selectOne: function(element) {
2823
+ var index = element.selectedIndex;
2824
+ return index >= 0 ? this.optionValue(element.options[index]) : null;
2825
+ },
2826
+
2827
+ selectMany: function(element) {
2828
+ var values, length = element.length;
2829
+ if (!length) return null;
2830
+
2831
+ for (var i = 0, values = []; i < length; i++) {
2832
+ var opt = element.options[i];
2833
+ if (opt.selected) values.push(this.optionValue(opt));
2834
+ }
2835
+ return values;
2836
+ },
2837
+
2838
+ optionValue: function(opt) {
2839
+ // extend element because hasAttribute may not be native
2840
+ return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
2841
+ }
2842
+ }
2843
+
2844
+ /*--------------------------------------------------------------------------*/
2845
+
2846
+ Abstract.TimedObserver = function() {}
2847
+ Abstract.TimedObserver.prototype = {
2848
+ initialize: function(element, frequency, callback) {
2849
+ this.frequency = frequency;
2850
+ this.element = $(element);
2851
+ this.callback = callback;
2852
+
2853
+ this.lastValue = this.getValue();
2854
+ this.registerCallback();
2855
+ },
2856
+
2857
+ registerCallback: function() {
2858
+ setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
2859
+ },
2860
+
2861
+ onTimerEvent: function() {
2862
+ var value = this.getValue();
2863
+ var changed = ('string' == typeof this.lastValue && 'string' == typeof value
2864
+ ? this.lastValue != value : String(this.lastValue) != String(value));
2865
+ if (changed) {
2866
+ this.callback(this.element, value);
2867
+ this.lastValue = value;
2868
+ }
2869
+ }
2870
+ }
2871
+
2872
+ Form.Element.Observer = Class.create();
2873
+ Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
2874
+ getValue: function() {
2875
+ return Form.Element.getValue(this.element);
2876
+ }
2877
+ });
2878
+
2879
+ Form.Observer = Class.create();
2880
+ Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
2881
+ getValue: function() {
2882
+ return Form.serialize(this.element);
2883
+ }
2884
+ });
2885
+
2886
+ /*--------------------------------------------------------------------------*/
2887
+
2888
+ Abstract.EventObserver = function() {}
2889
+ Abstract.EventObserver.prototype = {
2890
+ initialize: function(element, callback) {
2891
+ this.element = $(element);
2892
+ this.callback = callback;
2893
+
2894
+ this.lastValue = this.getValue();
2895
+ if (this.element.tagName.toLowerCase() == 'form')
2896
+ this.registerFormCallbacks();
2897
+ else
2898
+ this.registerCallback(this.element);
2899
+ },
2900
+
2901
+ onElementEvent: function() {
2902
+ var value = this.getValue();
2903
+ if (this.lastValue != value) {
2904
+ this.callback(this.element, value);
2905
+ this.lastValue = value;
2906
+ }
2907
+ },
2908
+
2909
+ registerFormCallbacks: function() {
2910
+ Form.getElements(this.element).each(this.registerCallback.bind(this));
2911
+ },
2912
+
2913
+ registerCallback: function(element) {
2914
+ if (element.type) {
2915
+ switch (element.type.toLowerCase()) {
2916
+ case 'checkbox':
2917
+ case 'radio':
2918
+ Event.observe(element, 'click', this.onElementEvent.bind(this));
2919
+ break;
2920
+ default:
2921
+ Event.observe(element, 'change', this.onElementEvent.bind(this));
2922
+ break;
2923
+ }
2924
+ }
2925
+ }
2926
+ }
2927
+
2928
+ Form.Element.EventObserver = Class.create();
2929
+ Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
2930
+ getValue: function() {
2931
+ return Form.Element.getValue(this.element);
2932
+ }
2933
+ });
2934
+
2935
+ Form.EventObserver = Class.create();
2936
+ Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
2937
+ getValue: function() {
2938
+ return Form.serialize(this.element);
2939
+ }
2940
+ });
2941
+ if (!window.Event) {
2942
+ var Event = new Object();
2943
+ }
2944
+
2945
+ Object.extend(Event, {
2946
+ KEY_BACKSPACE: 8,
2947
+ KEY_TAB: 9,
2948
+ KEY_RETURN: 13,
2949
+ KEY_ESC: 27,
2950
+ KEY_LEFT: 37,
2951
+ KEY_UP: 38,
2952
+ KEY_RIGHT: 39,
2953
+ KEY_DOWN: 40,
2954
+ KEY_DELETE: 46,
2955
+ KEY_HOME: 36,
2956
+ KEY_END: 35,
2957
+ KEY_PAGEUP: 33,
2958
+ KEY_PAGEDOWN: 34,
2959
+
2960
+ element: function(event) {
2961
+ return $(event.target || event.srcElement);
2962
+ },
2963
+
2964
+ isLeftClick: function(event) {
2965
+ return (((event.which) && (event.which == 1)) ||
2966
+ ((event.button) && (event.button == 1)));
2967
+ },
2968
+
2969
+ pointerX: function(event) {
2970
+ return event.pageX || (event.clientX +
2971
+ (document.documentElement.scrollLeft || document.body.scrollLeft));
2972
+ },
2973
+
2974
+ pointerY: function(event) {
2975
+ return event.pageY || (event.clientY +
2976
+ (document.documentElement.scrollTop || document.body.scrollTop));
2977
+ },
2978
+
2979
+ stop: function(event) {
2980
+ if (event.preventDefault) {
2981
+ event.preventDefault();
2982
+ event.stopPropagation();
2983
+ } else {
2984
+ event.returnValue = false;
2985
+ event.cancelBubble = true;
2986
+ }
2987
+ },
2988
+
2989
+ // find the first node with the given tagName, starting from the
2990
+ // node the event was triggered on; traverses the DOM upwards
2991
+ findElement: function(event, tagName) {
2992
+ var element = Event.element(event);
2993
+ while (element.parentNode && (!element.tagName ||
2994
+ (element.tagName.toUpperCase() != tagName.toUpperCase())))
2995
+ element = element.parentNode;
2996
+ return element;
2997
+ },
2998
+
2999
+ observers: false,
3000
+
3001
+ _observeAndCache: function(element, name, observer, useCapture) {
3002
+ if (!this.observers) this.observers = [];
3003
+ if (element.addEventListener) {
3004
+ this.observers.push([element, name, observer, useCapture]);
3005
+ element.addEventListener(name, observer, useCapture);
3006
+ } else if (element.attachEvent) {
3007
+ this.observers.push([element, name, observer, useCapture]);
3008
+ element.attachEvent('on' + name, observer);
3009
+ }
3010
+ },
3011
+
3012
+ unloadCache: function() {
3013
+ if (!Event.observers) return;
3014
+ for (var i = 0, length = Event.observers.length; i < length; i++) {
3015
+ Event.stopObserving.apply(this, Event.observers[i]);
3016
+ Event.observers[i][0] = null;
3017
+ }
3018
+ Event.observers = false;
3019
+ },
3020
+
3021
+ observe: function(element, name, observer, useCapture) {
3022
+ element = $(element);
3023
+ useCapture = useCapture || false;
3024
+
3025
+ if (name == 'keypress' &&
3026
+ (Prototype.Browser.WebKit || element.attachEvent))
3027
+ name = 'keydown';
3028
+
3029
+ Event._observeAndCache(element, name, observer, useCapture);
3030
+ },
3031
+
3032
+ stopObserving: function(element, name, observer, useCapture) {
3033
+ element = $(element);
3034
+ useCapture = useCapture || false;
3035
+
3036
+ if (name == 'keypress' &&
3037
+ (Prototype.Browser.WebKit || element.attachEvent))
3038
+ name = 'keydown';
3039
+
3040
+ if (element.removeEventListener) {
3041
+ element.removeEventListener(name, observer, useCapture);
3042
+ } else if (element.detachEvent) {
3043
+ try {
3044
+ element.detachEvent('on' + name, observer);
3045
+ } catch (e) {}
3046
+ }
3047
+ }
3048
+ });
3049
+
3050
+ /* prevent memory leaks in IE */
3051
+ if (Prototype.Browser.IE)
3052
+ Event.observe(window, 'unload', Event.unloadCache, false);
3053
+ var Position = {
3054
+ // set to true if needed, warning: firefox performance problems
3055
+ // NOT neeeded for page scrolling, only if draggable contained in
3056
+ // scrollable elements
3057
+ includeScrollOffsets: false,
3058
+
3059
+ // must be called before calling withinIncludingScrolloffset, every time the
3060
+ // page is scrolled
3061
+ prepare: function() {
3062
+ this.deltaX = window.pageXOffset
3063
+ || document.documentElement.scrollLeft
3064
+ || document.body.scrollLeft
3065
+ || 0;
3066
+ this.deltaY = window.pageYOffset
3067
+ || document.documentElement.scrollTop
3068
+ || document.body.scrollTop
3069
+ || 0;
3070
+ },
3071
+
3072
+ realOffset: function(element) {
3073
+ var valueT = 0, valueL = 0;
3074
+ do {
3075
+ valueT += element.scrollTop || 0;
3076
+ valueL += element.scrollLeft || 0;
3077
+ element = element.parentNode;
3078
+ } while (element);
3079
+ return [valueL, valueT];
3080
+ },
3081
+
3082
+ cumulativeOffset: function(element) {
3083
+ var valueT = 0, valueL = 0;
3084
+ do {
3085
+ valueT += element.offsetTop || 0;
3086
+ valueL += element.offsetLeft || 0;
3087
+ element = element.offsetParent;
3088
+ } while (element);
3089
+ return [valueL, valueT];
3090
+ },
3091
+
3092
+ positionedOffset: function(element) {
3093
+ var valueT = 0, valueL = 0;
3094
+ do {
3095
+ valueT += element.offsetTop || 0;
3096
+ valueL += element.offsetLeft || 0;
3097
+ element = element.offsetParent;
3098
+ if (element) {
3099
+ if(element.tagName=='BODY') break;
3100
+ var p = Element.getStyle(element, 'position');
3101
+ if (p == 'relative' || p == 'absolute') break;
3102
+ }
3103
+ } while (element);
3104
+ return [valueL, valueT];
3105
+ },
3106
+
3107
+ offsetParent: function(element) {
3108
+ if (element.offsetParent) return element.offsetParent;
3109
+ if (element == document.body) return element;
3110
+
3111
+ while ((element = element.parentNode) && element != document.body)
3112
+ if (Element.getStyle(element, 'position') != 'static')
3113
+ return element;
3114
+
3115
+ return document.body;
3116
+ },
3117
+
3118
+ // caches x/y coordinate pair to use with overlap
3119
+ within: function(element, x, y) {
3120
+ if (this.includeScrollOffsets)
3121
+ return this.withinIncludingScrolloffsets(element, x, y);
3122
+ this.xcomp = x;
3123
+ this.ycomp = y;
3124
+ this.offset = this.cumulativeOffset(element);
3125
+
3126
+ return (y >= this.offset[1] &&
3127
+ y < this.offset[1] + element.offsetHeight &&
3128
+ x >= this.offset[0] &&
3129
+ x < this.offset[0] + element.offsetWidth);
3130
+ },
3131
+
3132
+ withinIncludingScrolloffsets: function(element, x, y) {
3133
+ var offsetcache = this.realOffset(element);
3134
+
3135
+ this.xcomp = x + offsetcache[0] - this.deltaX;
3136
+ this.ycomp = y + offsetcache[1] - this.deltaY;
3137
+ this.offset = this.cumulativeOffset(element);
3138
+
3139
+ return (this.ycomp >= this.offset[1] &&
3140
+ this.ycomp < this.offset[1] + element.offsetHeight &&
3141
+ this.xcomp >= this.offset[0] &&
3142
+ this.xcomp < this.offset[0] + element.offsetWidth);
3143
+ },
3144
+
3145
+ // within must be called directly before
3146
+ overlap: function(mode, element) {
3147
+ if (!mode) return 0;
3148
+ if (mode == 'vertical')
3149
+ return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
3150
+ element.offsetHeight;
3151
+ if (mode == 'horizontal')
3152
+ return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
3153
+ element.offsetWidth;
3154
+ },
3155
+
3156
+ page: function(forElement) {
3157
+ var valueT = 0, valueL = 0;
3158
+
3159
+ var element = forElement;
3160
+ do {
3161
+ valueT += element.offsetTop || 0;
3162
+ valueL += element.offsetLeft || 0;
3163
+
3164
+ // Safari fix
3165
+ if (element.offsetParent == document.body)
3166
+ if (Element.getStyle(element,'position')=='absolute') break;
3167
+
3168
+ } while (element = element.offsetParent);
3169
+
3170
+ element = forElement;
3171
+ do {
3172
+ if (!window.opera || element.tagName=='BODY') {
3173
+ valueT -= element.scrollTop || 0;
3174
+ valueL -= element.scrollLeft || 0;
3175
+ }
3176
+ } while (element = element.parentNode);
3177
+
3178
+ return [valueL, valueT];
3179
+ },
3180
+
3181
+ clone: function(source, target) {
3182
+ var options = Object.extend({
3183
+ setLeft: true,
3184
+ setTop: true,
3185
+ setWidth: true,
3186
+ setHeight: true,
3187
+ offsetTop: 0,
3188
+ offsetLeft: 0
3189
+ }, arguments[2] || {})
3190
+
3191
+ // find page position of source
3192
+ source = $(source);
3193
+ var p = Position.page(source);
3194
+
3195
+ // find coordinate system to use
3196
+ target = $(target);
3197
+ var delta = [0, 0];
3198
+ var parent = null;
3199
+ // delta [0,0] will do fine with position: fixed elements,
3200
+ // position:absolute needs offsetParent deltas
3201
+ if (Element.getStyle(target,'position') == 'absolute') {
3202
+ parent = Position.offsetParent(target);
3203
+ delta = Position.page(parent);
3204
+ }
3205
+
3206
+ // correct by body offsets (fixes Safari)
3207
+ if (parent == document.body) {
3208
+ delta[0] -= document.body.offsetLeft;
3209
+ delta[1] -= document.body.offsetTop;
3210
+ }
3211
+
3212
+ // set position
3213
+ if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
3214
+ if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
3215
+ if(options.setWidth) target.style.width = source.offsetWidth + 'px';
3216
+ if(options.setHeight) target.style.height = source.offsetHeight + 'px';
3217
+ },
3218
+
3219
+ absolutize: function(element) {
3220
+ element = $(element);
3221
+ if (element.style.position == 'absolute') return;
3222
+ Position.prepare();
3223
+
3224
+ var offsets = Position.positionedOffset(element);
3225
+ var top = offsets[1];
3226
+ var left = offsets[0];
3227
+ var width = element.clientWidth;
3228
+ var height = element.clientHeight;
3229
+
3230
+ element._originalLeft = left - parseFloat(element.style.left || 0);
3231
+ element._originalTop = top - parseFloat(element.style.top || 0);
3232
+ element._originalWidth = element.style.width;
3233
+ element._originalHeight = element.style.height;
3234
+
3235
+ element.style.position = 'absolute';
3236
+ element.style.top = top + 'px';
3237
+ element.style.left = left + 'px';
3238
+ element.style.width = width + 'px';
3239
+ element.style.height = height + 'px';
3240
+ },
3241
+
3242
+ relativize: function(element) {
3243
+ element = $(element);
3244
+ if (element.style.position == 'relative') return;
3245
+ Position.prepare();
3246
+
3247
+ element.style.position = 'relative';
3248
+ var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
3249
+ var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
3250
+
3251
+ element.style.top = top + 'px';
3252
+ element.style.left = left + 'px';
3253
+ element.style.height = element._originalHeight;
3254
+ element.style.width = element._originalWidth;
3255
+ }
3256
+ }
3257
+
3258
+ // Safari returns margins on body which is incorrect if the child is absolutely
3259
+ // positioned. For performance reasons, redefine Position.cumulativeOffset for
3260
+ // KHTML/WebKit only.
3261
+ if (Prototype.Browser.WebKit) {
3262
+ Position.cumulativeOffset = function(element) {
3263
+ var valueT = 0, valueL = 0;
3264
+ do {
3265
+ valueT += element.offsetTop || 0;
3266
+ valueL += element.offsetLeft || 0;
3267
+ if (element.offsetParent == document.body)
3268
+ if (Element.getStyle(element, 'position') == 'absolute') break;
3269
+
3270
+ element = element.offsetParent;
3271
+ } while (element);
3272
+
3273
+ return [valueL, valueT];
3274
+ }
3275
+ }
3276
+
3277
+ Element.addMethods();