]> code.citadel.org Git - citadel.git/blob - webcit/static/prototype.js
* New AJAX-based wholist refresh
[citadel.git] / webcit / static / prototype.js
1 /*  Prototype: an object-oriented Javascript library, version 1.2.1
2  *  (c) 2005 Sam Stephenson <sam@conio.net>
3  *
4  *  THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff
5  *  against the source tree, available from the Prototype darcs repository. 
6  *
7  *  Prototype is freely distributable under the terms of an MIT-style license.
8  *
9  *  For details, see the Prototype web site: http://prototype.conio.net/
10  *
11 /*--------------------------------------------------------------------------*/
12
13 var Prototype = {
14   Version: '1.2.1'
15 }
16
17 var Class = {
18   create: function() {
19     return function() { 
20       this.initialize.apply(this, arguments);
21     }
22   }
23 }
24
25 var Abstract = new Object();
26
27 Object.prototype.extend = function(object) {
28   for (property in object) {
29     this[property] = object[property];
30   }
31   return this;
32 }
33
34 Function.prototype.bind = function(object) {
35   var method = this;
36   return function() {
37     method.apply(object, arguments);
38   }
39 }
40
41 Function.prototype.bindAsEventListener = function(object) {
42   var method = this;
43   return function(event) {
44     method.call(object, event || window.event);
45   }
46 }
47
48 Number.prototype.toColorPart = function() {
49   var digits = this.toString(16);
50   if (this < 16) return '0' + digits;
51   return digits;
52 }
53
54 var Try = {
55   these: function() {
56     var returnValue;
57     
58     for (var i = 0; i < arguments.length; i++) {
59       var lambda = arguments[i];
60       try {
61         returnValue = lambda();
62         break;
63       } catch (e) {}
64     }
65     
66     return returnValue;
67   }
68 }
69
70 /*--------------------------------------------------------------------------*/
71
72 var PeriodicalExecuter = Class.create();
73 PeriodicalExecuter.prototype = {
74   initialize: function(callback, frequency) {
75     this.callback = callback;
76     this.frequency = frequency;
77     this.currentlyExecuting = false;
78     
79     this.registerCallback();
80   },
81   
82   registerCallback: function() {
83     setTimeout(this.onTimerEvent.bind(this), this.frequency * 1000);
84   },
85   
86   onTimerEvent: function() {
87     if (!this.currentlyExecuting) {
88       try { 
89         this.currentlyExecuting = true;
90         this.callback(); 
91       } finally { 
92         this.currentlyExecuting = false;
93       }
94     }
95     
96     this.registerCallback();
97   }
98 }
99
100 /*--------------------------------------------------------------------------*/
101
102 function $() {
103   var elements = new Array();
104   
105   for (var i = 0; i < arguments.length; i++) {
106     var element = arguments[i];
107     if (typeof element == 'string')
108       element = document.getElementById(element);
109
110     if (arguments.length == 1) 
111       return element;
112       
113     elements.push(element);
114   }
115   
116   return elements;
117 }
118
119 /*--------------------------------------------------------------------------*/
120
121 if (!Array.prototype.push) {
122   Array.prototype.push = function() {
123                 var startLength = this.length;
124                 for (var i = 0; i < arguments.length; i++)
125       this[startLength + i] = arguments[i];
126           return this.length;
127   }
128 }
129
130 if (!Function.prototype.apply) {
131   // Based on code from http://www.youngpup.net/
132   Function.prototype.apply = function(object, parameters) {
133     var parameterStrings = new Array();
134     if (!object)     object = window;
135     if (!parameters) parameters = new Array();
136     
137     for (var i = 0; i < parameters.length; i++)
138       parameterStrings[i] = 'x[' + i + ']';
139     
140     object.__apply__ = this;
141     var result = eval('obj.__apply__(' + 
142       parameterStrings[i].join(', ') + ')');
143     object.__apply__ = null;
144     
145     return result;
146   }
147 }
148
149 /*--------------------------------------------------------------------------*/
150
151 var Ajax = {
152   getTransport: function() {
153     return Try.these(
154       function() {return new ActiveXObject('Msxml2.XMLHTTP')},
155       function() {return new ActiveXObject('Microsoft.XMLHTTP')},
156       function() {return new XMLHttpRequest()}
157     ) || false;
158   },
159   
160   emptyFunction: function() {}
161 }
162
163 Ajax.Base = function() {};
164 Ajax.Base.prototype = {
165   setOptions: function(options) {
166     this.options = {
167       method:       'post',
168       asynchronous: true,
169       parameters:   ''
170     }.extend(options || {});
171   }
172 }
173
174 Ajax.Request = Class.create();
175 Ajax.Request.Events = 
176   ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
177
178 Ajax.Request.prototype = (new Ajax.Base()).extend({
179   initialize: function(url, options) {
180     this.transport = Ajax.getTransport();
181     this.setOptions(options);
182   
183     try {
184       if (this.options.method == 'get')
185         url += '?' + this.options.parameters + '&_=';
186     
187       this.transport.open(this.options.method, url,
188         this.options.asynchronous);
189       
190       if (this.options.asynchronous) {
191         this.transport.onreadystatechange = this.onStateChange.bind(this);
192         setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
193       }
194               
195       this.transport.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
196       this.transport.setRequestHeader('X-Prototype-Version',
197         Prototype.Version);
198
199       if (this.options.method == 'post') {
200         this.transport.setRequestHeader('Connection', 'close');
201         this.transport.setRequestHeader('Content-type',
202           'application/x-www-form-urlencoded');
203       }
204
205       if (this.options.requestHeaders) {
206          for (var i=0; i< (this.options.requestHeaders.length-1);i+=2)
207             this.transport.setRequestHeader(this.options.requestHeaders[i],
208                                             this.options.requestHeaders[i+1]);
209       }
210
211       var sendData = this.options.postBody   ? this.options.postBody
212                    : this.options.parameters ? this.options.parameters + '&_'
213                    : null;
214
215       this.transport.send(this.options.method == 'post' ? sendData : null );
216                       
217     } catch (e) {
218     }    
219   },
220       
221   onStateChange: function() {
222     var readyState = this.transport.readyState;
223     if (readyState != 1)
224       this.respondToReadyState(this.transport.readyState);
225   },
226   
227   respondToReadyState: function(readyState) {
228     var event = Ajax.Request.Events[readyState];
229     (this.options['on' + event] || Ajax.emptyFunction)(this.transport);
230   }
231 });
232
233 Ajax.Updater = Class.create();
234 Ajax.Updater.prototype = (new Ajax.Base()).extend({
235   initialize: function(container, url, options) {
236     this.container = $(container);
237     this.setOptions(options);
238   
239     if (this.options.asynchronous) {
240       this.onComplete = this.options.onComplete;
241       this.options.onComplete = this.updateContent.bind(this);
242     }
243
244     this.request = new Ajax.Request(url, this.options);
245     
246     if (!this.options.asynchronous)
247       this.updateContent();
248   },
249   
250   updateContent: function() {
251     if (this.request.transport.status == 200) {
252       if (this.options.insertion) {
253         new this.options.insertion(this.container,
254         this.request.transport.responseText);
255       } else {
256         this.container.innerHTML = this.request.transport.responseText;
257       }
258     }  
259
260     if (this.onComplete) {
261       setTimeout((function() {this.onComplete(
262         this.request.transport)}).bind(this), 10);
263     }
264   }
265 });
266
267 /*--------------------------------------------------------------------------*/
268
269 var Field = {
270   clear: function() {
271     for (var i = 0; i < arguments.length; i++)
272       $(arguments[i]).value = '';
273   },
274
275   focus: function(element) {
276     $(element).focus();
277   },
278   
279   present: function() {
280     for (var i = 0; i < arguments.length; i++)
281       if ($(arguments[i]).value == '') return false;
282     return true;
283   },
284   
285   select: function(element) {
286     $(element).select();
287   },
288    
289   activate: function(element) {
290     $(element).focus();
291     $(element).select();
292   }
293 }
294
295 /*--------------------------------------------------------------------------*/
296
297 var Form = {
298   serialize: function(form) {
299     var elements = Form.getElements($(form));
300     var queryComponents = new Array();
301     
302     for (var i = 0; i < elements.length; i++) {
303       var queryComponent = Form.Element.serialize(elements[i]);
304       if (queryComponent)
305         queryComponents.push(queryComponent);
306     }
307     
308     return queryComponents.join('&');
309   },
310   
311   getElements: function(form) {
312     form = $(form);
313     var elements = new Array();
314
315     for (tagName in Form.Element.Serializers) {
316       var tagElements = form.getElementsByTagName(tagName);
317       for (var j = 0; j < tagElements.length; j++)
318         elements.push(tagElements[j]);
319     }
320     return elements;
321   },
322   
323   disable: function(form) {
324     var elements = Form.getElements(form);
325     for (var i = 0; i < elements.length; i++) {
326       var element = elements[i];
327       element.blur();
328       element.disable = 'true';
329     }
330   },
331
332   focusFirstElement: function(form) {
333     form = $(form);
334     var elements = Form.getElements(form);
335     for (var i = 0; i < elements.length; i++) {
336       var element = elements[i];
337       if (element.type != 'hidden' && !element.disabled) {
338         Field.activate(element);
339         break;
340       }
341     }
342   },
343
344   reset: function(form) {
345     $(form).reset();
346   }
347 }
348
349 Form.Element = {
350   serialize: function(element) {
351     element = $(element);
352     var method = element.tagName.toLowerCase();
353     var parameter = Form.Element.Serializers[method](element);
354     
355     if (parameter)
356       return encodeURIComponent(parameter[0]) + '=' + 
357         encodeURIComponent(parameter[1]);                   
358   },
359   
360   getValue: function(element) {
361     element = $(element);
362     var method = element.tagName.toLowerCase();
363     var parameter = Form.Element.Serializers[method](element);
364     
365     if (parameter) 
366       return parameter[1];
367   }
368 }
369
370 Form.Element.Serializers = {
371   input: function(element) {
372     switch (element.type.toLowerCase()) {
373       case 'hidden':
374       case 'password':
375       case 'text':
376         return Form.Element.Serializers.textarea(element);
377       case 'checkbox':  
378       case 'radio':
379         return Form.Element.Serializers.inputSelector(element);
380     }
381     return false;
382   },
383
384   inputSelector: function(element) {
385     if (element.checked)
386       return [element.name, element.value];
387   },
388
389   textarea: function(element) {
390     return [element.name, element.value];
391   },
392
393   select: function(element) {
394     var index = element.selectedIndex;
395     var value = element.options[index].value || element.options[index].text;
396     return [element.name, (index >= 0) ? value : ''];
397   }
398 }
399
400 /*--------------------------------------------------------------------------*/
401
402 var $F = Form.Element.getValue;
403
404 /*--------------------------------------------------------------------------*/
405
406 Abstract.TimedObserver = function() {}
407 Abstract.TimedObserver.prototype = {
408   initialize: function(element, frequency, callback) {
409     this.frequency = frequency;
410     this.element   = $(element);
411     this.callback  = callback;
412     
413     this.lastValue = this.getValue();
414     this.registerCallback();
415   },
416   
417   registerCallback: function() {
418     setTimeout(this.onTimerEvent.bind(this), this.frequency * 1000);
419   },
420   
421   onTimerEvent: function() {
422     var value = this.getValue();
423     if (this.lastValue != value) {
424       this.callback(this.element, value);
425       this.lastValue = value;
426     }
427     
428     this.registerCallback();
429   }
430 }
431
432 Form.Element.Observer = Class.create();
433 Form.Element.Observer.prototype = (new Abstract.TimedObserver()).extend({
434   getValue: function() {
435     return Form.Element.getValue(this.element);
436   }
437 });
438
439 Form.Observer = Class.create();
440 Form.Observer.prototype = (new Abstract.TimedObserver()).extend({
441   getValue: function() {
442     return Form.serialize(this.element);
443   }
444 });
445
446
447 /*--------------------------------------------------------------------------*/
448
449 document.getElementsByClassName = function(className) {
450   var children = document.getElementsByTagName('*') || document.all;
451   var elements = new Array();
452   
453   for (var i = 0; i < children.length; i++) {
454     var child = children[i];
455     var classNames = child.className.split(' ');
456     for (var j = 0; j < classNames.length; j++) {
457       if (classNames[j] == className) {
458         elements.push(child);
459         break;
460       }
461     }
462   }
463   
464   return elements;
465 }
466
467 /*--------------------------------------------------------------------------*/
468
469 var Element = {
470   toggle: function() {
471     for (var i = 0; i < arguments.length; i++) {
472       var element = $(arguments[i]);
473       element.style.display = 
474         (element.style.display == 'none' ? '' : 'none');
475     }
476   },
477
478   hide: function() {
479     for (var i = 0; i < arguments.length; i++) {
480       var element = $(arguments[i]);
481       element.style.display = 'none';
482     }
483   },
484
485   show: function() {
486     for (var i = 0; i < arguments.length; i++) {
487       var element = $(arguments[i]);
488       element.style.display = '';
489     }
490   },
491
492   remove: function(element) {
493     element = $(element);
494     element.parentNode.removeChild(element);
495   },
496    
497   getHeight: function(element) {
498     element = $(element);
499     return element.offsetHeight; 
500   }
501 }
502
503 var Toggle = new Object();
504 Toggle.display = Element.toggle;
505
506 /*--------------------------------------------------------------------------*/
507
508 Abstract.Insertion = function(adjacency) {
509   this.adjacency = adjacency;
510 }
511
512 Abstract.Insertion.prototype = {
513   initialize: function(element, content) {
514     this.element = $(element);
515     this.content = content;
516     
517     if (this.adjacency && this.element.insertAdjacentHTML) {
518       this.element.insertAdjacentHTML(this.adjacency, this.content);
519     } else {
520       this.range = this.element.ownerDocument.createRange();
521       if (this.initializeRange) this.initializeRange();
522       this.fragment = this.range.createContextualFragment(this.content);
523       this.insertContent();
524     }
525   }
526 }
527
528 var Insertion = new Object();
529
530 Insertion.Before = Class.create();
531 Insertion.Before.prototype = (new Abstract.Insertion('beforeBegin')).extend({
532   initializeRange: function() {
533     this.range.setStartBefore(this.element);
534   },
535   
536   insertContent: function() {
537     this.element.parentNode.insertBefore(this.fragment, this.element);
538   }
539 });
540
541 Insertion.Top = Class.create();
542 Insertion.Top.prototype = (new Abstract.Insertion('afterBegin')).extend({
543   initializeRange: function() {
544     this.range.selectNodeContents(this.element);
545     this.range.collapse(true);
546   },
547   
548   insertContent: function() {  
549     this.element.insertBefore(this.fragment, this.element.firstChild);
550   }
551 });
552
553 Insertion.Bottom = Class.create();
554 Insertion.Bottom.prototype = (new Abstract.Insertion('beforeEnd')).extend({
555   initializeRange: function() {
556     this.range.selectNodeContents(this.element);
557     this.range.collapse(this.element);
558   },
559   
560   insertContent: function() {
561     this.element.appendChild(this.fragment);
562   }
563 });
564
565 Insertion.After = Class.create();
566 Insertion.After.prototype = (new Abstract.Insertion('afterEnd')).extend({
567   initializeRange: function() {
568     this.range.setStartAfter(this.element);
569   },
570   
571   insertContent: function() {
572     this.element.parentNode.insertBefore(this.fragment, 
573       this.element.nextSibling);
574   }
575 });
576
577 /*--------------------------------------------------------------------------*/
578
579 var Effect = new Object();
580
581 Effect.Highlight = Class.create();
582 Effect.Highlight.prototype = {
583   initialize: function(element) {
584     this.element = $(element);
585     this.start  = 153;
586     this.finish = 255;
587     this.current = this.start;
588     this.fade();
589   },
590   
591   fade: function() {
592     if (this.isFinished()) return;
593     if (this.timer) clearTimeout(this.timer);
594     this.highlight(this.element, this.current);
595     this.current += 17;
596     this.timer = setTimeout(this.fade.bind(this), 250);
597   },
598   
599   isFinished: function() {
600     return this.current > this.finish;
601   },
602   
603   highlight: function(element, current) {
604     element.style.backgroundColor = "#ffff" + current.toColorPart();
605   }
606 }
607
608
609 Effect.Fade = Class.create();
610 Effect.Fade.prototype = {
611   initialize: function(element) {
612     this.element = $(element);
613     this.start  = 100;
614     this.finish = 0;
615     this.current = this.start;
616     this.fade();
617   },
618   
619   fade: function() {
620     if (this.isFinished()) { this.element.style.display = 'none'; return; }
621     if (this.timer) clearTimeout(this.timer);
622     this.setOpacity(this.element, this.current);
623     this.current -= 10;
624     this.timer = setTimeout(this.fade.bind(this), 50);
625   },
626   
627   isFinished: function() {
628     return this.current <= this.finish;
629   },
630   
631   setOpacity: function(element, opacity) {
632     opacity = (opacity == 100) ? 99.999 : opacity;
633     element.style.filter = "alpha(opacity:"+opacity+")";
634     element.style.opacity = opacity/100 /*//*/;
635   }
636 }
637
638 Effect.Scale = Class.create();
639 Effect.Scale.prototype = {
640   initialize: function(element, percent) {
641     this.element = $(element);
642     this.startScale    = 1.0;
643     this.startHeight   = this.element.offsetHeight;
644     this.startWidth    = this.element.offsetWidth;
645     this.currentHeight = this.startHeight;
646     this.currentWidth  = this.startWidth;
647     this.finishScale   = (percent/100) /*//*/;
648     if (this.element.style.fontSize=="") this.sizeEm = 1.0;
649     if (this.element.style.fontSize.indexOf("em")>0)
650        this.sizeEm      = parseFloat(this.element.style.fontSize);
651     if(this.element.effect_scale) {
652       clearTimeout(this.element.effect_scale.timer);
653       this.startScale  = this.element.effect_scale.currentScale;
654       this.startHeight = this.element.effect_scale.startHeight;
655       this.startWidth  = this.element.effect_scale.startWidth;
656       if(this.element.effect_scale.sizeEm) 
657         this.sizeEm    = this.element.effect_scale.sizeEm;      
658     }
659     this.element.effect_scale = this;
660     this.currentScale  = this.startScale;
661     this.factor        = this.finishScale - this.startScale;
662     this.options       = arguments[2] || {}; 
663     this.scale();
664   },
665   
666   scale: function() {
667     if (this.isFinished()) { 
668       this.setDimensions(this.element, this.startWidth*this.finishScale, this.startHeight*this.finishScale);
669       if(this.sizeEm) this.element.style.fontSize = this.sizeEm*this.finishScale + "em";
670       if(this.options.complete) this.options.complete(this);
671       return; 
672     }
673     if (this.timer) clearTimeout(this.timer);
674     if (this.options.step) this.options.step(this);
675     this.setDimensions(this.element, this.currentWidth, this.currentHeight);
676     if(this.sizeEm) this.element.style.fontSize = this.sizeEm*this.currentScale + "em";
677     this.currentScale += (this.factor/10) /*//*/;
678     this.currentWidth = this.startWidth * this.currentScale;
679     this.currentHeight = this.startHeight * this.currentScale;
680     this.timer = setTimeout(this.scale.bind(this), 50);
681   },
682   
683   isFinished: function() {
684     return (this.factor < 0) ? 
685       this.currentScale <= this.finishScale : this.currentScale >= this.finishScale;
686   },
687   
688   setDimensions: function(element, width, height) {
689     element.style.width = width + 'px';
690     element.style.height = height + 'px';
691   }
692 }
693
694 Effect.Squish = Class.create();
695 Effect.Squish.prototype = {
696   initialize: function(element) {
697     this.element = $(element);
698     new Effect.Scale(this.element, 1, { complete: this.hide.bind(this) } );
699   },
700   hide: function() {
701     this.element.style.display = 'none';
702   } 
703 }
704
705 Effect.Puff = Class.create();
706 Effect.Puff.prototype = {
707   initialize: function(element) {
708     this.element = $(element);
709     this.opacity = 100;
710     this.startTop  = this.element.top || this.element.offsetTop;
711     this.startLeft = this.element.left || this.element.offsetLeft;
712     new Effect.Scale(this.element, 200, { step: this.fade.bind(this), complete: this.hide.bind(this) } );
713   },
714   fade: function(effect) {
715     topd    = (((effect.currentScale)*effect.startHeight) - effect.startHeight)/2;
716     leftd   = (((effect.currentScale)*effect.startWidth) - effect.startWidth)/2;
717     this.element.style.position='absolute';
718     this.element.style.top = this.startTop-topd + "px";
719     this.element.style.left = this.startLeft-leftd + "px";
720     this.opacity -= 10;
721     this.setOpacity(this.element, this.opacity); 
722     if(navigator.appVersion.indexOf('AppleWebKit')>0) this.element.innerHTML += ''; //force redraw on safari
723   },
724   hide: function() {
725     this.element.style.display = 'none';
726   },
727   setOpacity: function(element, opacity) {
728     opacity = (opacity == 100) ? 99.999 : opacity;
729     element.style.filter = "alpha(opacity:"+opacity+")";
730     element.style.opacity = opacity/100 /*//*/;
731   }
732 }
733
734 Effect.Appear = Class.create();
735 Effect.Appear.prototype = {
736   initialize: function(element) {
737     this.element = $(element);
738     this.start  = 0;
739     this.finish = 100;
740     this.current = this.start;
741     this.fade();
742   },
743   
744   fade: function() {
745     if (this.isFinished()) return;
746     if (this.timer) clearTimeout(this.timer);
747     this.setOpacity(this.element, this.current);
748     this.current += 10;
749     this.timer = setTimeout(this.fade.bind(this), 50);
750   },
751   
752   isFinished: function() {
753     return this.current > this.finish;
754   },
755   
756   setOpacity: function(element, opacity) {
757     opacity = (opacity == 100) ? 99.999 : opacity;
758     element.style.filter = "alpha(opacity:"+opacity+")";
759     element.style.opacity = opacity/100 /*//*/;
760     element.style.display = '';
761   }
762 }
763
764 Effect.ContentZoom = Class.create();
765 Effect.ContentZoom.prototype = {
766   initialize: function(element, percent) {
767     this.element = $(element);
768     if (this.element.style.fontSize=="") this.sizeEm = 1.0;
769     if (this.element.style.fontSize.indexOf("em")>0)
770        this.sizeEm = parseFloat(this.element.style.fontSize);
771     if(this.element.effect_contentzoom) {
772       this.sizeEm = this.element.effect_contentzoom.sizeEm;
773     }
774     this.element.effect_contentzoom = this;
775     this.element.style.fontSize = this.sizeEm*(percent/100) + "em" /*//*/;
776     if(navigator.appVersion.indexOf('AppleWebKit')>0) { this.element.scrollTop -= 1; };
777   }
778 }