/[webpac2]/Webpacus/root/js/prototype.js
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /Webpacus/root/js/prototype.js

Parent Directory Parent Directory | Revision Log Revision Log


Revision 409 - (hide annotations)
Mon Feb 20 17:12:22 2006 UTC (18 years, 3 months ago) by dpavlin
File MIME type: application/javascript
File size: 47445 byte(s)
 r482@llin:  dpavlin | 2006-02-20 17:41:19 +0100
 update to prototype 1.4.0

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

  ViewVC Help
Powered by ViewVC 1.1.26