1
/* Prototype JavaScript framework, version 1.5.1
2
* (c) 2005-2007 Sam Stephenson
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/
7
/*--------------------------------------------------------------------------*/
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
20
XPath: !!document.evaluate,
21
ElementExtensions: !!window.HTMLElement,
22
SpecificElementExtensions:
23
(document.createElement('div').__proto__ !==
24
document.createElement('form').__proto__)
27
ScriptFragment: '<script[^>]*>([\u0001-\uFFFF]*?)</script>',
28
JSONFilter: /^\/\*-secure-\s*(.*)\s*\*\/\s*$/,
30
emptyFunction: function() { },
31
K: function(x) { return x }
37
this.initialize.apply(this, arguments);
42
var Abstract = new Object();
44
Object.extend = function(destination, source) {
45
for (var property in source) {
46
destination[property] = source[property];
51
Object.extend(Object, {
52
inspect: function(object) {
54
if (object === undefined) return 'undefined';
55
if (object === null) return 'null';
56
return object.inspect ? object.inspect() : object.toString();
58
if (e instanceof RangeError) return '...';
63
toJSON: function(object) {
64
var type = typeof object;
68
case 'unknown': return;
69
case 'boolean': return object.toString();
71
if (object === null) return 'null';
72
if (object.toJSON) return object.toJSON();
73
if (object.ownerDocument === document) return;
75
for (var property in object) {
76
var value = Object.toJSON(object[property]);
77
if (value !== undefined)
78
results.push(property.toJSON() + ': ' + value);
80
return '{' + results.join(', ') + '}';
83
keys: function(object) {
85
for (var property in object)
90
values: function(object) {
92
for (var property in object)
93
values.push(object[property]);
97
clone: function(object) {
98
return Object.extend({}, object);
102
Function.prototype.bind = function() {
103
var __method = this, args = $A(arguments), object = args.shift();
105
return __method.apply(object, args.concat($A(arguments)));
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));
116
Object.extend(Number.prototype, {
117
toColorPart: function() {
118
return this.toPaddedString(2, 16);
125
times: function(iterator) {
126
$R(0, this, true).each(iterator);
130
toPaddedString: function(length, radix) {
131
var string = this.toString(radix || 10);
132
return '0'.times(length - string.length) + string;
136
return isFinite(this) ? this.toString() : 'null';
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) + '"';
153
for (var i = 0, length = arguments.length; i < length; i++) {
154
var lambda = arguments[i];
156
returnValue = lambda();
165
/*--------------------------------------------------------------------------*/
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;
174
this.registerCallback();
177
registerCallback: function() {
178
this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
182
if (!this.timer) return;
183
clearInterval(this.timer);
187
onTimerEvent: function() {
188
if (!this.currentlyExecuting) {
190
this.currentlyExecuting = true;
193
this.currentlyExecuting = false;
198
Object.extend(String, {
199
interpret: function(value) {
200
return value == null ? '' : String(value);
212
Object.extend(String.prototype, {
213
gsub: function(pattern, replacement) {
214
var result = '', source = this, match;
215
replacement = arguments.callee.prepareReplacement(replacement);
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);
223
result += source, source = '';
229
sub: function(pattern, replacement, count) {
230
replacement = this.gsub.prepareReplacement(replacement);
231
count = count === undefined ? 1 : count;
233
return this.gsub(pattern, function(match) {
234
if (--count < 0) return match[0];
235
return replacement(match);
239
scan: function(pattern, iterator) {
240
this.gsub(pattern, iterator);
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;
252
return this.replace(/^\s+/, '').replace(/\s+$/, '');
255
stripTags: function() {
256
return this.replace(/<\/?[^>]+>/gi, '');
259
stripScripts: function() {
260
return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
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];
271
evalScripts: function() {
272
return this.extractScripts().map(function(script) { return eval(script) });
275
escapeHTML: function() {
276
var self = arguments.callee;
277
self.text.data = this;
278
return self.div.innerHTML;
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) : '';
289
toQueryParams: function(separator) {
290
var match = this.strip().match(/([^?#]*)(#.*)?$/);
291
if (!match) return {};
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);
300
if (hash[key].constructor != Array) hash[key] = [hash[key]];
301
hash[key].push(value);
303
else hash[key] = value;
309
toArray: function() {
310
return this.split('');
314
return this.slice(0, this.length - 1) +
315
String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
318
times: function(count) {
320
for (var i = 0; i < count; i++) result += this;
324
camelize: function() {
325
var parts = this.split('-'), len = parts.length;
326
if (len == 1) return parts[0];
328
var camelized = this.charAt(0) == '-'
329
? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
332
for (var i = 1; i < len; i++)
333
camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
338
capitalize: function() {
339
return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
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();
346
dasherize: function() {
347
return this.gsub(/_/,'-');
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);
355
if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
356
return "'" + escapedString.replace(/'/g, '\\\'') + "'";
360
return this.inspect(true);
363
unfilterJSON: function(filter) {
364
return this.sub(filter || Prototype.JSONFilter, '#{1}');
367
evalJSON: function(sanitize) {
368
var json = this.unfilterJSON();
370
if (!sanitize || (/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.test(json)))
371
return eval('(' + json + ')');
373
throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
376
include: function(pattern) {
377
return this.indexOf(pattern) > -1;
380
startsWith: function(pattern) {
381
return this.indexOf(pattern) === 0;
384
endsWith: function(pattern) {
385
var d = this.length - pattern.length;
386
return d >= 0 && this.lastIndexOf(pattern) === d;
394
return /^\s*$/.test(this);
398
if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
399
escapeHTML: function() {
400
return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
402
unescapeHTML: function() {
403
return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
407
String.prototype.gsub.prepareReplacement = function(replacement) {
408
if (typeof replacement == 'function') return replacement;
409
var template = new Template(replacement);
410
return function(match) { return template.evaluate(match) };
413
String.prototype.parseQuery = String.prototype.toQueryParams;
415
Object.extend(String.prototype.escapeHTML, {
416
div: document.createElement('div'),
417
text: document.createTextNode('')
420
with (String.prototype.escapeHTML) div.appendChild(text);
422
var Template = Class.create();
423
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
424
Template.prototype = {
425
initialize: function(template, pattern) {
426
this.template = template.toString();
427
this.pattern = pattern || Template.Pattern;
430
evaluate: function(object) {
431
return this.template.gsub(this.pattern, function(match) {
432
var before = match[1];
433
if (before == '\\') return match[2];
434
return before + String.interpret(object[match[3]]);
439
var $break = {}, $continue = new Error('"throw $continue" is deprecated, use "return" instead');
442
each: function(iterator) {
445
this._each(function(value) {
446
iterator(value, index++);
449
if (e != $break) throw e;
454
eachSlice: function(number, iterator) {
455
var index = -number, slices = [], array = this.toArray();
456
while ((index += number) < array.length)
457
slices.push(array.slice(index, index+number));
458
return slices.map(iterator);
461
all: function(iterator) {
463
this.each(function(value, index) {
464
result = result && !!(iterator || Prototype.K)(value, index);
465
if (!result) throw $break;
470
any: function(iterator) {
472
this.each(function(value, index) {
473
if (result = !!(iterator || Prototype.K)(value, index))
479
collect: function(iterator) {
481
this.each(function(value, index) {
482
results.push((iterator || Prototype.K)(value, index));
487
detect: function(iterator) {
489
this.each(function(value, index) {
490
if (iterator(value, index)) {
498
findAll: function(iterator) {
500
this.each(function(value, index) {
501
if (iterator(value, index))
507
grep: function(pattern, iterator) {
509
this.each(function(value, index) {
510
var stringValue = value.toString();
511
if (stringValue.match(pattern))
512
results.push((iterator || Prototype.K)(value, index));
517
include: function(object) {
519
this.each(function(value) {
520
if (value == object) {
528
inGroupsOf: function(number, fillWith) {
529
fillWith = fillWith === undefined ? null : fillWith;
530
return this.eachSlice(number, function(slice) {
531
while(slice.length < number) slice.push(fillWith);
536
inject: function(memo, iterator) {
537
this.each(function(value, index) {
538
memo = iterator(memo, value, index);
543
invoke: function(method) {
544
var args = $A(arguments).slice(1);
545
return this.map(function(value) {
546
return value[method].apply(value, args);
550
max: function(iterator) {
552
this.each(function(value, index) {
553
value = (iterator || Prototype.K)(value, index);
554
if (result == undefined || value >= result)
560
min: function(iterator) {
562
this.each(function(value, index) {
563
value = (iterator || Prototype.K)(value, index);
564
if (result == undefined || value < result)
570
partition: function(iterator) {
571
var trues = [], falses = [];
572
this.each(function(value, index) {
573
((iterator || Prototype.K)(value, index) ?
574
trues : falses).push(value);
576
return [trues, falses];
579
pluck: function(property) {
581
this.each(function(value, index) {
582
results.push(value[property]);
587
reject: function(iterator) {
589
this.each(function(value, index) {
590
if (!iterator(value, index))
596
sortBy: function(iterator) {
597
return this.map(function(value, index) {
598
return {value: value, criteria: iterator(value, index)};
599
}).sort(function(left, right) {
600
var a = left.criteria, b = right.criteria;
601
return a < b ? -1 : a > b ? 1 : 0;
605
toArray: function() {
610
var iterator = Prototype.K, args = $A(arguments);
611
if (typeof args.last() == 'function')
612
iterator = args.pop();
614
var collections = [this].concat(args).map($A);
615
return this.map(function(value, index) {
616
return iterator(collections.pluck(index));
621
return this.toArray().length;
624
inspect: function() {
625
return '#<Enumerable:' + this.toArray().inspect() + '>';
629
Object.extend(Enumerable, {
630
map: Enumerable.collect,
631
find: Enumerable.detect,
632
select: Enumerable.findAll,
633
member: Enumerable.include,
634
entries: Enumerable.toArray
636
var $A = Array.from = function(iterable) {
637
if (!iterable) return [];
638
if (iterable.toArray) {
639
return iterable.toArray();
642
for (var i = 0, length = iterable.length; i < length; i++)
643
results.push(iterable[i]);
648
if (Prototype.Browser.WebKit) {
649
$A = Array.from = function(iterable) {
650
if (!iterable) return [];
651
if (!(typeof iterable == 'function' && iterable == '[object NodeList]') &&
653
return iterable.toArray();
656
for (var i = 0, length = iterable.length; i < length; i++)
657
results.push(iterable[i]);
663
Object.extend(Array.prototype, Enumerable);
665
if (!Array.prototype._reverse)
666
Array.prototype._reverse = Array.prototype.reverse;
668
Object.extend(Array.prototype, {
669
_each: function(iterator) {
670
for (var i = 0, length = this.length; i < length; i++)
684
return this[this.length - 1];
687
compact: function() {
688
return this.select(function(value) {
689
return value != null;
693
flatten: function() {
694
return this.inject([], function(array, value) {
695
return array.concat(value && value.constructor == Array ?
696
value.flatten() : [value]);
700
without: function() {
701
var values = $A(arguments);
702
return this.select(function(value) {
703
return !values.include(value);
707
indexOf: function(object) {
708
for (var i = 0, length = this.length; i < length; i++)
709
if (this[i] == object) return i;
713
reverse: function(inline) {
714
return (inline !== false ? this : this.toArray())._reverse();
718
return this.length > 1 ? this : this[0];
721
uniq: function(sorted) {
722
return this.inject([], function(array, value, index) {
723
if (0 == index || (sorted ? array.last() != value : !array.include(value)))
730
return [].concat(this);
737
inspect: function() {
738
return '[' + this.map(Object.inspect).join(', ') + ']';
743
this.each(function(object) {
744
var value = Object.toJSON(object);
745
if (value !== undefined) results.push(value);
747
return '[' + results.join(', ') + ']';
751
Array.prototype.toArray = Array.prototype.clone;
753
function $w(string) {
754
string = string.strip();
755
return string ? string.split(/\s+/) : [];
758
if (Prototype.Browser.Opera){
759
Array.prototype.concat = function() {
761
for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
762
for (var i = 0, length = arguments.length; i < length; i++) {
763
if (arguments[i].constructor == Array) {
764
for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
765
array.push(arguments[i][j]);
767
array.push(arguments[i]);
773
var Hash = function(object) {
774
if (object instanceof Hash) this.merge(object);
775
else Object.extend(this, object || {});
778
Object.extend(Hash, {
779
toQueryString: function(obj) {
781
parts.add = arguments.callee.addPair;
783
this.prototype._each.call(obj, function(pair) {
784
if (!pair.key) return;
785
var value = pair.value;
787
if (value && typeof value == 'object') {
788
if (value.constructor == Array) value.each(function(value) {
789
parts.add(pair.key, value);
793
parts.add(pair.key, value);
796
return parts.join('&');
799
toJSON: function(object) {
801
this.prototype._each.call(object, function(pair) {
802
var value = Object.toJSON(pair.value);
803
if (value !== undefined) results.push(pair.key.toJSON() + ': ' + value);
805
return '{' + results.join(', ') + '}';
809
Hash.toQueryString.addPair = function(key, value, prefix) {
810
key = encodeURIComponent(key);
811
if (value === undefined) this.push(key);
812
else this.push(key + '=' + (value == null ? '' : encodeURIComponent(value)));
815
Object.extend(Hash.prototype, Enumerable);
816
Object.extend(Hash.prototype, {
817
_each: function(iterator) {
818
for (var key in this) {
819
var value = this[key];
820
if (value && value == Hash.prototype[key]) continue;
822
var pair = [key, value];
830
return this.pluck('key');
834
return this.pluck('value');
837
merge: function(hash) {
838
return $H(hash).inject(this, function(mergedHash, pair) {
839
mergedHash[pair.key] = pair.value;
846
for(var i = 0, length = arguments.length; i < length; i++) {
847
var value = this[arguments[i]];
848
if (value !== undefined){
849
if (result === undefined) result = value;
851
if (result.constructor != Array) result = [result];
855
delete this[arguments[i]];
860
toQueryString: function() {
861
return Hash.toQueryString(this);
864
inspect: function() {
865
return '#<Hash:{' + this.map(function(pair) {
866
return pair.map(Object.inspect).join(': ');
867
}).join(', ') + '}>';
871
return Hash.toJSON(this);
875
function $H(object) {
876
if (object instanceof Hash) return object;
877
return new Hash(object);
880
// Safari iterates over shadowed properties
882
var i = 0, Test = function(value) { this.key = value };
883
Test.prototype.key = 'foo';
884
for (var property in new Test('bar')) i++;
886
}()) Hash.prototype._each = function(iterator) {
888
for (var key in this) {
889
var value = this[key];
890
if ((value && value == Hash.prototype[key]) || cache.include(key)) continue;
892
var pair = [key, value];
898
ObjectRange = Class.create();
899
Object.extend(ObjectRange.prototype, Enumerable);
900
Object.extend(ObjectRange.prototype, {
901
initialize: function(start, end, exclusive) {
904
this.exclusive = exclusive;
907
_each: function(iterator) {
908
var value = this.start;
909
while (this.include(value)) {
911
value = value.succ();
915
include: function(value) {
916
if (value < this.start)
919
return value < this.end;
920
return value <= this.end;
924
var $R = function(start, end, exclusive) {
925
return new ObjectRange(start, end, exclusive);
929
getTransport: function() {
931
function() {return new XMLHttpRequest()},
932
function() {return new ActiveXObject('Msxml2.XMLHTTP')},
933
function() {return new ActiveXObject('Microsoft.XMLHTTP')}
937
activeRequestCount: 0
943
_each: function(iterator) {
944
this.responders._each(iterator);
947
register: function(responder) {
948
if (!this.include(responder))
949
this.responders.push(responder);
952
unregister: function(responder) {
953
this.responders = this.responders.without(responder);
956
dispatch: function(callback, request, transport, json) {
957
this.each(function(responder) {
958
if (typeof responder[callback] == 'function') {
960
responder[callback].apply(responder, [request, transport, json]);
967
Object.extend(Ajax.Responders, Enumerable);
969
Ajax.Responders.register({
970
onCreate: function() {
971
Ajax.activeRequestCount++;
973
onComplete: function() {
974
Ajax.activeRequestCount--;
978
Ajax.Base = function() {};
979
Ajax.Base.prototype = {
980
setOptions: function(options) {
984
contentType: 'application/x-www-form-urlencoded',
988
Object.extend(this.options, options || {});
990
this.options.method = this.options.method.toLowerCase();
991
if (typeof this.options.parameters == 'string')
992
this.options.parameters = this.options.parameters.toQueryParams();
996
Ajax.Request = Class.create();
997
Ajax.Request.Events =
998
['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
1000
Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
1003
initialize: function(url, options) {
1004
this.transport = Ajax.getTransport();
1005
this.setOptions(options);
1009
request: function(url) {
1011
this.method = this.options.method;
1012
var params = Object.clone(this.options.parameters);
1014
if (!['get', 'post'].include(this.method)) {
1015
// simulate other verbs over post
1016
params['_method'] = this.method;
1017
this.method = 'post';
1020
this.parameters = params;
1022
if (params = Hash.toQueryString(params)) {
1023
// when GET, append parameters to URL
1024
if (this.method == 'get')
1025
this.url += (this.url.include('?') ? '&' : '?') + params;
1026
else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
1031
if (this.options.onCreate) this.options.onCreate(this.transport);
1032
Ajax.Responders.dispatch('onCreate', this, this.transport);
1034
this.transport.open(this.method.toUpperCase(), this.url,
1035
this.options.asynchronous);
1037
if (this.options.asynchronous)
1038
setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
1040
this.transport.onreadystatechange = this.onStateChange.bind(this);
1041
this.setRequestHeaders();
1043
this.body = this.method == 'post' ? (this.options.postBody || params) : null;
1044
this.transport.send(this.body);
1046
/* Force Firefox to handle ready state 4 for synchronous requests */
1047
if (!this.options.asynchronous && this.transport.overrideMimeType)
1048
this.onStateChange();
1052
this.dispatchException(e);
1056
onStateChange: function() {
1057
var readyState = this.transport.readyState;
1058
if (readyState > 1 && !((readyState == 4) && this._complete))
1059
this.respondToReadyState(this.transport.readyState);
1062
setRequestHeaders: function() {
1064
'X-Requested-With': 'XMLHttpRequest',
1065
'X-Prototype-Version': Prototype.Version,
1066
'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
1069
if (this.method == 'post') {
1070
headers['Content-type'] = this.options.contentType +
1071
(this.options.encoding ? '; charset=' + this.options.encoding : '');
1073
/* Force "Connection: close" for older Mozilla browsers to work
1074
* around a bug where XMLHttpRequest sends an incorrect
1075
* Content-length header. See Mozilla Bugzilla #246651.
1077
if (this.transport.overrideMimeType &&
1078
(navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
1079
headers['Connection'] = 'close';
1082
// user-defined headers
1083
if (typeof this.options.requestHeaders == 'object') {
1084
var extras = this.options.requestHeaders;
1086
if (typeof extras.push == 'function')
1087
for (var i = 0, length = extras.length; i < length; i += 2)
1088
headers[extras[i]] = extras[i+1];
1090
$H(extras).each(function(pair) { headers[pair.key] = pair.value });
1093
for (var name in headers)
1094
this.transport.setRequestHeader(name, headers[name]);
1097
success: function() {
1098
return !this.transport.status
1099
|| (this.transport.status >= 200 && this.transport.status < 300);
1102
respondToReadyState: function(readyState) {
1103
var state = Ajax.Request.Events[readyState];
1104
var transport = this.transport, json = this.evalJSON();
1106
if (state == 'Complete') {
1108
this._complete = true;
1109
(this.options['on' + this.transport.status]
1110
|| this.options['on' + (this.success() ? 'Success' : 'Failure')]
1111
|| Prototype.emptyFunction)(transport, json);
1113
this.dispatchException(e);
1116
var contentType = this.getHeader('Content-type');
1117
if (contentType && contentType.strip().
1118
match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
1119
this.evalResponse();
1123
(this.options['on' + state] || Prototype.emptyFunction)(transport, json);
1124
Ajax.Responders.dispatch('on' + state, this, transport, json);
1126
this.dispatchException(e);
1129
if (state == 'Complete') {
1130
// avoid memory leak in MSIE: clean up
1131
this.transport.onreadystatechange = Prototype.emptyFunction;
1135
getHeader: function(name) {
1137
return this.transport.getResponseHeader(name);
1138
} catch (e) { return null }
1141
evalJSON: function() {
1143
var json = this.getHeader('X-JSON');
1144
return json ? json.evalJSON() : null;
1145
} catch (e) { return null }
1148
evalResponse: function() {
1150
return eval((this.transport.responseText || '').unfilterJSON());
1152
this.dispatchException(e);
1156
dispatchException: function(exception) {
1157
(this.options.onException || Prototype.emptyFunction)(this, exception);
1158
Ajax.Responders.dispatch('onException', this, exception);
1162
Ajax.Updater = Class.create();
1164
Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
1165
initialize: function(container, url, options) {
1167
success: (container.success || container),
1168
failure: (container.failure || (container.success ? null : container))
1171
this.transport = Ajax.getTransport();
1172
this.setOptions(options);
1174
var onComplete = this.options.onComplete || Prototype.emptyFunction;
1175
this.options.onComplete = (function(transport, param) {
1176
this.updateContent();
1177
onComplete(transport, param);
1183
updateContent: function() {
1184
var receiver = this.container[this.success() ? 'success' : 'failure'];
1185
var response = this.transport.responseText;
1187
if (!this.options.evalScripts) response = response.stripScripts();
1189
if (receiver = $(receiver)) {
1190
if (this.options.insertion)
1191
new this.options.insertion(receiver, response);
1193
receiver.update(response);
1196
if (this.success()) {
1197
if (this.onComplete)
1198
setTimeout(this.onComplete.bind(this), 10);
1203
Ajax.PeriodicalUpdater = Class.create();
1204
Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
1205
initialize: function(container, url, options) {
1206
this.setOptions(options);
1207
this.onComplete = this.options.onComplete;
1209
this.frequency = (this.options.frequency || 2);
1210
this.decay = (this.options.decay || 1);
1213
this.container = container;
1220
this.options.onComplete = this.updateComplete.bind(this);
1221
this.onTimerEvent();
1225
this.updater.options.onComplete = undefined;
1226
clearTimeout(this.timer);
1227
(this.onComplete || Prototype.emptyFunction).apply(this, arguments);
1230
updateComplete: function(request) {
1231
if (this.options.decay) {
1232
this.decay = (request.responseText == this.lastText ?
1233
this.decay * this.options.decay : 1);
1235
this.lastText = request.responseText;
1237
this.timer = setTimeout(this.onTimerEvent.bind(this),
1238
this.decay * this.frequency * 1000);
1241
onTimerEvent: function() {
1242
this.updater = new Ajax.Updater(this.container, this.url, this.options);
1245
function $(element) {
1246
if (arguments.length > 1) {
1247
for (var i = 0, elements = [], length = arguments.length; i < length; i++)
1248
elements.push($(arguments[i]));
1251
if (typeof element == 'string')
1252
element = document.getElementById(element);
1253
return Element.extend(element);
1256
if (Prototype.BrowserFeatures.XPath) {
1257
document._getElementsByXPath = function(expression, parentElement) {
1259
var query = document.evaluate(expression, $(parentElement) || document,
1260
null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
1261
for (var i = 0, length = query.snapshotLength; i < length; i++)
1262
results.push(query.snapshotItem(i));
1266
document.getElementsByClassName = function(className, parentElement) {
1267
var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
1268
return document._getElementsByXPath(q, parentElement);
1271
} else document.getElementsByClassName = function(className, parentElement) {
1272
var children = ($(parentElement) || document.body).getElementsByTagName('*');
1273
var elements = [], child;
1274
for (var i = 0, length = children.length; i < length; i++) {
1275
child = children[i];
1276
if (Element.hasClassName(child, className))
1277
elements.push(Element.extend(child));
1282
/*--------------------------------------------------------------------------*/
1284
if (!window.Element) var Element = {};
1286
Element.extend = function(element) {
1287
var F = Prototype.BrowserFeatures;
1288
if (!element || !element.tagName || element.nodeType == 3 ||
1289
element._extended || F.SpecificElementExtensions || element == window)
1292
var methods = {}, tagName = element.tagName, cache = Element.extend.cache,
1293
T = Element.Methods.ByTag;
1295
// extend methods for all tags (Safari doesn't need this)
1296
if (!F.ElementExtensions) {
1297
Object.extend(methods, Element.Methods),
1298
Object.extend(methods, Element.Methods.Simulated);
1301
// extend methods for specific tags
1302
if (T[tagName]) Object.extend(methods, T[tagName]);
1304
for (var property in methods) {
1305
var value = methods[property];
1306
if (typeof value == 'function' && !(property in element))
1307
element[property] = cache.findOrStore(value);
1310
element._extended = Prototype.emptyFunction;
1314
Element.extend.cache = {
1315
findOrStore: function(value) {
1316
return this[value] = this[value] || function() {
1317
return value.apply(null, [this].concat($A(arguments)));
1323
visible: function(element) {
1324
return $(element).style.display != 'none';
1327
toggle: function(element) {
1328
element = $(element);
1329
Element[Element.visible(element) ? 'hide' : 'show'](element);
1333
hide: function(element) {
1334
$(element).style.display = 'none';
1338
show: function(element) {
1339
$(element).style.display = '';
1343
remove: function(element) {
1344
element = $(element);
1345
element.parentNode.removeChild(element);
1349
update: function(element, html) {
1350
html = typeof html == 'undefined' ? '' : html.toString();
1351
$(element).innerHTML = html.stripScripts();
1352
setTimeout(function() {html.evalScripts()}, 10);
1356
replace: function(element, html) {
1357
element = $(element);
1358
html = typeof html == 'undefined' ? '' : html.toString();
1359
if (element.outerHTML) {
1360
element.outerHTML = html.stripScripts();
1362
var range = element.ownerDocument.createRange();
1363
range.selectNodeContents(element);
1364
element.parentNode.replaceChild(
1365
range.createContextualFragment(html.stripScripts()), element);
1367
setTimeout(function() {html.evalScripts()}, 10);
1371
inspect: function(element) {
1372
element = $(element);
1373
var result = '<' + element.tagName.toLowerCase();
1374
$H({'id': 'id', 'className': 'class'}).each(function(pair) {
1375
var property = pair.first(), attribute = pair.last();
1376
var value = (element[property] || '').toString();
1377
if (value) result += ' ' + attribute + '=' + value.inspect(true);
1379
return result + '>';
1382
recursivelyCollect: function(element, property) {
1383
element = $(element);
1385
while (element = element[property])
1386
if (element.nodeType == 1)
1387
elements.push(Element.extend(element));
1391
ancestors: function(element) {
1392
return $(element).recursivelyCollect('parentNode');
1395
descendants: function(element) {
1396
return $A($(element).getElementsByTagName('*')).each(Element.extend);
1399
firstDescendant: function(element) {
1400
element = $(element).firstChild;
1401
while (element && element.nodeType != 1) element = element.nextSibling;
1405
immediateDescendants: function(element) {
1406
if (!(element = $(element).firstChild)) return [];
1407
while (element && element.nodeType != 1) element = element.nextSibling;
1408
if (element) return [element].concat($(element).nextSiblings());
1412
previousSiblings: function(element) {
1413
return $(element).recursivelyCollect('previousSibling');
1416
nextSiblings: function(element) {
1417
return $(element).recursivelyCollect('nextSibling');
1420
siblings: function(element) {
1421
element = $(element);
1422
return element.previousSiblings().reverse().concat(element.nextSiblings());
1425
match: function(element, selector) {
1426
if (typeof selector == 'string')
1427
selector = new Selector(selector);
1428
return selector.match($(element));
1431
up: function(element, expression, index) {
1432
element = $(element);
1433
if (arguments.length == 1) return $(element.parentNode);
1434
var ancestors = element.ancestors();
1435
return expression ? Selector.findElement(ancestors, expression, index) :
1436
ancestors[index || 0];
1439
down: function(element, expression, index) {
1440
element = $(element);
1441
if (arguments.length == 1) return element.firstDescendant();
1442
var descendants = element.descendants();
1443
return expression ? Selector.findElement(descendants, expression, index) :
1444
descendants[index || 0];
1447
previous: function(element, expression, index) {
1448
element = $(element);
1449
if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
1450
var previousSiblings = element.previousSiblings();
1451
return expression ? Selector.findElement(previousSiblings, expression, index) :
1452
previousSiblings[index || 0];
1455
next: function(element, expression, index) {
1456
element = $(element);
1457
if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
1458
var nextSiblings = element.nextSiblings();
1459
return expression ? Selector.findElement(nextSiblings, expression, index) :
1460
nextSiblings[index || 0];
1463
getElementsBySelector: function() {
1464
var args = $A(arguments), element = $(args.shift());
1465
return Selector.findChildElements(element, args);
1468
getElementsByClassName: function(element, className) {
1469
return document.getElementsByClassName(className, element);
1472
readAttribute: function(element, name) {
1473
element = $(element);
1474
if (Prototype.Browser.IE) {
1475
if (!element.attributes) return null;
1476
var t = Element._attributeTranslations;
1477
if (t.values[name]) return t.values[name](element, name);
1478
if (t.names[name]) name = t.names[name];
1479
var attribute = element.attributes[name];
1480
return attribute ? attribute.nodeValue : null;
1482
return element.getAttribute(name);
1485
getHeight: function(element) {
1486
return $(element).getDimensions().height;
1489
getWidth: function(element) {
1490
return $(element).getDimensions().width;
1493
classNames: function(element) {
1494
return new Element.ClassNames(element);
1497
hasClassName: function(element, className) {
1498
if (!(element = $(element))) return;
1499
var elementClassName = element.className;
1500
if (elementClassName.length == 0) return false;
1501
if (elementClassName == className ||
1502
elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
1507
addClassName: function(element, className) {
1508
if (!(element = $(element))) return;
1509
Element.classNames(element).add(className);
1513
removeClassName: function(element, className) {
1514
if (!(element = $(element))) return;
1515
Element.classNames(element).remove(className);
1519
toggleClassName: function(element, className) {
1520
if (!(element = $(element))) return;
1521
Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
1525
observe: function() {
1526
Event.observe.apply(Event, arguments);
1527
return $A(arguments).first();
1530
stopObserving: function() {
1531
Event.stopObserving.apply(Event, arguments);
1532
return $A(arguments).first();
1535
// removes whitespace-only text node children
1536
cleanWhitespace: function(element) {
1537
element = $(element);
1538
var node = element.firstChild;
1540
var nextNode = node.nextSibling;
1541
if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
1542
element.removeChild(node);
1548
empty: function(element) {
1549
return $(element).innerHTML.blank();
1552
descendantOf: function(element, ancestor) {
1553
element = $(element), ancestor = $(ancestor);
1554
while (element = element.parentNode)
1555
if (element == ancestor) return true;
1559
scrollTo: function(element) {
1560
element = $(element);
1561
var pos = Position.cumulativeOffset(element);
1562
window.scrollTo(pos[0], pos[1]);
1566
getStyle: function(element, style) {
1567
element = $(element);
1568
style = style == 'float' ? 'cssFloat' : style.camelize();
1569
var value = element.style[style];
1571
var css = document.defaultView.getComputedStyle(element, null);
1572
value = css ? css[style] : null;
1574
if (style == 'opacity') return value ? parseFloat(value) : 1.0;
1575
return value == 'auto' ? null : value;
1578
getOpacity: function(element) {
1579
return $(element).getStyle('opacity');
1582
setStyle: function(element, styles, camelized) {
1583
element = $(element);
1584
var elementStyle = element.style;
1586
for (var property in styles)
1587
if (property == 'opacity') element.setOpacity(styles[property])
1589
elementStyle[(property == 'float' || property == 'cssFloat') ?
1590
(elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') :
1591
(camelized ? property : property.camelize())] = styles[property];
1596
setOpacity: function(element, value) {
1597
element = $(element);
1598
element.style.opacity = (value == 1 || value === '') ? '' :
1599
(value < 0.00001) ? 0 : value;
1603
getDimensions: function(element) {
1604
element = $(element);
1605
var display = $(element).getStyle('display');
1606
if (display != 'none' && display != null) // Safari bug
1607
return {width: element.offsetWidth, height: element.offsetHeight};
1609
// All *Width and *Height properties give 0 on elements with display none,
1610
// so enable the element temporarily
1611
var els = element.style;
1612
var originalVisibility = els.visibility;
1613
var originalPosition = els.position;
1614
var originalDisplay = els.display;
1615
els.visibility = 'hidden';
1616
els.position = 'absolute';
1617
els.display = 'block';
1618
var originalWidth = element.clientWidth;
1619
var originalHeight = element.clientHeight;
1620
els.display = originalDisplay;
1621
els.position = originalPosition;
1622
els.visibility = originalVisibility;
1623
return {width: originalWidth, height: originalHeight};
1626
makePositioned: function(element) {
1627
element = $(element);
1628
var pos = Element.getStyle(element, 'position');
1629
if (pos == 'static' || !pos) {
1630
element._madePositioned = true;
1631
element.style.position = 'relative';
1632
// Opera returns the offset relative to the positioning context, when an
1633
// element is position relative but top and left have not been defined
1635
element.style.top = 0;
1636
element.style.left = 0;
1642
undoPositioned: function(element) {
1643
element = $(element);
1644
if (element._madePositioned) {
1645
element._madePositioned = undefined;
1646
element.style.position =
1648
element.style.left =
1649
element.style.bottom =
1650
element.style.right = '';
1655
makeClipping: function(element) {
1656
element = $(element);
1657
if (element._overflow) return element;
1658
element._overflow = element.style.overflow || 'auto';
1659
if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
1660
element.style.overflow = 'hidden';
1664
undoClipping: function(element) {
1665
element = $(element);
1666
if (!element._overflow) return element;
1667
element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
1668
element._overflow = null;
1673
Object.extend(Element.Methods, {
1674
childOf: Element.Methods.descendantOf,
1675
childElements: Element.Methods.immediateDescendants
1678
if (Prototype.Browser.Opera) {
1679
Element.Methods._getStyle = Element.Methods.getStyle;
1680
Element.Methods.getStyle = function(element, style) {
1686
if (Element._getStyle(element, 'position') == 'static') return null;
1687
default: return Element._getStyle(element, style);
1691
else if (Prototype.Browser.IE) {
1692
Element.Methods.getStyle = function(element, style) {
1693
element = $(element);
1694
style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
1695
var value = element.style[style];
1696
if (!value && element.currentStyle) value = element.currentStyle[style];
1698
if (style == 'opacity') {
1699
if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
1700
if (value[1]) return parseFloat(value[1]) / 100;
1704
if (value == 'auto') {
1705
if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
1706
return element['offset'+style.capitalize()] + 'px';
1712
Element.Methods.setOpacity = function(element, value) {
1713
element = $(element);
1714
var filter = element.getStyle('filter'), style = element.style;
1715
if (value == 1 || value === '') {
1716
style.filter = filter.replace(/alpha\([^\)]*\)/gi,'');
1718
} else if (value < 0.00001) value = 0;
1719
style.filter = filter.replace(/alpha\([^\)]*\)/gi, '') +
1720
'alpha(opacity=' + (value * 100) + ')';
1724
// IE is missing .innerHTML support for TABLE-related elements
1725
Element.Methods.update = function(element, html) {
1726
element = $(element);
1727
html = typeof html == 'undefined' ? '' : html.toString();
1728
var tagName = element.tagName.toUpperCase();
1729
if (['THEAD','TBODY','TR','TD'].include(tagName)) {
1730
var div = document.createElement('div');
1734
div.innerHTML = '<table><tbody>' + html.stripScripts() + '</tbody></table>';
1738
div.innerHTML = '<table><tbody><tr>' + html.stripScripts() + '</tr></tbody></table>';
1742
div.innerHTML = '<table><tbody><tr><td>' + html.stripScripts() + '</td></tr></tbody></table>';
1745
$A(element.childNodes).each(function(node) { element.removeChild(node) });
1746
depth.times(function() { div = div.firstChild });
1747
$A(div.childNodes).each(function(node) { element.appendChild(node) });
1749
element.innerHTML = html.stripScripts();
1751
setTimeout(function() { html.evalScripts() }, 10);
1755
else if (Prototype.Browser.Gecko) {
1756
Element.Methods.setOpacity = function(element, value) {
1757
element = $(element);
1758
element.style.opacity = (value == 1) ? 0.999999 :
1759
(value === '') ? '' : (value < 0.00001) ? 0 : value;
1764
Element._attributeTranslations = {
1769
datetime: "dateTime",
1770
accesskey: "accessKey",
1771
tabindex: "tabIndex",
1773
maxlength: "maxLength",
1774
readonly: "readOnly",
1775
longdesc: "longDesc"
1778
_getAttr: function(element, attribute) {
1779
return element.getAttribute(attribute, 2);
1781
_flag: function(element, attribute) {
1782
return $(element).hasAttribute(attribute) ? attribute : null;
1784
style: function(element) {
1785
return element.style.cssText.toLowerCase();
1787
title: function(element) {
1788
var node = element.getAttributeNode('title');
1789
return node.specified ? node.nodeValue : null;
1795
Object.extend(this, {
1796
href: this._getAttr,
1798
type: this._getAttr,
1799
disabled: this._flag,
1800
checked: this._flag,
1801
readonly: this._flag,
1802
multiple: this._flag
1804
}).call(Element._attributeTranslations.values);
1806
Element.Methods.Simulated = {
1807
hasAttribute: function(element, attribute) {
1808
var t = Element._attributeTranslations, node;
1809
attribute = t.names[attribute] || attribute;
1810
node = $(element).getAttributeNode(attribute);
1811
return node && node.specified;
1815
Element.Methods.ByTag = {};
1817
Object.extend(Element, Element.Methods);
1819
if (!Prototype.BrowserFeatures.ElementExtensions &&
1820
document.createElement('div').__proto__) {
1821
window.HTMLElement = {};
1822
window.HTMLElement.prototype = document.createElement('div').__proto__;
1823
Prototype.BrowserFeatures.ElementExtensions = true;
1826
Element.hasAttribute = function(element, attribute) {
1827
if (element.hasAttribute) return element.hasAttribute(attribute);
1828
return Element.Methods.Simulated.hasAttribute(element, attribute);
1831
Element.addMethods = function(methods) {
1832
var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
1835
Object.extend(Form, Form.Methods);
1836
Object.extend(Form.Element, Form.Element.Methods);
1837
Object.extend(Element.Methods.ByTag, {
1838
"FORM": Object.clone(Form.Methods),
1839
"INPUT": Object.clone(Form.Element.Methods),
1840
"SELECT": Object.clone(Form.Element.Methods),
1841
"TEXTAREA": Object.clone(Form.Element.Methods)
1845
if (arguments.length == 2) {
1846
var tagName = methods;
1847
methods = arguments[1];
1850
if (!tagName) Object.extend(Element.Methods, methods || {});
1852
if (tagName.constructor == Array) tagName.each(extend);
1853
else extend(tagName);
1856
function extend(tagName) {
1857
tagName = tagName.toUpperCase();
1858
if (!Element.Methods.ByTag[tagName])
1859
Element.Methods.ByTag[tagName] = {};
1860
Object.extend(Element.Methods.ByTag[tagName], methods);
1863
function copy(methods, destination, onlyIfAbsent) {
1864
onlyIfAbsent = onlyIfAbsent || false;
1865
var cache = Element.extend.cache;
1866
for (var property in methods) {
1867
var value = methods[property];
1868
if (!onlyIfAbsent || !(property in destination))
1869
destination[property] = cache.findOrStore(value);
1873
function findDOMClass(tagName) {
1876
"OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
1877
"FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
1878
"DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
1879
"H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
1880
"INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
1881
"TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
1882
"TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
1883
"TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
1884
"FrameSet", "IFRAME": "IFrame"
1886
if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
1887
if (window[klass]) return window[klass];
1888
klass = 'HTML' + tagName + 'Element';
1889
if (window[klass]) return window[klass];
1890
klass = 'HTML' + tagName.capitalize() + 'Element';
1891
if (window[klass]) return window[klass];
1894
window[klass].prototype = document.createElement(tagName).__proto__;
1895
return window[klass];
1898
if (F.ElementExtensions) {
1899
copy(Element.Methods, HTMLElement.prototype);
1900
copy(Element.Methods.Simulated, HTMLElement.prototype, true);
1903
if (F.SpecificElementExtensions) {
1904
for (var tag in Element.Methods.ByTag) {
1905
var klass = findDOMClass(tag);
1906
if (typeof klass == "undefined") continue;
1907
copy(T[tag], klass.prototype);
1911
Object.extend(Element, Element.Methods);
1912
delete Element.ByTag;
1915
var Toggle = { display: Element.toggle };
1917
/*--------------------------------------------------------------------------*/
1919
Abstract.Insertion = function(adjacency) {
1920
this.adjacency = adjacency;
1923
Abstract.Insertion.prototype = {
1924
initialize: function(element, content) {
1925
this.element = $(element);
1926
this.content = content.stripScripts();
1928
if (this.adjacency && this.element.insertAdjacentHTML) {
1930
this.element.insertAdjacentHTML(this.adjacency, this.content);
1932
var tagName = this.element.tagName.toUpperCase();
1933
if (['TBODY', 'TR'].include(tagName)) {
1934
this.insertContent(this.contentFromAnonymousTable());
1940
this.range = this.element.ownerDocument.createRange();
1941
if (this.initializeRange) this.initializeRange();
1942
this.insertContent([this.range.createContextualFragment(this.content)]);
1945
setTimeout(function() {content.evalScripts()}, 10);
1948
contentFromAnonymousTable: function() {
1949
var div = document.createElement('div');
1950
div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
1951
return $A(div.childNodes[0].childNodes[0].childNodes);
1955
var Insertion = new Object();
1957
Insertion.Before = Class.create();
1958
Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
1959
initializeRange: function() {
1960
this.range.setStartBefore(this.element);
1963
insertContent: function(fragments) {
1964
fragments.each((function(fragment) {
1965
this.element.parentNode.insertBefore(fragment, this.element);
1970
Insertion.Top = Class.create();
1971
Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
1972
initializeRange: function() {
1973
this.range.selectNodeContents(this.element);
1974
this.range.collapse(true);
1977
insertContent: function(fragments) {
1978
fragments.reverse(false).each((function(fragment) {
1979
this.element.insertBefore(fragment, this.element.firstChild);
1984
Insertion.Bottom = Class.create();
1985
Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
1986
initializeRange: function() {
1987
this.range.selectNodeContents(this.element);
1988
this.range.collapse(this.element);
1991
insertContent: function(fragments) {
1992
fragments.each((function(fragment) {
1993
this.element.appendChild(fragment);
1998
Insertion.After = Class.create();
1999
Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
2000
initializeRange: function() {
2001
this.range.setStartAfter(this.element);
2004
insertContent: function(fragments) {
2005
fragments.each((function(fragment) {
2006
this.element.parentNode.insertBefore(fragment,
2007
this.element.nextSibling);
2012
/*--------------------------------------------------------------------------*/
2014
Element.ClassNames = Class.create();
2015
Element.ClassNames.prototype = {
2016
initialize: function(element) {
2017
this.element = $(element);
2020
_each: function(iterator) {
2021
this.element.className.split(/\s+/).select(function(name) {
2022
return name.length > 0;
2026
set: function(className) {
2027
this.element.className = className;
2030
add: function(classNameToAdd) {
2031
if (this.include(classNameToAdd)) return;
2032
this.set($A(this).concat(classNameToAdd).join(' '));
2035
remove: function(classNameToRemove) {
2036
if (!this.include(classNameToRemove)) return;
2037
this.set($A(this).without(classNameToRemove).join(' '));
2040
toString: function() {
2041
return $A(this).join(' ');
2045
Object.extend(Element.ClassNames.prototype, Enumerable);
2046
/* Portions of the Selector class are derived from Jack Slocum’s DomQuery,
2047
* part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
2048
* license. Please see http://www.yui-ext.com/ for more information. */
2050
var Selector = Class.create();
2052
Selector.prototype = {
2053
initialize: function(expression) {
2054
this.expression = expression.strip();
2055
this.compileMatcher();
2058
compileMatcher: function() {
2059
// Selectors with namespaced attributes can't use the XPath version
2060
if (Prototype.BrowserFeatures.XPath && !(/\[[\w-]*?:/).test(this.expression))
2061
return this.compileXPathMatcher();
2063
var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
2064
c = Selector.criteria, le, p, m;
2066
if (Selector._cache[e]) {
2067
this.matcher = Selector._cache[e]; return;
2069
this.matcher = ["this.matcher = function(root) {",
2070
"var r = root, h = Selector.handlers, c = false, n;"];
2072
while (e && le != e && (/\S/).test(e)) {
2076
if (m = e.match(p)) {
2077
this.matcher.push(typeof c[i] == 'function' ? c[i](m) :
2078
new Template(c[i]).evaluate(m));
2079
e = e.replace(m[0], '');
2085
this.matcher.push("return h.unique(n);\n}");
2086
eval(this.matcher.join('\n'));
2087
Selector._cache[this.expression] = this.matcher;
2090
compileXPathMatcher: function() {
2091
var e = this.expression, ps = Selector.patterns,
2092
x = Selector.xpath, le, m;
2094
if (Selector._cache[e]) {
2095
this.xpath = Selector._cache[e]; return;
2098
this.matcher = ['.//*'];
2099
while (e && le != e && (/\S/).test(e)) {
2102
if (m = e.match(ps[i])) {
2103
this.matcher.push(typeof x[i] == 'function' ? x[i](m) :
2104
new Template(x[i]).evaluate(m));
2105
e = e.replace(m[0], '');
2111
this.xpath = this.matcher.join('');
2112
Selector._cache[this.expression] = this.xpath;
2115
findElements: function(root) {
2116
root = root || document;
2117
if (this.xpath) return document._getElementsByXPath(this.xpath, root);
2118
return this.matcher(root);
2121
match: function(element) {
2122
return this.findElements(document).include(element);
2125
toString: function() {
2126
return this.expression;
2129
inspect: function() {
2130
return "#<Selector:" + this.expression.inspect() + ">";
2134
Object.extend(Selector, {
2140
adjacent: "/following-sibling::*[1]",
2141
laterSibling: '/following-sibling::*',
2142
tagName: function(m) {
2143
if (m[1] == '*') return '';
2144
return "[local-name()='" + m[1].toLowerCase() +
2145
"' or local-name()='" + m[1].toUpperCase() + "']";
2147
className: "[contains(concat(' ', @class, ' '), ' #{1} ')]",
2149
attrPresence: "[@#{1}]",
2151
m[3] = m[5] || m[6];
2152
return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
2154
pseudo: function(m) {
2155
var h = Selector.xpath.pseudos[m[1]];
2157
if (typeof h === 'function') return h(m);
2158
return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
2161
'=': "[@#{1}='#{3}']",
2162
'!=': "[@#{1}!='#{3}']",
2163
'^=': "[starts-with(@#{1}, '#{3}')]",
2164
'$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
2165
'*=': "[contains(@#{1}, '#{3}')]",
2166
'~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
2167
'|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
2170
'first-child': '[not(preceding-sibling::*)]',
2171
'last-child': '[not(following-sibling::*)]',
2172
'only-child': '[not(preceding-sibling::* or following-sibling::*)]',
2173
'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
2174
'checked': "[@checked]",
2175
'disabled': "[@disabled]",
2176
'enabled': "[not(@disabled)]",
2177
'not': function(m) {
2178
var e = m[6], p = Selector.patterns,
2179
x = Selector.xpath, le, m, v;
2182
while (e && le != e && (/\S/).test(e)) {
2185
if (m = e.match(p[i])) {
2186
v = typeof x[i] == 'function' ? x[i](m) : new Template(x[i]).evaluate(m);
2187
exclusion.push("(" + v.substring(1, v.length - 1) + ")");
2188
e = e.replace(m[0], '');
2193
return "[not(" + exclusion.join(" and ") + ")]";
2195
'nth-child': function(m) {
2196
return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
2198
'nth-last-child': function(m) {
2199
return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
2201
'nth-of-type': function(m) {
2202
return Selector.xpath.pseudos.nth("position() ", m);
2204
'nth-last-of-type': function(m) {
2205
return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
2207
'first-of-type': function(m) {
2208
m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
2210
'last-of-type': function(m) {
2211
m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
2213
'only-of-type': function(m) {
2214
var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
2216
nth: function(fragment, m) {
2217
var mm, formula = m[6], predicate;
2218
if (formula == 'even') formula = '2n+0';
2219
if (formula == 'odd') formula = '2n+1';
2220
if (mm = formula.match(/^(\d+)$/)) // digit only
2221
return '[' + fragment + "= " + mm[1] + ']';
2222
if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
2223
if (mm[1] == "-") mm[1] = -1;
2224
var a = mm[1] ? Number(mm[1]) : 1;
2225
var b = mm[2] ? Number(mm[2]) : 0;
2226
predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
2227
"((#{fragment} - #{b}) div #{a} >= 0)]";
2228
return new Template(predicate).evaluate({
2229
fragment: fragment, a: a, b: b });
2236
tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
2237
className: 'n = h.className(n, r, "#{1}", c); c = false;',
2238
id: 'n = h.id(n, r, "#{1}", c); c = false;',
2239
attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
2241
m[3] = (m[5] || m[6]);
2242
return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
2244
pseudo: function(m) {
2245
if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
2246
return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
2248
descendant: 'c = "descendant";',
2249
child: 'c = "child";',
2250
adjacent: 'c = "adjacent";',
2251
laterSibling: 'c = "laterSibling";'
2255
// combinators must be listed first
2256
// (and descendant needs to be last combinator)
2257
laterSibling: /^\s*~\s*/,
2259
adjacent: /^\s*\+\s*/,
2263
tagName: /^\s*(\*|[\w\-]+)(\b|$)?/,
2264
id: /^#([\w\-\*]+)(\b|$)/,
2265
className: /^\.([\w\-\*]+)(\b|$)/,
2266
pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|\s|(?=:))/,
2267
attrPresence: /^\[([\w]+)\]/,
2268
attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\]]*?)\4|([^'"][^\]]*?)))?\]/
2272
// UTILITY FUNCTIONS
2273
// joins two collections
2274
concat: function(a, b) {
2275
for (var i = 0, node; node = b[i]; i++)
2280
// marks an array of nodes for counting
2281
mark: function(nodes) {
2282
for (var i = 0, node; node = nodes[i]; i++)
2283
node._counted = true;
2287
unmark: function(nodes) {
2288
for (var i = 0, node; node = nodes[i]; i++)
2289
node._counted = undefined;
2293
// mark each child node with its position (for nth calls)
2294
// "ofType" flag indicates whether we're indexing for nth-of-type
2295
// rather than nth-child
2296
index: function(parentNode, reverse, ofType) {
2297
parentNode._counted = true;
2299
for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
2301
if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
2304
for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
2305
if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
2309
// filters out duplicates and extends all nodes
2310
unique: function(nodes) {
2311
if (nodes.length == 0) return nodes;
2312
var results = [], n;
2313
for (var i = 0, l = nodes.length; i < l; i++)
2314
if (!(n = nodes[i])._counted) {
2316
results.push(Element.extend(n));
2318
return Selector.handlers.unmark(results);
2321
// COMBINATOR FUNCTIONS
2322
descendant: function(nodes) {
2323
var h = Selector.handlers;
2324
for (var i = 0, results = [], node; node = nodes[i]; i++)
2325
h.concat(results, node.getElementsByTagName('*'));
2329
child: function(nodes) {
2330
var h = Selector.handlers;
2331
for (var i = 0, results = [], node; node = nodes[i]; i++) {
2332
for (var j = 0, children = [], child; child = node.childNodes[j]; j++)
2333
if (child.nodeType == 1 && child.tagName != '!') results.push(child);
2338
adjacent: function(nodes) {
2339
for (var i = 0, results = [], node; node = nodes[i]; i++) {
2340
var next = this.nextElementSibling(node);
2341
if (next) results.push(next);
2346
laterSibling: function(nodes) {
2347
var h = Selector.handlers;
2348
for (var i = 0, results = [], node; node = nodes[i]; i++)
2349
h.concat(results, Element.nextSiblings(node));
2353
nextElementSibling: function(node) {
2354
while (node = node.nextSibling)
2355
if (node.nodeType == 1) return node;
2359
previousElementSibling: function(node) {
2360
while (node = node.previousSibling)
2361
if (node.nodeType == 1) return node;
2366
tagName: function(nodes, root, tagName, combinator) {
2367
tagName = tagName.toUpperCase();
2368
var results = [], h = Selector.handlers;
2371
// fastlane for ordinary descendant combinators
2372
if (combinator == "descendant") {
2373
for (var i = 0, node; node = nodes[i]; i++)
2374
h.concat(results, node.getElementsByTagName(tagName));
2376
} else nodes = this[combinator](nodes);
2377
if (tagName == "*") return nodes;
2379
for (var i = 0, node; node = nodes[i]; i++)
2380
if (node.tagName.toUpperCase() == tagName) results.push(node);
2382
} else return root.getElementsByTagName(tagName);
2385
id: function(nodes, root, id, combinator) {
2386
var targetNode = $(id), h = Selector.handlers;
2387
if (!nodes && root == document) return targetNode ? [targetNode] : [];
2390
if (combinator == 'child') {
2391
for (var i = 0, node; node = nodes[i]; i++)
2392
if (targetNode.parentNode == node) return [targetNode];
2393
} else if (combinator == 'descendant') {
2394
for (var i = 0, node; node = nodes[i]; i++)
2395
if (Element.descendantOf(targetNode, node)) return [targetNode];
2396
} else if (combinator == 'adjacent') {
2397
for (var i = 0, node; node = nodes[i]; i++)
2398
if (Selector.handlers.previousElementSibling(targetNode) == node)
2399
return [targetNode];
2400
} else nodes = h[combinator](nodes);
2402
for (var i = 0, node; node = nodes[i]; i++)
2403
if (node == targetNode) return [targetNode];
2406
return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
2409
className: function(nodes, root, className, combinator) {
2410
if (nodes && combinator) nodes = this[combinator](nodes);
2411
return Selector.handlers.byClassName(nodes, root, className);
2414
byClassName: function(nodes, root, className) {
2415
if (!nodes) nodes = Selector.handlers.descendant([root]);
2416
var needle = ' ' + className + ' ';
2417
for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
2418
nodeClassName = node.className;
2419
if (nodeClassName.length == 0) continue;
2420
if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
2426
attrPresence: function(nodes, root, attr) {
2428
for (var i = 0, node; node = nodes[i]; i++)
2429
if (Element.hasAttribute(node, attr)) results.push(node);
2433
attr: function(nodes, root, attr, value, operator) {
2434
if (!nodes) nodes = root.getElementsByTagName("*");
2435
var handler = Selector.operators[operator], results = [];
2436
for (var i = 0, node; node = nodes[i]; i++) {
2437
var nodeValue = Element.readAttribute(node, attr);
2438
if (nodeValue === null) continue;
2439
if (handler(nodeValue, value)) results.push(node);
2444
pseudo: function(nodes, name, value, root, combinator) {
2445
if (nodes && combinator) nodes = this[combinator](nodes);
2446
if (!nodes) nodes = root.getElementsByTagName("*");
2447
return Selector.pseudos[name](nodes, value, root);
2452
'first-child': function(nodes, value, root) {
2453
for (var i = 0, results = [], node; node = nodes[i]; i++) {
2454
if (Selector.handlers.previousElementSibling(node)) continue;
2459
'last-child': function(nodes, value, root) {
2460
for (var i = 0, results = [], node; node = nodes[i]; i++) {
2461
if (Selector.handlers.nextElementSibling(node)) continue;
2466
'only-child': function(nodes, value, root) {
2467
var h = Selector.handlers;
2468
for (var i = 0, results = [], node; node = nodes[i]; i++)
2469
if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
2473
'nth-child': function(nodes, formula, root) {
2474
return Selector.pseudos.nth(nodes, formula, root);
2476
'nth-last-child': function(nodes, formula, root) {
2477
return Selector.pseudos.nth(nodes, formula, root, true);
2479
'nth-of-type': function(nodes, formula, root) {
2480
return Selector.pseudos.nth(nodes, formula, root, false, true);
2482
'nth-last-of-type': function(nodes, formula, root) {
2483
return Selector.pseudos.nth(nodes, formula, root, true, true);
2485
'first-of-type': function(nodes, formula, root) {
2486
return Selector.pseudos.nth(nodes, "1", root, false, true);
2488
'last-of-type': function(nodes, formula, root) {
2489
return Selector.pseudos.nth(nodes, "1", root, true, true);
2491
'only-of-type': function(nodes, formula, root) {
2492
var p = Selector.pseudos;
2493
return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
2496
// handles the an+b logic
2497
getIndices: function(a, b, total) {
2498
if (a == 0) return b > 0 ? [b] : [];
2499
return $R(1, total).inject([], function(memo, i) {
2500
if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
2505
// handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
2506
nth: function(nodes, formula, root, reverse, ofType) {
2507
if (nodes.length == 0) return [];
2508
if (formula == 'even') formula = '2n+0';
2509
if (formula == 'odd') formula = '2n+1';
2510
var h = Selector.handlers, results = [], indexed = [], m;
2512
for (var i = 0, node; node = nodes[i]; i++) {
2513
if (!node.parentNode._counted) {
2514
h.index(node.parentNode, reverse, ofType);
2515
indexed.push(node.parentNode);
2518
if (formula.match(/^\d+$/)) { // just a number
2519
formula = Number(formula);
2520
for (var i = 0, node; node = nodes[i]; i++)
2521
if (node.nodeIndex == formula) results.push(node);
2522
} else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
2523
if (m[1] == "-") m[1] = -1;
2524
var a = m[1] ? Number(m[1]) : 1;
2525
var b = m[2] ? Number(m[2]) : 0;
2526
var indices = Selector.pseudos.getIndices(a, b, nodes.length);
2527
for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
2528
for (var j = 0; j < l; j++)
2529
if (node.nodeIndex == indices[j]) results.push(node);
2537
'empty': function(nodes, value, root) {
2538
for (var i = 0, results = [], node; node = nodes[i]; i++) {
2539
// IE treats comments as element nodes
2540
if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
2546
'not': function(nodes, selector, root) {
2547
var h = Selector.handlers, selectorType, m;
2548
var exclusions = new Selector(selector).findElements(root);
2550
for (var i = 0, results = [], node; node = nodes[i]; i++)
2551
if (!node._counted) results.push(node);
2552
h.unmark(exclusions);
2556
'enabled': function(nodes, value, root) {
2557
for (var i = 0, results = [], node; node = nodes[i]; i++)
2558
if (!node.disabled) results.push(node);
2562
'disabled': function(nodes, value, root) {
2563
for (var i = 0, results = [], node; node = nodes[i]; i++)
2564
if (node.disabled) results.push(node);
2568
'checked': function(nodes, value, root) {
2569
for (var i = 0, results = [], node; node = nodes[i]; i++)
2570
if (node.checked) results.push(node);
2576
'=': function(nv, v) { return nv == v; },
2577
'!=': function(nv, v) { return nv != v; },
2578
'^=': function(nv, v) { return nv.startsWith(v); },
2579
'$=': function(nv, v) { return nv.endsWith(v); },
2580
'*=': function(nv, v) { return nv.include(v); },
2581
'~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
2582
'|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
2585
matchElements: function(elements, expression) {
2586
var matches = new Selector(expression).findElements(), h = Selector.handlers;
2588
for (var i = 0, results = [], element; element = elements[i]; i++)
2589
if (element._counted) results.push(element);
2594
findElement: function(elements, expression, index) {
2595
if (typeof expression == 'number') {
2596
index = expression; expression = false;
2598
return Selector.matchElements(elements, expression || '*')[index || 0];
2601
findChildElements: function(element, expressions) {
2602
var exprs = expressions.join(','), expressions = [];
2603
exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
2604
expressions.push(m[1].strip());
2606
var results = [], h = Selector.handlers;
2607
for (var i = 0, l = expressions.length, selector; i < l; i++) {
2608
selector = new Selector(expressions[i].strip());
2609
h.concat(results, selector.findElements(element));
2611
return (l > 1) ? h.unique(results) : results;
2616
return Selector.findChildElements(document, $A(arguments));
2619
reset: function(form) {
2624
serializeElements: function(elements, getHash) {
2625
var data = elements.inject({}, function(result, element) {
2626
if (!element.disabled && element.name) {
2627
var key = element.name, value = $(element).getValue();
2628
if (value != null) {
2629
if (key in result) {
2630
if (result[key].constructor != Array) result[key] = [result[key]];
2631
result[key].push(value);
2633
else result[key] = value;
2639
return getHash ? data : Hash.toQueryString(data);
2644
serialize: function(form, getHash) {
2645
return Form.serializeElements(Form.getElements(form), getHash);
2648
getElements: function(form) {
2649
return $A($(form).getElementsByTagName('*')).inject([],
2650
function(elements, child) {
2651
if (Form.Element.Serializers[child.tagName.toLowerCase()])
2652
elements.push(Element.extend(child));
2658
getInputs: function(form, typeName, name) {
2660
var inputs = form.getElementsByTagName('input');
2662
if (!typeName && !name) return $A(inputs).map(Element.extend);
2664
for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
2665
var input = inputs[i];
2666
if ((typeName && input.type != typeName) || (name && input.name != name))
2668
matchingInputs.push(Element.extend(input));
2671
return matchingInputs;
2674
disable: function(form) {
2676
Form.getElements(form).invoke('disable');
2680
enable: function(form) {
2682
Form.getElements(form).invoke('enable');
2686
findFirstElement: function(form) {
2687
return $(form).getElements().find(function(element) {
2688
return element.type != 'hidden' && !element.disabled &&
2689
['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
2693
focusFirstElement: function(form) {
2695
form.findFirstElement().activate();
2699
request: function(form, options) {
2700
form = $(form), options = Object.clone(options || {});
2702
var params = options.parameters;
2703
options.parameters = form.serialize(true);
2706
if (typeof params == 'string') params = params.toQueryParams();
2707
Object.extend(options.parameters, params);
2710
if (form.hasAttribute('method') && !options.method)
2711
options.method = form.method;
2713
return new Ajax.Request(form.readAttribute('action'), options);
2717
/*--------------------------------------------------------------------------*/
2720
focus: function(element) {
2725
select: function(element) {
2726
$(element).select();
2731
Form.Element.Methods = {
2732
serialize: function(element) {
2733
element = $(element);
2734
if (!element.disabled && element.name) {
2735
var value = element.getValue();
2736
if (value != undefined) {
2738
pair[element.name] = value;
2739
return Hash.toQueryString(pair);
2745
getValue: function(element) {
2746
element = $(element);
2747
var method = element.tagName.toLowerCase();
2748
return Form.Element.Serializers[method](element);
2751
clear: function(element) {
2752
$(element).value = '';
2756
present: function(element) {
2757
return $(element).value != '';
2760
activate: function(element) {
2761
element = $(element);
2764
if (element.select && (element.tagName.toLowerCase() != 'input' ||
2765
!['button', 'reset', 'submit'].include(element.type)))
2771
disable: function(element) {
2772
element = $(element);
2774
element.disabled = true;
2778
enable: function(element) {
2779
element = $(element);
2780
element.disabled = false;
2785
/*--------------------------------------------------------------------------*/
2787
var Field = Form.Element;
2788
var $F = Form.Element.Methods.getValue;
2790
/*--------------------------------------------------------------------------*/
2792
Form.Element.Serializers = {
2793
input: function(element) {
2794
switch (element.type.toLowerCase()) {
2797
return Form.Element.Serializers.inputSelector(element);
2799
return Form.Element.Serializers.textarea(element);
2803
inputSelector: function(element) {
2804
return element.checked ? element.value : null;
2807
textarea: function(element) {
2808
return element.value;
2811
select: function(element) {
2812
return this[element.type == 'select-one' ?
2813
'selectOne' : 'selectMany'](element);
2816
selectOne: function(element) {
2817
var index = element.selectedIndex;
2818
return index >= 0 ? this.optionValue(element.options[index]) : null;
2821
selectMany: function(element) {
2822
var values, length = element.length;
2823
if (!length) return null;
2825
for (var i = 0, values = []; i < length; i++) {
2826
var opt = element.options[i];
2827
if (opt.selected) values.push(this.optionValue(opt));
2832
optionValue: function(opt) {
2833
// extend element because hasAttribute may not be native
2834
return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
2838
/*--------------------------------------------------------------------------*/
2840
Abstract.TimedObserver = function() {}
2841
Abstract.TimedObserver.prototype = {
2842
initialize: function(element, frequency, callback) {
2843
this.frequency = frequency;
2844
this.element = $(element);
2845
this.callback = callback;
2847
this.lastValue = this.getValue();
2848
this.registerCallback();
2851
registerCallback: function() {
2852
setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
2855
onTimerEvent: function() {
2856
var value = this.getValue();
2857
var changed = ('string' == typeof this.lastValue && 'string' == typeof value
2858
? this.lastValue != value : String(this.lastValue) != String(value));
2860
this.callback(this.element, value);
2861
this.lastValue = value;
2866
Form.Element.Observer = Class.create();
2867
Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
2868
getValue: function() {
2869
return Form.Element.getValue(this.element);
2873
Form.Observer = Class.create();
2874
Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
2875
getValue: function() {
2876
return Form.serialize(this.element);
2880
/*--------------------------------------------------------------------------*/
2882
Abstract.EventObserver = function() {}
2883
Abstract.EventObserver.prototype = {
2884
initialize: function(element, callback) {
2885
this.element = $(element);
2886
this.callback = callback;
2888
this.lastValue = this.getValue();
2889
if (this.element.tagName.toLowerCase() == 'form')
2890
this.registerFormCallbacks();
2892
this.registerCallback(this.element);
2895
onElementEvent: function() {
2896
var value = this.getValue();
2897
if (this.lastValue != value) {
2898
this.callback(this.element, value);
2899
this.lastValue = value;
2903
registerFormCallbacks: function() {
2904
Form.getElements(this.element).each(this.registerCallback.bind(this));
2907
registerCallback: function(element) {
2909
switch (element.type.toLowerCase()) {
2912
Event.observe(element, 'click', this.onElementEvent.bind(this));
2915
Event.observe(element, 'change', this.onElementEvent.bind(this));
2922
Form.Element.EventObserver = Class.create();
2923
Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
2924
getValue: function() {
2925
return Form.Element.getValue(this.element);
2929
Form.EventObserver = Class.create();
2930
Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
2931
getValue: function() {
2932
return Form.serialize(this.element);
2935
if (!window.Event) {
2936
var Event = new Object();
2939
Object.extend(Event, {
2954
element: function(event) {
2955
return $(event.target || event.srcElement);
2958
isLeftClick: function(event) {
2959
return (((event.which) && (event.which == 1)) ||
2960
((event.button) && (event.button == 1)));
2963
pointerX: function(event) {
2964
return event.pageX || (event.clientX +
2965
(document.documentElement.scrollLeft || document.body.scrollLeft));
2968
pointerY: function(event) {
2969
return event.pageY || (event.clientY +
2970
(document.documentElement.scrollTop || document.body.scrollTop));
2973
stop: function(event) {
2974
if (event.preventDefault) {
2975
event.preventDefault();
2976
event.stopPropagation();
2978
event.returnValue = false;
2979
event.cancelBubble = true;
2983
// find the first node with the given tagName, starting from the
2984
// node the event was triggered on; traverses the DOM upwards
2985
findElement: function(event, tagName) {
2986
var element = Event.element(event);
2987
while (element.parentNode && (!element.tagName ||
2988
(element.tagName.toUpperCase() != tagName.toUpperCase())))
2989
element = element.parentNode;
2995
_observeAndCache: function(element, name, observer, useCapture) {
2996
if (!this.observers) this.observers = [];
2997
if (element.addEventListener) {
2998
this.observers.push([element, name, observer, useCapture]);
2999
element.addEventListener(name, observer, useCapture);
3000
} else if (element.attachEvent) {
3001
this.observers.push([element, name, observer, useCapture]);
3002
element.attachEvent('on' + name, observer);
3006
unloadCache: function() {
3007
if (!Event.observers) return;
3008
for (var i = 0, length = Event.observers.length; i < length; i++) {
3009
Event.stopObserving.apply(this, Event.observers[i]);
3010
Event.observers[i][0] = null;
3012
Event.observers = false;
3015
observe: function(element, name, observer, useCapture) {
3016
element = $(element);
3017
useCapture = useCapture || false;
3019
if (name == 'keypress' &&
3020
(Prototype.Browser.WebKit || element.attachEvent))
3023
Event._observeAndCache(element, name, observer, useCapture);
3026
stopObserving: function(element, name, observer, useCapture) {
3027
element = $(element);
3028
useCapture = useCapture || false;
3030
if (name == 'keypress' &&
3031
(Prototype.Browser.WebKit || element.attachEvent))
3034
if (element.removeEventListener) {
3035
element.removeEventListener(name, observer, useCapture);
3036
} else if (element.detachEvent) {
3038
element.detachEvent('on' + name, observer);
3044
/* prevent memory leaks in IE */
3045
if (Prototype.Browser.IE)
3046
Event.observe(window, 'unload', Event.unloadCache, false);
3048
// set to true if needed, warning: firefox performance problems
3049
// NOT neeeded for page scrolling, only if draggable contained in
3050
// scrollable elements
3051
includeScrollOffsets: false,
3053
// must be called before calling withinIncludingScrolloffset, every time the
3055
prepare: function() {
3056
this.deltaX = window.pageXOffset
3057
|| document.documentElement.scrollLeft
3058
|| document.body.scrollLeft
3060
this.deltaY = window.pageYOffset
3061
|| document.documentElement.scrollTop
3062
|| document.body.scrollTop
3066
realOffset: function(element) {
3067
var valueT = 0, valueL = 0;
3069
valueT += element.scrollTop || 0;
3070
valueL += element.scrollLeft || 0;
3071
element = element.parentNode;
3073
return [valueL, valueT];
3076
cumulativeOffset: function(element) {
3077
var valueT = 0, valueL = 0;
3079
valueT += element.offsetTop || 0;
3080
valueL += element.offsetLeft || 0;
3081
element = element.offsetParent;
3083
return [valueL, valueT];
3086
positionedOffset: function(element) {
3087
var valueT = 0, valueL = 0;
3089
valueT += element.offsetTop || 0;
3090
valueL += element.offsetLeft || 0;
3091
element = element.offsetParent;
3093
if(element.tagName=='BODY') break;
3094
var p = Element.getStyle(element, 'position');
3095
if (p == 'relative' || p == 'absolute') break;
3098
return [valueL, valueT];
3101
offsetParent: function(element) {
3102
if (element.offsetParent) return element.offsetParent;
3103
if (element == document.body) return element;
3105
while ((element = element.parentNode) && element != document.body)
3106
if (Element.getStyle(element, 'position') != 'static')
3109
return document.body;
3112
// caches x/y coordinate pair to use with overlap
3113
within: function(element, x, y) {
3114
if (this.includeScrollOffsets)
3115
return this.withinIncludingScrolloffsets(element, x, y);
3118
this.offset = this.cumulativeOffset(element);
3120
return (y >= this.offset[1] &&
3121
y < this.offset[1] + element.offsetHeight &&
3122
x >= this.offset[0] &&
3123
x < this.offset[0] + element.offsetWidth);
3126
withinIncludingScrolloffsets: function(element, x, y) {
3127
var offsetcache = this.realOffset(element);
3129
this.xcomp = x + offsetcache[0] - this.deltaX;
3130
this.ycomp = y + offsetcache[1] - this.deltaY;
3131
this.offset = this.cumulativeOffset(element);
3133
return (this.ycomp >= this.offset[1] &&
3134
this.ycomp < this.offset[1] + element.offsetHeight &&
3135
this.xcomp >= this.offset[0] &&
3136
this.xcomp < this.offset[0] + element.offsetWidth);
3139
// within must be called directly before
3140
overlap: function(mode, element) {
3141
if (!mode) return 0;
3142
if (mode == 'vertical')
3143
return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
3144
element.offsetHeight;
3145
if (mode == 'horizontal')
3146
return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
3147
element.offsetWidth;
3150
page: function(forElement) {
3151
var valueT = 0, valueL = 0;
3153
var element = forElement;
3155
valueT += element.offsetTop || 0;
3156
valueL += element.offsetLeft || 0;
3159
if (element.offsetParent == document.body)
3160
if (Element.getStyle(element,'position')=='absolute') break;
3162
} while (element = element.offsetParent);
3164
element = forElement;
3166
if (!window.opera || element.tagName=='BODY') {
3167
valueT -= element.scrollTop || 0;
3168
valueL -= element.scrollLeft || 0;
3170
} while (element = element.parentNode);
3172
return [valueL, valueT];
3175
clone: function(source, target) {
3176
var options = Object.extend({
3183
}, arguments[2] || {})
3185
// find page position of source
3187
var p = Position.page(source);
3189
// find coordinate system to use
3193
// delta [0,0] will do fine with position: fixed elements,
3194
// position:absolute needs offsetParent deltas
3195
if (Element.getStyle(target,'position') == 'absolute') {
3196
parent = Position.offsetParent(target);
3197
delta = Position.page(parent);
3200
// correct by body offsets (fixes Safari)
3201
if (parent == document.body) {
3202
delta[0] -= document.body.offsetLeft;
3203
delta[1] -= document.body.offsetTop;
3207
if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
3208
if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
3209
if(options.setWidth) target.style.width = source.offsetWidth + 'px';
3210
if(options.setHeight) target.style.height = source.offsetHeight + 'px';
3213
absolutize: function(element) {
3214
element = $(element);
3215
if (element.style.position == 'absolute') return;
3218
var offsets = Position.positionedOffset(element);
3219
var top = offsets[1];
3220
var left = offsets[0];
3221
var width = element.clientWidth;
3222
var height = element.clientHeight;
3224
element._originalLeft = left - parseFloat(element.style.left || 0);
3225
element._originalTop = top - parseFloat(element.style.top || 0);
3226
element._originalWidth = element.style.width;
3227
element._originalHeight = element.style.height;
3229
element.style.position = 'absolute';
3230
element.style.top = top + 'px';
3231
element.style.left = left + 'px';
3232
element.style.width = width + 'px';
3233
element.style.height = height + 'px';
3236
relativize: function(element) {
3237
element = $(element);
3238
if (element.style.position == 'relative') return;
3241
element.style.position = 'relative';
3242
var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
3243
var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
3245
element.style.top = top + 'px';
3246
element.style.left = left + 'px';
3247
element.style.height = element._originalHeight;
3248
element.style.width = element._originalWidth;
3252
// Safari returns margins on body which is incorrect if the child is absolutely
3253
// positioned. For performance reasons, redefine Position.cumulativeOffset for
3254
// KHTML/WebKit only.
3255
if (Prototype.Browser.WebKit) {
3256
Position.cumulativeOffset = function(element) {
3257
var valueT = 0, valueL = 0;
3259
valueT += element.offsetTop || 0;
3260
valueL += element.offsetLeft || 0;
3261
if (element.offsetParent == document.body)
3262
if (Element.getStyle(element, 'position') == 'absolute') break;
3264
element = element.offsetParent;
3267
return [valueL, valueT];
3271
Element.addMethods();
b'\\ No newline at end of file'