Description:
fixed javascript/css assets, fixed link_to_remote in problems page
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r322:c744bb196ba4 - - 30 files changed: 1508 inserted, 7506 deleted

@@ -0,0 +1,41
1 +
2 + var Announcement = {
3 +
4 + mostRecentId: 0,
5 +
6 + refreshUrl: '/main/announcements',
7 +
8 + setMostRecentId: function(id) {
9 + Announcement.mostRecentId = id;
10 + },
11 +
12 + updateRecentId: function(id) {
13 + if(Announcement.mostRecentId < id)
14 + Announcement.mostRecentId = id;
15 + },
16 +
17 + refreshAnnouncement: function() {
18 + var url = Announcement.refreshUrl;
19 + new Ajax.Request(url, {
20 + method: 'get',
21 + parameters: { recent: Announcement.mostRecentId },
22 + onSuccess: function(transport) {
23 + if((transport.status == 200) &&
24 + (transport.responseText.match(/\S/)!=null)) {
25 + var announcementBody = $("announcementbox-body");
26 + announcementBody.insert({ top: transport.responseText });
27 + var announcementBoxes = $$(".announcementbox");
28 + if(announcementBoxes.length!=0)
29 + announcementBoxes[0].show();
30 + Announcement.registerRefreshEventTimer();
31 + }
32 + }
33 + });
34 + },
35 +
36 + registerRefreshEventTimer: function() {
37 + setTimeout(function () {
38 + Announcement.refreshAnnouncement();
39 + }, 30000);
40 + }
41 + };
This diff has been collapsed as it changes many lines, (1128 lines changed) Show them Hide them
@@ -0,0 +1,1128
1 + // Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
2 + // Contributors:
3 + // Justin Palmer (http://encytemedia.com/)
4 + // Mark Pilgrim (http://diveintomark.org/)
5 + // Martin Bialasinki
6 + //
7 + // script.aculo.us is freely distributable under the terms of an MIT-style license.
8 + // For details, see the script.aculo.us web site: http://script.aculo.us/
9 +
10 + // converts rgb() and #xxx to #xxxxxx format,
11 + // returns self (or first argument) if not convertable
12 + String.prototype.parseColor = function() {
13 + var color = '#';
14 + if (this.slice(0,4) == 'rgb(') {
15 + var cols = this.slice(4,this.length-1).split(',');
16 + var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
17 + } else {
18 + if (this.slice(0,1) == '#') {
19 + if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
20 + if (this.length==7) color = this.toLowerCase();
21 + }
22 + }
23 + return (color.length==7 ? color : (arguments[0] || this));
24 + };
25 +
26 + /*--------------------------------------------------------------------------*/
27 +
28 + Element.collectTextNodes = function(element) {
29 + return $A($(element).childNodes).collect( function(node) {
30 + return (node.nodeType==3 ? node.nodeValue :
31 + (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
32 + }).flatten().join('');
33 + };
34 +
35 + Element.collectTextNodesIgnoreClass = function(element, className) {
36 + return $A($(element).childNodes).collect( function(node) {
37 + return (node.nodeType==3 ? node.nodeValue :
38 + ((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
39 + Element.collectTextNodesIgnoreClass(node, className) : ''));
40 + }).flatten().join('');
41 + };
42 +
43 + Element.setContentZoom = function(element, percent) {
44 + element = $(element);
45 + element.setStyle({fontSize: (percent/100) + 'em'});
46 + if (Prototype.Browser.WebKit) window.scrollBy(0,0);
47 + return element;
48 + };
49 +
50 + Element.getInlineOpacity = function(element){
51 + return $(element).style.opacity || '';
52 + };
53 +
54 + Element.forceRerendering = function(element) {
55 + try {
56 + element = $(element);
57 + var n = document.createTextNode(' ');
58 + element.appendChild(n);
59 + element.removeChild(n);
60 + } catch(e) { }
61 + };
62 +
63 + /*--------------------------------------------------------------------------*/
64 +
65 + var Effect = {
66 + _elementDoesNotExistError: {
67 + name: 'ElementDoesNotExistError',
68 + message: 'The specified DOM element does not exist, but is required for this effect to operate'
69 + },
70 + Transitions: {
71 + linear: Prototype.K,
72 + sinoidal: function(pos) {
73 + return (-Math.cos(pos*Math.PI)/2) + .5;
74 + },
75 + reverse: function(pos) {
76 + return 1-pos;
77 + },
78 + flicker: function(pos) {
79 + var pos = ((-Math.cos(pos*Math.PI)/4) + .75) + Math.random()/4;
80 + return pos > 1 ? 1 : pos;
81 + },
82 + wobble: function(pos) {
83 + return (-Math.cos(pos*Math.PI*(9*pos))/2) + .5;
84 + },
85 + pulse: function(pos, pulses) {
86 + return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5;
87 + },
88 + spring: function(pos) {
89 + return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
90 + },
91 + none: function(pos) {
92 + return 0;
93 + },
94 + full: function(pos) {
95 + return 1;
96 + }
97 + },
98 + DefaultOptions: {
99 + duration: 1.0, // seconds
100 + fps: 100, // 100= assume 66fps max.
101 + sync: false, // true for combining
102 + from: 0.0,
103 + to: 1.0,
104 + delay: 0.0,
105 + queue: 'parallel'
106 + },
107 + tagifyText: function(element) {
108 + var tagifyStyle = 'position:relative';
109 + if (Prototype.Browser.IE) tagifyStyle += ';zoom:1';
110 +
111 + element = $(element);
112 + $A(element.childNodes).each( function(child) {
113 + if (child.nodeType==3) {
114 + child.nodeValue.toArray().each( function(character) {
115 + element.insertBefore(
116 + new Element('span', {style: tagifyStyle}).update(
117 + character == ' ' ? String.fromCharCode(160) : character),
118 + child);
119 + });
120 + Element.remove(child);
121 + }
122 + });
123 + },
124 + multiple: function(element, effect) {
125 + var elements;
126 + if (((typeof element == 'object') ||
127 + Object.isFunction(element)) &&
128 + (element.length))
129 + elements = element;
130 + else
131 + elements = $(element).childNodes;
132 +
133 + var options = Object.extend({
134 + speed: 0.1,
135 + delay: 0.0
136 + }, arguments[2] || { });
137 + var masterDelay = options.delay;
138 +
139 + $A(elements).each( function(element, index) {
140 + new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
141 + });
142 + },
143 + PAIRS: {
144 + 'slide': ['SlideDown','SlideUp'],
145 + 'blind': ['BlindDown','BlindUp'],
146 + 'appear': ['Appear','Fade']
147 + },
148 + toggle: function(element, effect) {
149 + element = $(element);
150 + effect = (effect || 'appear').toLowerCase();
151 + var options = Object.extend({
152 + queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
153 + }, arguments[2] || { });
154 + Effect[element.visible() ?
155 + Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
156 + }
157 + };
158 +
159 + Effect.DefaultOptions.transition = Effect.Transitions.sinoidal;
160 +
161 + /* ------------- core effects ------------- */
162 +
163 + Effect.ScopedQueue = Class.create(Enumerable, {
164 + initialize: function() {
165 + this.effects = [];
166 + this.interval = null;
167 + },
168 + _each: function(iterator) {
169 + this.effects._each(iterator);
170 + },
171 + add: function(effect) {
172 + var timestamp = new Date().getTime();
173 +
174 + var position = Object.isString(effect.options.queue) ?
175 + effect.options.queue : effect.options.queue.position;
176 +
177 + switch(position) {
178 + case 'front':
179 + // move unstarted effects after this effect
180 + this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
181 + e.startOn += effect.finishOn;
182 + e.finishOn += effect.finishOn;
183 + });
184 + break;
185 + case 'with-last':
186 + timestamp = this.effects.pluck('startOn').max() || timestamp;
187 + break;
188 + case 'end':
189 + // start effect after last queued effect has finished
190 + timestamp = this.effects.pluck('finishOn').max() || timestamp;
191 + break;
192 + }
193 +
194 + effect.startOn += timestamp;
195 + effect.finishOn += timestamp;
196 +
197 + if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
198 + this.effects.push(effect);
199 +
200 + if (!this.interval)
201 + this.interval = setInterval(this.loop.bind(this), 15);
202 + },
203 + remove: function(effect) {
204 + this.effects = this.effects.reject(function(e) { return e==effect });
205 + if (this.effects.length == 0) {
206 + clearInterval(this.interval);
207 + this.interval = null;
208 + }
209 + },
210 + loop: function() {
211 + var timePos = new Date().getTime();
212 + for(var i=0, len=this.effects.length;i<len;i++)
213 + this.effects[i] && this.effects[i].loop(timePos);
214 + }
215 + });
216 +
217 + Effect.Queues = {
218 + instances: $H(),
219 + get: function(queueName) {
220 + if (!Object.isString(queueName)) return queueName;
221 +
222 + return this.instances.get(queueName) ||
223 + this.instances.set(queueName, new Effect.ScopedQueue());
224 + }
225 + };
226 + Effect.Queue = Effect.Queues.get('global');
227 +
228 + Effect.Base = Class.create({
229 + position: null,
230 + start: function(options) {
231 + function codeForEvent(options,eventName){
232 + return (
233 + (options[eventName+'Internal'] ? 'this.options.'+eventName+'Internal(this);' : '') +
234 + (options[eventName] ? 'this.options.'+eventName+'(this);' : '')
235 + );
236 + }
237 + if (options && options.transition === false) options.transition = Effect.Transitions.linear;
238 + this.options = Object.extend(Object.extend({ },Effect.DefaultOptions), options || { });
239 + this.currentFrame = 0;
240 + this.state = 'idle';
241 + this.startOn = this.options.delay*1000;
242 + this.finishOn = this.startOn+(this.options.duration*1000);
243 + this.fromToDelta = this.options.to-this.options.from;
244 + this.totalTime = this.finishOn-this.startOn;
245 + this.totalFrames = this.options.fps*this.options.duration;
246 +
247 + this.render = (function() {
248 + function dispatch(effect, eventName) {
249 + if (effect.options[eventName + 'Internal'])
250 + effect.options[eventName + 'Internal'](effect);
251 + if (effect.options[eventName])
252 + effect.options[eventName](effect);
253 + }
254 +
255 + return function(pos) {
256 + if (this.state === "idle") {
257 + this.state = "running";
258 + dispatch(this, 'beforeSetup');
259 + if (this.setup) this.setup();
260 + dispatch(this, 'afterSetup');
261 + }
262 + if (this.state === "running") {
263 + pos = (this.options.transition(pos) * this.fromToDelta) + this.options.from;
264 + this.position = pos;
265 + dispatch(this, 'beforeUpdate');
266 + if (this.update) this.update(pos);
267 + dispatch(this, 'afterUpdate');
268 + }
269 + };
270 + })();
271 +
272 + this.event('beforeStart');
273 + if (!this.options.sync)
274 + Effect.Queues.get(Object.isString(this.options.queue) ?
275 + 'global' : this.options.queue.scope).add(this);
276 + },
277 + loop: function(timePos) {
278 + if (timePos >= this.startOn) {
279 + if (timePos >= this.finishOn) {
280 + this.render(1.0);
281 + this.cancel();
282 + this.event('beforeFinish');
283 + if (this.finish) this.finish();
284 + this.event('afterFinish');
285 + return;
286 + }
287 + var pos = (timePos - this.startOn) / this.totalTime,
288 + frame = (pos * this.totalFrames).round();
289 + if (frame > this.currentFrame) {
290 + this.render(pos);
291 + this.currentFrame = frame;
292 + }
293 + }
294 + },
295 + cancel: function() {
296 + if (!this.options.sync)
297 + Effect.Queues.get(Object.isString(this.options.queue) ?
298 + 'global' : this.options.queue.scope).remove(this);
299 + this.state = 'finished';
300 + },
301 + event: function(eventName) {
302 + if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
303 + if (this.options[eventName]) this.options[eventName](this);
304 + },
305 + inspect: function() {
306 + var data = $H();
307 + for(property in this)
308 + if (!Object.isFunction(this[property])) data.set(property, this[property]);
309 + return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
310 + }
311 + });
312 +
313 + Effect.Parallel = Class.create(Effect.Base, {
314 + initialize: function(effects) {
315 + this.effects = effects || [];
316 + this.start(arguments[1]);
317 + },
318 + update: function(position) {
319 + this.effects.invoke('render', position);
320 + },
321 + finish: function(position) {
322 + this.effects.each( function(effect) {
323 + effect.render(1.0);
324 + effect.cancel();
325 + effect.event('beforeFinish');
326 + if (effect.finish) effect.finish(position);
327 + effect.event('afterFinish');
328 + });
329 + }
330 + });
331 +
332 + Effect.Tween = Class.create(Effect.Base, {
333 + initialize: function(object, from, to) {
334 + object = Object.isString(object) ? $(object) : object;
335 + var args = $A(arguments), method = args.last(),
336 + options = args.length == 5 ? args[3] : null;
337 + this.method = Object.isFunction(method) ? method.bind(object) :
338 + Object.isFunction(object[method]) ? object[method].bind(object) :
339 + function(value) { object[method] = value };
340 + this.start(Object.extend({ from: from, to: to }, options || { }));
341 + },
342 + update: function(position) {
343 + this.method(position);
344 + }
345 + });
346 +
347 + Effect.Event = Class.create(Effect.Base, {
348 + initialize: function() {
349 + this.start(Object.extend({ duration: 0 }, arguments[0] || { }));
350 + },
351 + update: Prototype.emptyFunction
352 + });
353 +
354 + Effect.Opacity = Class.create(Effect.Base, {
355 + initialize: function(element) {
356 + this.element = $(element);
357 + if (!this.element) throw(Effect._elementDoesNotExistError);
358 + // make this work on IE on elements without 'layout'
359 + if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
360 + this.element.setStyle({zoom: 1});
361 + var options = Object.extend({
362 + from: this.element.getOpacity() || 0.0,
363 + to: 1.0
364 + }, arguments[1] || { });
365 + this.start(options);
366 + },
367 + update: function(position) {
368 + this.element.setOpacity(position);
369 + }
370 + });
371 +
372 + Effect.Move = Class.create(Effect.Base, {
373 + initialize: function(element) {
374 + this.element = $(element);
375 + if (!this.element) throw(Effect._elementDoesNotExistError);
376 + var options = Object.extend({
377 + x: 0,
378 + y: 0,
379 + mode: 'relative'
380 + }, arguments[1] || { });
381 + this.start(options);
382 + },
383 + setup: function() {
384 + this.element.makePositioned();
385 + this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
386 + this.originalTop = parseFloat(this.element.getStyle('top') || '0');
387 + if (this.options.mode == 'absolute') {
388 + this.options.x = this.options.x - this.originalLeft;
389 + this.options.y = this.options.y - this.originalTop;
390 + }
391 + },
392 + update: function(position) {
393 + this.element.setStyle({
394 + left: (this.options.x * position + this.originalLeft).round() + 'px',
395 + top: (this.options.y * position + this.originalTop).round() + 'px'
396 + });
397 + }
398 + });
399 +
400 + // for backwards compatibility
401 + Effect.MoveBy = function(element, toTop, toLeft) {
402 + return new Effect.Move(element,
403 + Object.extend({ x: toLeft, y: toTop }, arguments[3] || { }));
404 + };
405 +
406 + Effect.Scale = Class.create(Effect.Base, {
407 + initialize: function(element, percent) {
408 + this.element = $(element);
409 + if (!this.element) throw(Effect._elementDoesNotExistError);
410 + var options = Object.extend({
411 + scaleX: true,
412 + scaleY: true,
413 + scaleContent: true,
414 + scaleFromCenter: false,
415 + scaleMode: 'box', // 'box' or 'contents' or { } with provided values
416 + scaleFrom: 100.0,
417 + scaleTo: percent
418 + }, arguments[2] || { });
419 + this.start(options);
420 + },
421 + setup: function() {
422 + this.restoreAfterFinish = this.options.restoreAfterFinish || false;
423 + this.elementPositioning = this.element.getStyle('position');
424 +
425 + this.originalStyle = { };
426 + ['top','left','width','height','fontSize'].each( function(k) {
427 + this.originalStyle[k] = this.element.style[k];
428 + }.bind(this));
429 +
430 + this.originalTop = this.element.offsetTop;
431 + this.originalLeft = this.element.offsetLeft;
432 +
433 + var fontSize = this.element.getStyle('font-size') || '100%';
434 + ['em','px','%','pt'].each( function(fontSizeType) {
435 + if (fontSize.indexOf(fontSizeType)>0) {
436 + this.fontSize = parseFloat(fontSize);
437 + this.fontSizeType = fontSizeType;
438 + }
439 + }.bind(this));
440 +
441 + this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
442 +
443 + this.dims = null;
444 + if (this.options.scaleMode=='box')
445 + this.dims = [this.element.offsetHeight, this.element.offsetWidth];
446 + if (/^content/.test(this.options.scaleMode))
447 + this.dims = [this.element.scrollHeight, this.element.scrollWidth];
448 + if (!this.dims)
449 + this.dims = [this.options.scaleMode.originalHeight,
450 + this.options.scaleMode.originalWidth];
451 + },
452 + update: function(position) {
453 + var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
454 + if (this.options.scaleContent && this.fontSize)
455 + this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
456 + this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
457 + },
458 + finish: function(position) {
459 + if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
460 + },
461 + setDimensions: function(height, width) {
462 + var d = { };
463 + if (this.options.scaleX) d.width = width.round() + 'px';
464 + if (this.options.scaleY) d.height = height.round() + 'px';
465 + if (this.options.scaleFromCenter) {
466 + var topd = (height - this.dims[0])/2;
467 + var leftd = (width - this.dims[1])/2;
468 + if (this.elementPositioning == 'absolute') {
469 + if (this.options.scaleY) d.top = this.originalTop-topd + 'px';
470 + if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
471 + } else {
472 + if (this.options.scaleY) d.top = -topd + 'px';
473 + if (this.options.scaleX) d.left = -leftd + 'px';
474 + }
475 + }
476 + this.element.setStyle(d);
477 + }
478 + });
479 +
480 + Effect.Highlight = Class.create(Effect.Base, {
481 + initialize: function(element) {
482 + this.element = $(element);
483 + if (!this.element) throw(Effect._elementDoesNotExistError);
484 + var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { });
485 + this.start(options);
486 + },
487 + setup: function() {
488 + // Prevent executing on elements not in the layout flow
489 + if (this.element.getStyle('display')=='none') { this.cancel(); return; }
490 + // Disable background image during the effect
491 + this.oldStyle = { };
492 + if (!this.options.keepBackgroundImage) {
493 + this.oldStyle.backgroundImage = this.element.getStyle('background-image');
494 + this.element.setStyle({backgroundImage: 'none'});
495 + }
496 + if (!this.options.endcolor)
497 + this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
498 + if (!this.options.restorecolor)
499 + this.options.restorecolor = this.element.getStyle('background-color');
500 + // init color calculations
501 + this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
502 + this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
503 + },
504 + update: function(position) {
505 + this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
506 + return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) });
507 + },
508 + finish: function() {
509 + this.element.setStyle(Object.extend(this.oldStyle, {
510 + backgroundColor: this.options.restorecolor
511 + }));
512 + }
513 + });
514 +
515 + Effect.ScrollTo = function(element) {
516 + var options = arguments[1] || { },
517 + scrollOffsets = document.viewport.getScrollOffsets(),
518 + elementOffsets = $(element).cumulativeOffset();
519 +
520 + if (options.offset) elementOffsets[1] += options.offset;
521 +
522 + return new Effect.Tween(null,
523 + scrollOffsets.top,
524 + elementOffsets[1],
525 + options,
526 + function(p){ scrollTo(scrollOffsets.left, p.round()); }
527 + );
528 + };
529 +
530 + /* ------------- combination effects ------------- */
531 +
532 + Effect.Fade = function(element) {
533 + element = $(element);
534 + var oldOpacity = element.getInlineOpacity();
535 + var options = Object.extend({
536 + from: element.getOpacity() || 1.0,
537 + to: 0.0,
538 + afterFinishInternal: function(effect) {
539 + if (effect.options.to!=0) return;
540 + effect.element.hide().setStyle({opacity: oldOpacity});
541 + }
542 + }, arguments[1] || { });
543 + return new Effect.Opacity(element,options);
544 + };
545 +
546 + Effect.Appear = function(element) {
547 + element = $(element);
548 + var options = Object.extend({
549 + from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
550 + to: 1.0,
551 + // force Safari to render floated elements properly
552 + afterFinishInternal: function(effect) {
553 + effect.element.forceRerendering();
554 + },
555 + beforeSetup: function(effect) {
556 + effect.element.setOpacity(effect.options.from).show();
557 + }}, arguments[1] || { });
558 + return new Effect.Opacity(element,options);
559 + };
560 +
561 + Effect.Puff = function(element) {
562 + element = $(element);
563 + var oldStyle = {
564 + opacity: element.getInlineOpacity(),
565 + position: element.getStyle('position'),
566 + top: element.style.top,
567 + left: element.style.left,
568 + width: element.style.width,
569 + height: element.style.height
570 + };
571 + return new Effect.Parallel(
572 + [ new Effect.Scale(element, 200,
573 + { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
574 + new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
575 + Object.extend({ duration: 1.0,
576 + beforeSetupInternal: function(effect) {
577 + Position.absolutize(effect.effects[0].element);
578 + },
579 + afterFinishInternal: function(effect) {
580 + effect.effects[0].element.hide().setStyle(oldStyle); }
581 + }, arguments[1] || { })
582 + );
583 + };
584 +
585 + Effect.BlindUp = function(element) {
586 + element = $(element);
587 + element.makeClipping();
588 + return new Effect.Scale(element, 0,
589 + Object.extend({ scaleContent: false,
590 + scaleX: false,
591 + restoreAfterFinish: true,
592 + afterFinishInternal: function(effect) {
593 + effect.element.hide().undoClipping();
594 + }
595 + }, arguments[1] || { })
596 + );
597 + };
598 +
599 + Effect.BlindDown = function(element) {
600 + element = $(element);
601 + var elementDimensions = element.getDimensions();
602 + return new Effect.Scale(element, 100, Object.extend({
603 + scaleContent: false,
604 + scaleX: false,
605 + scaleFrom: 0,
606 + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
607 + restoreAfterFinish: true,
608 + afterSetup: function(effect) {
609 + effect.element.makeClipping().setStyle({height: '0px'}).show();
610 + },
611 + afterFinishInternal: function(effect) {
612 + effect.element.undoClipping();
613 + }
614 + }, arguments[1] || { }));
615 + };
616 +
617 + Effect.SwitchOff = function(element) {
618 + element = $(element);
619 + var oldOpacity = element.getInlineOpacity();
620 + return new Effect.Appear(element, Object.extend({
621 + duration: 0.4,
622 + from: 0,
623 + transition: Effect.Transitions.flicker,
624 + afterFinishInternal: function(effect) {
625 + new Effect.Scale(effect.element, 1, {
626 + duration: 0.3, scaleFromCenter: true,
627 + scaleX: false, scaleContent: false, restoreAfterFinish: true,
628 + beforeSetup: function(effect) {
629 + effect.element.makePositioned().makeClipping();
630 + },
631 + afterFinishInternal: function(effect) {
632 + effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
633 + }
634 + });
635 + }
636 + }, arguments[1] || { }));
637 + };
638 +
639 + Effect.DropOut = function(element) {
640 + element = $(element);
641 + var oldStyle = {
642 + top: element.getStyle('top'),
643 + left: element.getStyle('left'),
644 + opacity: element.getInlineOpacity() };
645 + return new Effect.Parallel(
646 + [ new Effect.Move(element, {x: 0, y: 100, sync: true }),
647 + new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
648 + Object.extend(
649 + { duration: 0.5,
650 + beforeSetup: function(effect) {
651 + effect.effects[0].element.makePositioned();
652 + },
653 + afterFinishInternal: function(effect) {
654 + effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
655 + }
656 + }, arguments[1] || { }));
657 + };
658 +
659 + Effect.Shake = function(element) {
660 + element = $(element);
661 + var options = Object.extend({
662 + distance: 20,
663 + duration: 0.5
664 + }, arguments[1] || {});
665 + var distance = parseFloat(options.distance);
666 + var split = parseFloat(options.duration) / 10.0;
667 + var oldStyle = {
668 + top: element.getStyle('top'),
669 + left: element.getStyle('left') };
670 + return new Effect.Move(element,
671 + { x: distance, y: 0, duration: split, afterFinishInternal: function(effect) {
672 + new Effect.Move(effect.element,
673 + { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
674 + new Effect.Move(effect.element,
675 + { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
676 + new Effect.Move(effect.element,
677 + { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
678 + new Effect.Move(effect.element,
679 + { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
680 + new Effect.Move(effect.element,
681 + { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) {
682 + effect.element.undoPositioned().setStyle(oldStyle);
683 + }}); }}); }}); }}); }}); }});
684 + };
685 +
686 + Effect.SlideDown = function(element) {
687 + element = $(element).cleanWhitespace();
688 + // SlideDown need to have the content of the element wrapped in a container element with fixed height!
689 + var oldInnerBottom = element.down().getStyle('bottom');
690 + var elementDimensions = element.getDimensions();
691 + return new Effect.Scale(element, 100, Object.extend({
692 + scaleContent: false,
693 + scaleX: false,
694 + scaleFrom: window.opera ? 0 : 1,
695 + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
696 + restoreAfterFinish: true,
697 + afterSetup: function(effect) {
698 + effect.element.makePositioned();
699 + effect.element.down().makePositioned();
700 + if (window.opera) effect.element.setStyle({top: ''});
701 + effect.element.makeClipping().setStyle({height: '0px'}).show();
702 + },
703 + afterUpdateInternal: function(effect) {
704 + effect.element.down().setStyle({bottom:
705 + (effect.dims[0] - effect.element.clientHeight) + 'px' });
706 + },
707 + afterFinishInternal: function(effect) {
708 + effect.element.undoClipping().undoPositioned();
709 + effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
710 + }, arguments[1] || { })
711 + );
712 + };
713 +
714 + Effect.SlideUp = function(element) {
715 + element = $(element).cleanWhitespace();
716 + var oldInnerBottom = element.down().getStyle('bottom');
717 + var elementDimensions = element.getDimensions();
718 + return new Effect.Scale(element, window.opera ? 0 : 1,
719 + Object.extend({ scaleContent: false,
720 + scaleX: false,
721 + scaleMode: 'box',
722 + scaleFrom: 100,
723 + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
724 + restoreAfterFinish: true,
725 + afterSetup: function(effect) {
726 + effect.element.makePositioned();
727 + effect.element.down().makePositioned();
728 + if (window.opera) effect.element.setStyle({top: ''});
729 + effect.element.makeClipping().show();
730 + },
731 + afterUpdateInternal: function(effect) {
732 + effect.element.down().setStyle({bottom:
733 + (effect.dims[0] - effect.element.clientHeight) + 'px' });
734 + },
735 + afterFinishInternal: function(effect) {
736 + effect.element.hide().undoClipping().undoPositioned();
737 + effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom});
738 + }
739 + }, arguments[1] || { })
740 + );
741 + };
742 +
743 + // Bug in opera makes the TD containing this element expand for a instance after finish
744 + Effect.Squish = function(element) {
745 + return new Effect.Scale(element, window.opera ? 1 : 0, {
746 + restoreAfterFinish: true,
747 + beforeSetup: function(effect) {
748 + effect.element.makeClipping();
749 + },
750 + afterFinishInternal: function(effect) {
751 + effect.element.hide().undoClipping();
752 + }
753 + });
754 + };
755 +
756 + Effect.Grow = function(element) {
757 + element = $(element);
758 + var options = Object.extend({
759 + direction: 'center',
760 + moveTransition: Effect.Transitions.sinoidal,
761 + scaleTransition: Effect.Transitions.sinoidal,
762 + opacityTransition: Effect.Transitions.full
763 + }, arguments[1] || { });
764 + var oldStyle = {
765 + top: element.style.top,
766 + left: element.style.left,
767 + height: element.style.height,
768 + width: element.style.width,
769 + opacity: element.getInlineOpacity() };
770 +
771 + var dims = element.getDimensions();
772 + var initialMoveX, initialMoveY;
773 + var moveX, moveY;
774 +
775 + switch (options.direction) {
776 + case 'top-left':
777 + initialMoveX = initialMoveY = moveX = moveY = 0;
778 + break;
779 + case 'top-right':
780 + initialMoveX = dims.width;
781 + initialMoveY = moveY = 0;
782 + moveX = -dims.width;
783 + break;
784 + case 'bottom-left':
785 + initialMoveX = moveX = 0;
786 + initialMoveY = dims.height;
787 + moveY = -dims.height;
788 + break;
789 + case 'bottom-right':
790 + initialMoveX = dims.width;
791 + initialMoveY = dims.height;
792 + moveX = -dims.width;
793 + moveY = -dims.height;
794 + break;
795 + case 'center':
796 + initialMoveX = dims.width / 2;
797 + initialMoveY = dims.height / 2;
798 + moveX = -dims.width / 2;
799 + moveY = -dims.height / 2;
800 + break;
801 + }
802 +
803 + return new Effect.Move(element, {
804 + x: initialMoveX,
805 + y: initialMoveY,
806 + duration: 0.01,
807 + beforeSetup: function(effect) {
808 + effect.element.hide().makeClipping().makePositioned();
809 + },
810 + afterFinishInternal: function(effect) {
811 + new Effect.Parallel(
812 + [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
813 + new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
814 + new Effect.Scale(effect.element, 100, {
815 + scaleMode: { originalHeight: dims.height, originalWidth: dims.width },
816 + sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
817 + ], Object.extend({
818 + beforeSetup: function(effect) {
819 + effect.effects[0].element.setStyle({height: '0px'}).show();
820 + },
821 + afterFinishInternal: function(effect) {
822 + effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);
823 + }
824 + }, options)
825 + );
826 + }
827 + });
828 + };
829 +
830 + Effect.Shrink = function(element) {
831 + element = $(element);
832 + var options = Object.extend({
833 + direction: 'center',
834 + moveTransition: Effect.Transitions.sinoidal,
835 + scaleTransition: Effect.Transitions.sinoidal,
836 + opacityTransition: Effect.Transitions.none
837 + }, arguments[1] || { });
838 + var oldStyle = {
839 + top: element.style.top,
840 + left: element.style.left,
841 + height: element.style.height,
842 + width: element.style.width,
843 + opacity: element.getInlineOpacity() };
844 +
845 + var dims = element.getDimensions();
846 + var moveX, moveY;
847 +
848 + switch (options.direction) {
849 + case 'top-left':
850 + moveX = moveY = 0;
851 + break;
852 + case 'top-right':
853 + moveX = dims.width;
854 + moveY = 0;
855 + break;
856 + case 'bottom-left':
857 + moveX = 0;
858 + moveY = dims.height;
859 + break;
860 + case 'bottom-right':
861 + moveX = dims.width;
862 + moveY = dims.height;
863 + break;
864 + case 'center':
865 + moveX = dims.width / 2;
866 + moveY = dims.height / 2;
867 + break;
868 + }
869 +
870 + return new Effect.Parallel(
871 + [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
872 + new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
873 + new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
874 + ], Object.extend({
875 + beforeStartInternal: function(effect) {
876 + effect.effects[0].element.makePositioned().makeClipping();
877 + },
878 + afterFinishInternal: function(effect) {
879 + effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
880 + }, options)
881 + );
882 + };
883 +
884 + Effect.Pulsate = function(element) {
885 + element = $(element);
886 + var options = arguments[1] || { },
887 + oldOpacity = element.getInlineOpacity(),
888 + transition = options.transition || Effect.Transitions.linear,
889 + reverser = function(pos){
890 + return 1 - transition((-Math.cos((pos*(options.pulses||5)*2)*Math.PI)/2) + .5);
891 + };
892 +
893 + return new Effect.Opacity(element,
894 + Object.extend(Object.extend({ duration: 2.0, from: 0,
895 + afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
896 + }, options), {transition: reverser}));
897 + };
898 +
899 + Effect.Fold = function(element) {
900 + element = $(element);
901 + var oldStyle = {
902 + top: element.style.top,
903 + left: element.style.left,
904 + width: element.style.width,
905 + height: element.style.height };
906 + element.makeClipping();
907 + return new Effect.Scale(element, 5, Object.extend({
908 + scaleContent: false,
909 + scaleX: false,
910 + afterFinishInternal: function(effect) {
911 + new Effect.Scale(element, 1, {
912 + scaleContent: false,
913 + scaleY: false,
914 + afterFinishInternal: function(effect) {
915 + effect.element.hide().undoClipping().setStyle(oldStyle);
916 + } });
917 + }}, arguments[1] || { }));
918 + };
919 +
920 + Effect.Morph = Class.create(Effect.Base, {
921 + initialize: function(element) {
922 + this.element = $(element);
923 + if (!this.element) throw(Effect._elementDoesNotExistError);
924 + var options = Object.extend({
925 + style: { }
926 + }, arguments[1] || { });
927 +
928 + if (!Object.isString(options.style)) this.style = $H(options.style);
929 + else {
930 + if (options.style.include(':'))
931 + this.style = options.style.parseStyle();
932 + else {
933 + this.element.addClassName(options.style);
934 + this.style = $H(this.element.getStyles());
935 + this.element.removeClassName(options.style);
936 + var css = this.element.getStyles();
937 + this.style = this.style.reject(function(style) {
938 + return style.value == css[style.key];
939 + });
940 + options.afterFinishInternal = function(effect) {
941 + effect.element.addClassName(effect.options.style);
942 + effect.transforms.each(function(transform) {
943 + effect.element.style[transform.style] = '';
944 + });
945 + };
946 + }
947 + }
948 + this.start(options);
949 + },
950 +
951 + setup: function(){
952 + function parseColor(color){
953 + if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
954 + color = color.parseColor();
955 + return $R(0,2).map(function(i){
956 + return parseInt( color.slice(i*2+1,i*2+3), 16 );
957 + });
958 + }
959 + this.transforms = this.style.map(function(pair){
960 + var property = pair[0], value = pair[1], unit = null;
961 +
962 + if (value.parseColor('#zzzzzz') != '#zzzzzz') {
963 + value = value.parseColor();
964 + unit = 'color';
965 + } else if (property == 'opacity') {
966 + value = parseFloat(value);
967 + if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
968 + this.element.setStyle({zoom: 1});
969 + } else if (Element.CSS_LENGTH.test(value)) {
970 + var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
971 + value = parseFloat(components[1]);
972 + unit = (components.length == 3) ? components[2] : null;
973 + }
974 +
975 + var originalValue = this.element.getStyle(property);
976 + return {
977 + style: property.camelize(),
978 + originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0),
979 + targetValue: unit=='color' ? parseColor(value) : value,
980 + unit: unit
981 + };
982 + }.bind(this)).reject(function(transform){
983 + return (
984 + (transform.originalValue == transform.targetValue) ||
985 + (
986 + transform.unit != 'color' &&
987 + (isNaN(transform.originalValue) || isNaN(transform.targetValue))
988 + )
989 + );
990 + });
991 + },
992 + update: function(position) {
993 + var style = { }, transform, i = this.transforms.length;
994 + while(i--)
995 + style[(transform = this.transforms[i]).style] =
996 + transform.unit=='color' ? '#'+
997 + (Math.round(transform.originalValue[0]+
998 + (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
999 + (Math.round(transform.originalValue[1]+
1000 + (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +
1001 + (Math.round(transform.originalValue[2]+
1002 + (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
1003 + (transform.originalValue +
1004 + (transform.targetValue - transform.originalValue) * position).toFixed(3) +
1005 + (transform.unit === null ? '' : transform.unit);
1006 + this.element.setStyle(style, true);
1007 + }
1008 + });
1009 +
1010 + Effect.Transform = Class.create({
1011 + initialize: function(tracks){
1012 + this.tracks = [];
1013 + this.options = arguments[1] || { };
1014 + this.addTracks(tracks);
1015 + },
1016 + addTracks: function(tracks){
1017 + tracks.each(function(track){
1018 + track = $H(track);
1019 + var data = track.values().first();
1020 + this.tracks.push($H({
1021 + ids: track.keys().first(),
1022 + effect: Effect.Morph,
1023 + options: { style: data }
1024 + }));
1025 + }.bind(this));
1026 + return this;
1027 + },
1028 + play: function(){
1029 + return new Effect.Parallel(
1030 + this.tracks.map(function(track){
1031 + var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options');
1032 + var elements = [$(ids) || $$(ids)].flatten();
1033 + return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) });
1034 + }).flatten(),
1035 + this.options
1036 + );
1037 + }
1038 + });
1039 +
1040 + Element.CSS_PROPERTIES = $w(
1041 + 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' +
1042 + 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
1043 + 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
1044 + 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
1045 + 'fontSize fontWeight height left letterSpacing lineHeight ' +
1046 + 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
1047 + 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
1048 + 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
1049 + 'right textIndent top width wordSpacing zIndex');
1050 +
1051 + Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
1052 +
1053 + String.__parseStyleElement = document.createElement('div');
1054 + String.prototype.parseStyle = function(){
1055 + var style, styleRules = $H();
1056 + if (Prototype.Browser.WebKit)
1057 + style = new Element('div',{style:this}).style;
1058 + else {
1059 + String.__parseStyleElement.innerHTML = '<div style="' + this + '"></div>';
1060 + style = String.__parseStyleElement.childNodes[0].style;
1061 + }
1062 +
1063 + Element.CSS_PROPERTIES.each(function(property){
1064 + if (style[property]) styleRules.set(property, style[property]);
1065 + });
1066 +
1067 + if (Prototype.Browser.IE && this.include('opacity'))
1068 + styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]);
1069 +
1070 + return styleRules;
1071 + };
1072 +
1073 + if (document.defaultView && document.defaultView.getComputedStyle) {
1074 + Element.getStyles = function(element) {
1075 + var css = document.defaultView.getComputedStyle($(element), null);
1076 + return Element.CSS_PROPERTIES.inject({ }, function(styles, property) {
1077 + styles[property] = css[property];
1078 + return styles;
1079 + });
1080 + };
1081 + } else {
1082 + Element.getStyles = function(element) {
1083 + element = $(element);
1084 + var css = element.currentStyle, styles;
1085 + styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) {
1086 + results[property] = css[property];
1087 + return results;
1088 + });
1089 + if (!styles.opacity) styles.opacity = element.getOpacity();
1090 + return styles;
1091 + };
1092 + }
1093 +
1094 + Effect.Methods = {
1095 + morph: function(element, style) {
1096 + element = $(element);
1097 + new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { }));
1098 + return element;
1099 + },
1100 + visualEffect: function(element, effect, options) {
1101 + element = $(element);
1102 + var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1);
1103 + new Effect[klass](element, options);
1104 + return element;
1105 + },
1106 + highlight: function(element, options) {
1107 + element = $(element);
1108 + new Effect.Highlight(element, options);
1109 + return element;
1110 + }
1111 + };
1112 +
1113 + $w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+
1114 + 'pulsate shake puff squish switchOff dropOut').each(
1115 + function(effect) {
1116 + Effect.Methods[effect] = function(element, options){
1117 + element = $(element);
1118 + Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options);
1119 + return element;
1120 + };
1121 + }
1122 + );
1123 +
1124 + $w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each(
1125 + function(f) { Effect.Methods[f] = Element[f]; }
1126 + );
1127 +
1128 + Element.addMethods(Effect.Methods); No newline at end of file
@@ -0,0 +1,32
1 + function updateSiteList() {
2 + currentCountry = document.getElementById("site_country_id").value;
3 +
4 + sites = siteList[currentCountry];
5 + siteSelect = document.getElementById("login_site_id");
6 + old_len = siteSelect.length;
7 + // clear old box
8 + for(i=0; i<old_len; i++) siteSelect.remove(0);
9 +
10 + if(currentCountry==0) {
11 + for(i=0; i<allSiteList.length; i++) {
12 + if(allSiteList[i]!=null) {
13 + try {
14 + siteSelect.add(new Option(allSiteList[i],""+i,false,false),null);
15 + } catch(ex) {
16 + siteSelect.add(new Option(allSiteList[i],""+i,false,false));
17 + }
18 + }
19 + }
20 + } else {
21 + for(i=0; i<sites.length; i++) {
22 + if(sites[i]!=null) {
23 + try {
24 + siteSelect.add(new Option(sites[i],""+i,false,false),null);
25 + } catch(ex) {
26 + siteSelect.add(new Option(sites[i],""+i,false,false));
27 + }
28 + }
29 + }
30 + }
31 + }
32 + No newline at end of file
@@ -0,0 +1,17
1 +
2 + table.graders tr.active {
3 + border: 1px solid black;
4 + background: lightgreen;
5 + text-align: center;
6 + }
7 +
8 + table.graders tr.inactive {
9 + border: 1px solid black;
10 + background: #ffcccc;
11 + text-align: center;
12 + }
13 +
14 + .submitbox .item {
15 + padding-right: 5px;
16 + float: left;
17 + }
@@ -0,0 +1,14
1 +
2 + tr.available {
3 + background: #c0ffc0;
4 + }
5 +
6 + tr.not-available {
7 + background: #ffc0c0;
8 + }
9 +
10 + .import-log {
11 + background: lightgray;
12 + border: solid black 1px;
13 + padding: 10px;
14 + } No newline at end of file
@@ -29,20 +29,20
29
29
30 # Use unicorn as the app server
30 # Use unicorn as the app server
31 # gem 'unicorn'
31 # gem 'unicorn'
32
32
33 # Deploy with Capistrano
33 # Deploy with Capistrano
34 # gem 'capistrano'
34 # gem 'capistrano'
35
35
36 # To use debugger
36 # To use debugger
37 # gem 'debugger'
37 # gem 'debugger'
38
38
39 gem "haml"
39 gem "haml"
40 gem "tmail"
40 gem "tmail"
41 - gem "rdiscount", :require => "rdiscount"
41 + gem "rdiscount"
42 gem "test-unit"
42 gem "test-unit"
43 gem 'will_paginate', '~> 3.0.0'
43 gem 'will_paginate', '~> 3.0.0'
44 gem 'dynamic_form'
44 gem 'dynamic_form'
45
45
46 group :test, :development do
46 group :test, :development do
47 gem "rspec-rails", "~> 2.0"
47 gem "rspec-rails", "~> 2.0"
48 end
48 end
@@ -3,13 +3,13
3 //
3 //
4 // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
4 // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5 // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
5 // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6 //
6 //
7 // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
7 // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8 // the compiled file.
8 // the compiled file.
9 //
9 //
10 // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
10 // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
11 // GO AFTER THE REQUIRES BELOW.
11 // GO AFTER THE REQUIRES BELOW.
12 //
12 //
13 //= require prototype
13 //= require prototype
14 //= require prototype_ujs
14 //= require prototype_ujs
15 - //= require_tree .
15 +
@@ -1,13 +1,255
1 /*
1 /*
2 - * This is a manifest file that'll be compiled into application.css, which will include all the files
2 + * This is a manifest file that'll be compiled into application.css, which will include all the
3 - * listed below.
3 + * listed below.
4 - *
4 + *
5 - * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
5 + * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheet
6 - * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
6 + * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path
7 - *
7 + *
8 - * You're free to add application-wide styles to this file and they'll appear at the top of the
8 + * You're free to add application-wide styles to this file and they'll appear at the top of the
9 - * compiled file, but it's generally better to create a new file per style scope.
9 + * compiled file, but it's generally better to create a new file per style scope.
10 - *
10 + *
11 - *= require_self
11 + *= require_self
12 - *= require_tree .
12 + */
13 - */
13 +
14 + body {
15 + background: white url(../images/topbg.jpg) repeat-x top center;
16 + font-size: 13px;
17 + font-family: Tahoma, "sans-serif";
18 + margin: 10px;
19 + padding: 10px; }
20 +
21 + input {
22 + font-family: Tahoma, "sans-serif"; }
23 +
24 + h1 {
25 + font-size: 24px;
26 + color: #334488;
27 + line-height: 2em; }
28 +
29 + h2 {
30 + font-size: 18px;
31 + color: #5566bb;
32 + line-height: 1.5em; }
33 +
34 + hr {
35 + border-top: 1px solid #dddddd;
36 + border-bottom: 1px solid #eeeeee; }
37 +
38 + a {
39 + color: #6666cc;
40 + text-decoration: none; }
41 + a:link, a:visited {
42 + color: #6666cc;
43 + text-decoration: none; }
44 + a:hover, a:focus {
45 + color: #111166;
46 + text-decoration: none; }
47 +
48 + div.userbar {
49 + line-height: 1.5em;
50 + text-align: right;
51 + font-size: 12px; }
52 + div.title {
53 + padding: 10px 0px;
54 + line-height: 1.5em;
55 + font-size: 13px; }
56 + div.title span.contest-over-msg {
57 + font-size: 15px;
58 + color: red; }
59 + div.title table {
60 + width: 100%;
61 + font-weight: bold; }
62 + div.title td.left-col {
63 + text-align: left;
64 + vertical-align: top;
65 + color: #444444; }
66 + div.title td.right-col {
67 + text-align: right;
68 + vertical-align: top;
69 + font-size: 18px;
70 + color: #116699; }
71 +
72 + table.info {
73 + margin: 10px 0;
74 + border: 1px solid #666666;
75 + border-collapse: collapse;
76 + font-size: 12px; }
77 + table.info th {
78 + border: 1px solid #666666;
79 + line-height: 1.5em;
80 + padding: 0 0.5em; }
81 + table.info td {
82 + border-left: 1px solid #666666;
83 + border-right: 1px solid #666666;
84 + line-height: 1.5em;
85 + padding: 0 0.5em; }
86 +
87 + tr.info-head {
88 + background: #777777;
89 + color: white; }
90 + tr.info-odd {
91 + background: #eeeeee; }
92 + tr.info-even {
93 + background: #fcfcfc; }
94 +
95 + .infobox {
96 + background: #eeeeff;
97 + border: 1px dotted #99aaee;
98 + padding: 5px;
99 + margin: 10px 0px;
100 + color: black;
101 + font-size: 13px; }
102 +
103 + .submitbox {
104 + background: #eeeeff;
105 + border: 1px dotted #99aaee;
106 + padding: 5px;
107 + margin: 10px 0px;
108 + color: black;
109 + font-size: 13px; }
110 +
111 + .errorExplanation {
112 + border: 1px dotted gray;
113 + color: #bb2222;
114 + padding: 5px 15px 5px 15px;
115 + margin-bottom: 5px;
116 + background-color: white;
117 + font-weight: normal; }
118 + .errorExplanation h2 {
119 + color: #cc1111;
120 + font-weight: bold; }
121 +
122 + table.uinfo {
123 + border-collapse: collapse;
124 + border: 1px solid black;
125 + font-size: 13px; }
126 +
127 + td.uinfo {
128 + vertical-align: top;
129 + border: 1px solid black;
130 + padding: 5px; }
131 +
132 + th.uinfo {
133 + background: lightgreen;
134 + vertical-align: top;
135 + text-align: right;
136 + border: 1px solid black;
137 + padding: 5px; }
138 +
139 + div.compilermsgbody {
140 + font-family: monospace; }
141 + div.task-menu {
142 + text-align: center;
143 + font-size: 13px;
144 + line-height: 1.75em;
145 + font-weight: bold;
146 + border-top: 1px dashed gray;
147 + border-bottom: 1px dashed gray;
148 + margin-top: 2px;
149 + margin-bottom: 4px; }
150 +
151 + table.taskdesc {
152 + border: 2px solid #dddddd;
153 + border-collapse: collapse;
154 + margin: 10px auto;
155 + width: 90%;
156 + font-size: 13px; }
157 + table.taskdesc p {
158 + font-size: 13px; }
159 + table.taskdesc tr.name {
160 + border: 2px solid #dddddd;
161 + background: #dddddd;
162 + color: #333333;
163 + font-weight: bold;
164 + font-size: 14px;
165 + line-height: 1.5em;
166 + text-align: center; }
167 + table.taskdesc td.desc-odd {
168 + padding: 5px;
169 + padding-left: 20px;
170 + background: #fefeee; }
171 + table.taskdesc td.desc-even {
172 + padding: 5px;
173 + padding-left: 20px;
174 + background: #feeefe; }
175 +
176 + .announcementbox {
177 + margin: 10px 0px;
178 + background: #bbddee;
179 + padding: 1px; }
180 + .announcementbox span.title {
181 + font-weight: bold;
182 + color: #224455;
183 + padding-left: 10px;
184 + line-height: 1.6em; }
185 +
186 + .announcement {
187 + margin: 2px;
188 + background: white;
189 + padding: 1px;
190 + padding-left: 10px;
191 + padding-right: 10px;
192 + padding-top: 5px;
193 + padding-bottom: 5px; }
194 +
195 + .announcement p {
196 + font-size: 12px;
197 + margin: 2px; }
198 +
199 + .pub-info {
200 + text-align: right;
201 + font-style: italic;
202 + font-size: 9px; }
203 + .pub-info p {
204 + text-align: right;
205 + font-style: italic;
206 + font-size: 9px; }
207 +
208 + .announcement .toggles {
209 + font-weight: normal;
210 + float: right;
211 + font-size: 80%; }
212 + .announcement .announcement-title {
213 + font-weight: bold; }
214 +
215 + div.message {
216 + margin: 10px 0 0; }
217 + div.message div.message {
218 + margin: 0 0 0 30px; }
219 + div.message div.body {
220 + border: 2px solid #dddddd;
221 + background: #fff8f8;
222 + padding-left: 5px; }
223 + div.message div.reply-body {
224 + border: 2px solid #bbbbbb;
225 + background: #fffff8;
226 + padding-left: 5px; }
227 + div.message div.stat {
228 + font-size: 10px;
229 + line-height: 1.75em;
230 + padding: 0 5px;
231 + color: #333333;
232 + background: #dddddd;
233 + font-weight: bold; }
234 + div.message div.message div.stat {
235 + font-size: 10px;
236 + line-height: 1.75em;
237 + padding: 0 5px;
238 + color: #444444;
239 + background: #bbbbbb;
240 + font-weight: bold; }
241 + div.contest-title {
242 + color: white;
243 + text-align: center;
244 + line-height: 2em; }
245 + div.registration-desc, div.test-desc {
246 + border: 1px dotted gray;
247 + background: #f5f5f5;
248 + padding: 5px;
249 + margin: 10px 0;
250 + font-size: 12px;
251 + line-height: 1.5em; }
252 +
253 + h2.contest-title {
254 + margin-top: 5px;
255 + margin-bottom: 5px; }
@@ -116,13 +116,18
116 #{t 'title_bar.current_time'} #{format_short_time(Time.new)}
116 #{t 'title_bar.current_time'} #{format_short_time(Time.new)}
117 #{time_left}
117 #{time_left}
118 <br/>
118 <br/>
119 </td>
119 </td>
120 <td class="right-col">#{contest_name}</td>
120 <td class="right-col">#{contest_name}</td>
121 </tr>
121 </tr>
122 </table>
122 </table>
123 </div>
123 </div>
124 TITLEBAR
124 TITLEBAR
125 result.html_safe
125 result.html_safe
126 end
126 end
127
127
128 + def markdown(text)
129 + markdown = RDiscount.new(text)
130 + markdown.to_html.html_safe
131 + end
132 +
128 end
133 end
@@ -1,16 +1,12
1 - <% content_for :head do %>
2 - <%= javascript_include_tag :defaults %>
3 - <% end %>
4 -
5 <h1>Listing announcements</h1>
1 <h1>Listing announcements</h1>
6
2
7 <%= link_to 'New announcement', new_announcement_path %>
3 <%= link_to 'New announcement', new_announcement_path %>
8
4
9 <table class="info">
5 <table class="info">
10 <tr class="info-head">
6 <tr class="info-head">
11 <th>Updated</th>
7 <th>Updated</th>
12 <th>Announcement</th>
8 <th>Announcement</th>
13 <th>Author</th>
9 <th>Author</th>
14 <th>Published</th>
10 <th>Published</th>
15 <th></th>
11 <th></th>
16 <th></th>
12 <th></th>
@@ -1,15 +1,12
1 - - content_for :head do
2 - = javascript_include_tag :defaults
3 -
4 %h1 System configuration
1 %h1 System configuration
5
2
6 %table.info
3 %table.info
7 %tr.info-head
4 %tr.info-head
8 %th Key
5 %th Key
9 %th Type
6 %th Type
10 %th Value
7 %th Value
11 %th Description
8 %th Description
12 - @configurations.each do |conf|
9 - @configurations.each do |conf|
13 - @configuration = conf
10 - @configuration = conf
14 %tr{:class => cycle("info-odd", "info-even")}
11 %tr{:class => cycle("info-odd", "info-even")}
15 %td
12 %td
@@ -1,31 +1,31
1 %h1 Contest management
1 %h1 Contest management
2
2
3 .infobox
3 .infobox
4
4
5 - if @num_contests>1
5 - if @num_contests>1
6 %b Multiple contests:
6 %b Multiple contests:
7 = "There are #{@num_contests} contests running."
7 = "There are #{@num_contests} contests running."
8 - else
8 - else
9 %b Single contest:
9 %b Single contest:
10 - = "[#{link_to 'Add/remove contests', :controller => 'contests', :action => 'index'}]"
10 + =raw "[#{link_to 'Add/remove contests', :controller => 'contests', :action => 'index'}]"
11
11
12 .infobox
12 .infobox
13 %b Web interface mode:
13 %b Web interface mode:
14 - if (not GraderConfiguration.contest_mode?) and (not GraderConfiguration.indv_contest_mode?)
14 - if (not GraderConfiguration.contest_mode?) and (not GraderConfiguration.indv_contest_mode?)
15 standard mode
15 standard mode
16 - elsif GraderConfiguration.contest_mode?
16 - elsif GraderConfiguration.contest_mode?
17 normal contest mode.
17 normal contest mode.
18 - else
18 - else
19 individual contest mode.
19 individual contest mode.
20
20
21 %br/
21 %br/
22 Change mode to:
22 Change mode to:
23 - = "[#{link_to 'standard', :action => 'change_contest_mode', :id => 'standard'}]"
23 + =raw "[#{link_to 'standard', :action => 'change_contest_mode', :id => 'standard'}]"
24 - = "[#{link_to 'contest', :action => 'change_contest_mode', :id => 'contest'}]"
24 + =raw "[#{link_to 'contest', :action => 'change_contest_mode', :id => 'contest'}]"
25 - = "[#{link_to 'individual contest', :action => 'change_contest_mode', :id => 'indv-contest'}]"
25 + =raw "[#{link_to 'individual contest', :action => 'change_contest_mode', :id => 'indv-contest'}]"
26
26
27 - if GraderConfiguration.indv_contest_mode?
27 - if GraderConfiguration.indv_contest_mode?
28 = render :partial => 'indv_contest_mode_index'
28 = render :partial => 'indv_contest_mode_index'
29
29
30 %br/
30 %br/
31
31
@@ -1,16 +1,12
1 - <% content_for :head do %>
2 - <%= javascript_include_tag :defaults %>
3 - <% end %>
4 -
5 <h1>Listing contests</h1>
1 <h1>Listing contests</h1>
6
2
7 <div class="infobox">
3 <div class="infobox">
8 <b>Go back to:</b> [<%= link_to 'contest management', :controller => 'contest_management', :action => 'index' %>]
4 <b>Go back to:</b> [<%= link_to 'contest management', :controller => 'contest_management', :action => 'index' %>]
9 </div>
5 </div>
10
6
11 <table>
7 <table>
12 <tr>
8 <tr>
13 <th>Name</th>
9 <th>Name</th>
14 <th>Title</th>
10 <th>Title</th>
15 <th>Enabled</th>
11 <th>Enabled</th>
16 </tr>
12 </tr>
@@ -2,50 +2,50
2 = stylesheet_link_tag 'graders'
2 = stylesheet_link_tag 'graders'
3 <meta http-equiv ="refresh" content="60"/>
3 <meta http-equiv ="refresh" content="60"/>
4
4
5 %h1 Grader information
5 %h1 Grader information
6
6
7 = link_to '[Refresh]', :action => 'list'
7 = link_to '[Refresh]', :action => 'list'
8 %br/
8 %br/
9
9
10 .submitbox
10 .submitbox
11 .item
11 .item
12 Grader control:
12 Grader control:
13 .item
13 .item
14 - = form_for :clear, nil, :url => {:action => 'start_grading'} do |f|
14 + = form_for :clear, :url => {:action => 'start_grading'} do |f|
15 = submit_tag 'Start graders in grading env'
15 = submit_tag 'Start graders in grading env'
16 .item
16 .item
17 - = form_for :clear, nil, :url => {:action => 'start_exam'} do |f|
17 + = form_for :clear, :url => {:action => 'start_exam'} do |f|
18 = submit_tag 'Start graders in exam env'
18 = submit_tag 'Start graders in exam env'
19 .item
19 .item
20 - = form_for :clear, nil, :url => {:action => 'stop_all'} do |f|
20 + = form_for :clear, :url => {:action => 'stop_all'} do |f|
21 = submit_tag 'Stop all running graders'
21 = submit_tag 'Stop all running graders'
22 .item
22 .item
23 - = form_for :clear, nil, :url => {:action => 'clear_all'} do |f|
23 + = form_for :clear, :url => {:action => 'clear_all'} do |f|
24 = submit_tag 'Clear all data'
24 = submit_tag 'Clear all data'
25 %br{:style => 'clear:both'}/
25 %br{:style => 'clear:both'}/
26
26
27 - if @last_task
27 - if @last_task
28 Last task:
28 Last task:
29 = link_to "#{@last_task.id}", :action => 'view', :id => @last_task.id, :type => 'Task'
29 = link_to "#{@last_task.id}", :action => 'view', :id => @last_task.id, :type => 'Task'
30
30
31 %br/
31 %br/
32
32
33 - if @last_test_request
33 - if @last_test_request
34 Last test_request:
34 Last test_request:
35 = link_to "#{@last_test_request.id}", :action => 'view', :id => @last_test_request.id, :type => 'TestRequest'
35 = link_to "#{@last_test_request.id}", :action => 'view', :id => @last_test_request.id, :type => 'TestRequest'
36
36
37
37
38 %h2 Current graders
38 %h2 Current graders
39
39
40 = render :partial => 'grader_list', :locals => {:grader_list => @grader_processes}
40 = render :partial => 'grader_list', :locals => {:grader_list => @grader_processes}
41
41
42 %h2 Stalled graders
42 %h2 Stalled graders
43
43
44 = render :partial => 'grader_list', :locals => {:grader_list => @stalled_processes}
44 = render :partial => 'grader_list', :locals => {:grader_list => @stalled_processes}
45
45
46 %h2 Terminated graders
46 %h2 Terminated graders
47
47
48 - = form_for :clear, nil, :url => {:action => 'clear_terminated'} do |f|
48 + = form_for :clear, :url => {:action => 'clear_terminated'} do |f|
49 = submit_tag 'Clear data for terminated graders'
49 = submit_tag 'Clear data for terminated graders'
50
50
51 = render :partial => 'grader_list', :locals => {:grader_list => @terminated_processes}
51 = render :partial => 'grader_list', :locals => {:grader_list => @terminated_processes}
@@ -1,15 +1,15
1 - content_for :head do
1 - content_for :head do
2 - = javascript_include_tag :defaults
2 + = javascript_include_tag "effects"
3 - = javascript_include_tag 'announcement_refresh.js'
3 + = javascript_include_tag "announcement_refresh"
4
4
5 = user_title_bar(@user)
5 = user_title_bar(@user)
6
6
7 .announcementbox{:style => (@announcements.length==0 ? "display:none" : "")}
7 .announcementbox{:style => (@announcements.length==0 ? "display:none" : "")}
8 %span{:class => 'title'}
8 %span{:class => 'title'}
9 Announcements
9 Announcements
10 #announcementbox-body
10 #announcementbox-body
11 = render :partial => 'announcement', :collection => @announcements
11 = render :partial => 'announcement', :collection => @announcements
12
12
13 - if GraderConfiguration.show_submitbox_to?(@user)
13 - if GraderConfiguration.show_submitbox_to?(@user)
14 .submitbox
14 .submitbox
15 = error_messages_for 'submission'
15 = error_messages_for 'submission'
@@ -5,22 +5,22
5 How to submit clarification requests
5 How to submit clarification requests
6 .announcement
6 .announcement
7 %p
7 %p
8 :markdown
8 :markdown
9 The clarification requests should be phrased as yes/no questions.
9 The clarification requests should be phrased as yes/no questions.
10 The answers will be one of the following:
10 The answers will be one of the following:
11 (1) **YES**,
11 (1) **YES**,
12 (2) <b>NO</b>,
12 (2) <b>NO</b>,
13 (3) **ANSWERED IN TASK DESCRIPTION (EXPLICITLY OR IMPLICITLY)**,
13 (3) **ANSWERED IN TASK DESCRIPTION (EXPLICITLY OR IMPLICITLY)**,
14 (4) **INVALID QUESTION**, and
14 (4) **INVALID QUESTION**, and
15 (5) **NO COMMENT**.
15 (5) **NO COMMENT**.
16
16
17 - = form_for 'message', nil, :url => { :action => 'create'} do |f|
17 + = form_for 'message', :url => { :action => 'create'} do |f|
18 %p
18 %p
19 %b New clarification request
19 %b New clarification request
20 = submit_tag "Post"
20 = submit_tag "Post"
21 %br/
21 %br/
22 = f.text_area :body, :rows => 5, :cols => 100
22 = f.text_area :body, :rows => 5, :cols => 100
23
23
24 %hr/
24 %hr/
25
25
26 = render :partial => 'message', :collection => @messages, :locals => {:reply => false}
26 = render :partial => 'message', :collection => @messages, :locals => {:reply => false}
@@ -1,15 +1,14
1 - content_for :head do
1 - content_for :head do
2 = stylesheet_link_tag 'problems'
2 = stylesheet_link_tag 'problems'
3 - = javascript_include_tag :defaults
4
3
5 %h1 Import problems: successful
4 %h1 Import problems: successful
6
5
7 %p
6 %p
8 %b Problem:
7 %b Problem:
9 = "#{@problem.full_name} (#{@problem.name})"
8 = "#{@problem.full_name} (#{@problem.name})"
10 %br/
9 %br/
11 Note that the full score has be assigned to the default value, 100.
10 Note that the full score has be assigned to the default value, 100.
12 You should change it to the correct full score.
11 You should change it to the correct full score.
13
12
14 %p
13 %p
15 = link_to '[Back to problem list]', :action => 'list'
14 = link_to '[Back to problem list]', :action => 'list'
@@ -1,15 +1,14
1 - content_for :head do
1 - content_for :head do
2 = stylesheet_link_tag 'problems'
2 = stylesheet_link_tag 'problems'
3 - = javascript_include_tag :defaults
4
3
5 %h1 Import problems
4 %h1 Import problems
6
5
7 %p= link_to '[Back to problem list]', :action => 'list'
6 %p= link_to '[Back to problem list]', :action => 'list'
8
7
9 - if @problem and @problem.errors
8 - if @problem and @problem.errors
10 =error_messages_for 'problem'
9 =error_messages_for 'problem'
11
10
12 = form_tag({:action => 'do_import'}, :multipart => true) do
11 = form_tag({:action => 'do_import'}, :multipart => true) do
13 .submitbox
12 .submitbox
14 %table
13 %table
15 %tr
14 %tr
@@ -1,15 +1,14
1 <% content_for :head do %>
1 <% content_for :head do %>
2 <%= stylesheet_link_tag 'problems' %>
2 <%= stylesheet_link_tag 'problems' %>
3 - <%= javascript_include_tag :defaults %>
4 <% end %>
3 <% end %>
5
4
6 <h1>Listing problems</h1>
5 <h1>Listing problems</h1>
7
6
8 <p>
7 <p>
9 <%= link_to '[New problem]', :action => 'new' %>
8 <%= link_to '[New problem]', :action => 'new' %>
10 <%= link_to '[Manage problems]', :action => 'manage' %>
9 <%= link_to '[Manage problems]', :action => 'manage' %>
11 <%= link_to '[Import problems]', :action => 'import' %>
10 <%= link_to '[Import problems]', :action => 'import' %>
12 <%= link_to '[Turn off all problems]', :action => 'turn_all_off' %>
11 <%= link_to '[Turn off all problems]', :action => 'turn_all_off' %>
13 <%= link_to '[Turn on all problems]', :action => 'turn_all_on' %>
12 <%= link_to '[Turn on all problems]', :action => 'turn_all_on' %>
14 </p>
13 </p>
15
14
@@ -44,24 +43,24
44 <td><%= in_place_editor_field :problem, :full_name, {}, :rows=>1 %></td>
43 <td><%= in_place_editor_field :problem, :full_name, {}, :rows=>1 %></td>
45 <td><%= in_place_editor_field :problem, :full_score, {}, :rows=>1 %></td>
44 <td><%= in_place_editor_field :problem, :full_score, {}, :rows=>1 %></td>
46 <td><%= problem.date_added %></td>
45 <td><%= problem.date_added %></td>
47 <td id="prob-<%= problem.id %>-avail"><%= problem.available %></td>
46 <td id="prob-<%= problem.id %>-avail"><%= problem.available %></td>
48 <td><%= problem.test_allowed %></td>
47 <td><%= problem.test_allowed %></td>
49
48
50 <% if GraderConfiguration.multicontests? %>
49 <% if GraderConfiguration.multicontests? %>
51 <td>
50 <td>
52 <%= problem.contests.collect { |c| c.name }.join(', ') %>
51 <%= problem.contests.collect { |c| c.name }.join(', ') %>
53 </td>
52 </td>
54 <% end %>
53 <% end %>
55
54
56 - <td><%= link_to_remote '[Toggle]', :url => {:action => 'toggle', :id => problem.id } %></td>
55 + <td><%= link_to '[Toggle]', {:action => 'toggle', :id => problem.id }, :remote => true %></td>
57 <td><%= link_to '[Stat]', :action => 'stat', :id => problem.id %></td>
56 <td><%= link_to '[Stat]', :action => 'stat', :id => problem.id %></td>
58 <td><%= link_to '[Show]', :action => 'show', :id => problem %></td>
57 <td><%= link_to '[Show]', :action => 'show', :id => problem %></td>
59 <td><%= link_to '[Edit]', :action => 'edit', :id => problem %></td>
58 <td><%= link_to '[Edit]', :action => 'edit', :id => problem %></td>
60 <td><%= link_to '[Destroy]', { :action => 'destroy', :id => problem }, :confirm => 'Are you sure?', :method => :post %></td>
59 <td><%= link_to '[Destroy]', { :action => 'destroy', :id => problem }, :confirm => 'Are you sure?', :method => :post %></td>
61 </tr>
60 </tr>
62 <% end %>
61 <% end %>
63 </table>
62 </table>
64
63
65 <br />
64 <br />
66
65
67 <%= link_to '[New problem]', :action => 'new' %>
66 <%= link_to '[New problem]', :action => 'new' %>
@@ -1,15 +1,14
1 - content_for :head do
1 - content_for :head do
2 = stylesheet_link_tag 'problems'
2 = stylesheet_link_tag 'problems'
3 - = javascript_include_tag :defaults
4
3
5 %h1 Manage problems
4 %h1 Manage problems
6
5
7 %p= link_to '[Back to problem list]', :action => 'list'
6 %p= link_to '[Back to problem list]', :action => 'list'
8
7
9 = form_tag :action=>'do_manage' do
8 = form_tag :action=>'do_manage' do
10 .submitbox
9 .submitbox
11 What do you want to do?
10 What do you want to do?
12 %br/
11 %br/
13 %ul
12 %ul
14 %li
13 %li
15 Change date added to
14 Change date added to
@@ -31,25 +31,25
31 try {
31 try {
32 submissionSelect.add(new Option(""+i,""+i,false,false),null);
32 submissionSelect.add(new Option(""+i,""+i,false,false),null);
33 } catch(ex) {
33 } catch(ex) {
34 submissionSelect.add(new Option(""+i,""+i,false,false));
34 submissionSelect.add(new Option(""+i,""+i,false,false));
35 }
35 }
36 }
36 }
37 }
37 }
38 </script>
38 </script>
39
39
40 <% if GraderConfiguration.show_submitbox_to?(@user) and GraderConfiguration.allow_test_request(@user) %>
40 <% if GraderConfiguration.show_submitbox_to?(@user) and GraderConfiguration.allow_test_request(@user) %>
41 <div class="submitbox">
41 <div class="submitbox">
42 <%= error_messages_for 'submitted_test_request' %>
42 <%= error_messages_for 'submitted_test_request' %>
43 - <%= form_for :test_request, nil,
43 + <%= form_for :test_request,
44 :url => { :action => 'submit'},
44 :url => { :action => 'submit'},
45 :html => { :multipart => true } do |f| %>
45 :html => { :multipart => true } do |f| %>
46 <table>
46 <table>
47 <tr>
47 <tr>
48 <td>Task:</td>
48 <td>Task:</td>
49 <td>
49 <td>
50 <%= select(:test_request,
50 <%= select(:test_request,
51 :problem_id,
51 :problem_id,
52 @problems.collect {|p| [p.name, p.id]}, {},
52 @problems.collect {|p| [p.name, p.id]}, {},
53 { :onclick => "updateSubmissionList();" }) %>
53 { :onclick => "updateSubmissionList();" }) %>
54 </td>
54 </td>
55 </tr>
55 </tr>
@@ -1,15 +1,12
1 - - content_for :head do
2 - = javascript_include_tag :defaults
3 -
4 = user_title_bar(@user)
1 = user_title_bar(@user)
5
2
6 %h1 Your account settings
3 %h1 Your account settings
7
4
8 -#%p
5 -#%p
9 -#You can edit your alias and e-mails. Just click on the text and edit it.
6 -#You can edit your alias and e-mails. Just click on the text and edit it.
10
7
11 %table.uinfo
8 %table.uinfo
12 %tr
9 %tr
13 %th.uinfo Login
10 %th.uinfo Login
14 %td.uinfo= @user.login
11 %td.uinfo= @user.login
15 %tr
12 %tr
@@ -45,18 +45,18
45 # Use SQL instead of Active Record's schema dumper when creating the database.
45 # Use SQL instead of Active Record's schema dumper when creating the database.
46 # This is necessary if your schema can't be completely dumped by the schema dumper,
46 # This is necessary if your schema can't be completely dumped by the schema dumper,
47 # like if you have constraints or database-specific column types
47 # like if you have constraints or database-specific column types
48 # config.active_record.schema_format = :sql
48 # config.active_record.schema_format = :sql
49
49
50 # Enforce whitelist mode for mass assignment.
50 # Enforce whitelist mode for mass assignment.
51 # This will create an empty whitelist of attributes available for mass-assignment for all models
51 # This will create an empty whitelist of attributes available for mass-assignment for all models
52 # in your app. As such, your models will need to explicitly whitelist or blacklist accessible
52 # in your app. As such, your models will need to explicitly whitelist or blacklist accessible
53 # parameters by using an attr_accessible or attr_protected declaration.
53 # parameters by using an attr_accessible or attr_protected declaration.
54 config.active_record.whitelist_attributes = false
54 config.active_record.whitelist_attributes = false
55
55
56 # Enable the asset pipeline
56 # Enable the asset pipeline
57 - config.assets.enabled = false
57 + config.assets.enabled = true
58
58
59 # Version of your assets, change this if you want to expire all your assets
59 # Version of your assets, change this if you want to expire all your assets
60 config.assets.version = '1.0'
60 config.assets.version = '1.0'
61 end
61 end
62 end
62 end
@@ -1,41 +0,0
1 -
2 - var Announcement = {
3 -
4 - mostRecentId: 0,
5 -
6 - refreshUrl: '/main/announcements',
7 -
8 - setMostRecentId: function(id) {
9 - Announcement.mostRecentId = id;
10 - },
11 -
12 - updateRecentId: function(id) {
13 - if(Announcement.mostRecentId < id)
14 - Announcement.mostRecentId = id;
15 - },
16 -
17 - refreshAnnouncement: function() {
18 - var url = Announcement.refreshUrl;
19 - new Ajax.Request(url, {
20 - method: 'get',
21 - parameters: { recent: Announcement.mostRecentId },
22 - onSuccess: function(transport) {
23 - if((transport.status == 200) &&
24 - (transport.responseText.match(/\S/)!=null)) {
25 - var announcementBody = $("announcementbox-body");
26 - announcementBody.insert({ top: transport.responseText });
27 - var announcementBoxes = $$(".announcementbox");
28 - if(announcementBoxes.length!=0)
29 - announcementBoxes[0].show();
30 - Announcement.registerRefreshEventTimer();
31 - }
32 - }
33 - });
34 - },
35 -
36 - registerRefreshEventTimer: function() {
37 - setTimeout(function () {
38 - Announcement.refreshAnnouncement();
39 - }, 30000);
40 - }
41 - };
@@ -1,2 +0,0
1 - // Place your application-specific JavaScript functions and classes here
2 - // This file is automatically included by javascript_include_tag :defaults
This diff has been collapsed as it changes many lines, (963 lines changed) Show them Hide them
@@ -1,963 +0,0
1 - // Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
2 - // (c) 2005-2008 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
3 - // (c) 2005-2008 Jon Tirsen (http://www.tirsen.com)
4 - // Contributors:
5 - // Richard Livsey
6 - // Rahul Bhargava
7 - // Rob Wills
8 - //
9 - // script.aculo.us is freely distributable under the terms of an MIT-style license.
10 - // For details, see the script.aculo.us web site: http://script.aculo.us/
11 -
12 - // Autocompleter.Base handles all the autocompletion functionality
13 - // that's independent of the data source for autocompletion. This
14 - // includes drawing the autocompletion menu, observing keyboard
15 - // and mouse events, and similar.
16 - //
17 - // Specific autocompleters need to provide, at the very least,
18 - // a getUpdatedChoices function that will be invoked every time
19 - // the text inside the monitored textbox changes. This method
20 - // should get the text for which to provide autocompletion by
21 - // invoking this.getToken(), NOT by directly accessing
22 - // this.element.value. This is to allow incremental tokenized
23 - // autocompletion. Specific auto-completion logic (AJAX, etc)
24 - // belongs in getUpdatedChoices.
25 - //
26 - // Tokenized incremental autocompletion is enabled automatically
27 - // when an autocompleter is instantiated with the 'tokens' option
28 - // in the options parameter, e.g.:
29 - // new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
30 - // will incrementally autocomplete with a comma as the token.
31 - // Additionally, ',' in the above example can be replaced with
32 - // a token array, e.g. { tokens: [',', '\n'] } which
33 - // enables autocompletion on multiple tokens. This is most
34 - // useful when one of the tokens is \n (a newline), as it
35 - // allows smart autocompletion after linebreaks.
36 -
37 - if(typeof Effect == 'undefined')
38 - throw("controls.js requires including script.aculo.us' effects.js library");
39 -
40 - var Autocompleter = { };
41 - Autocompleter.Base = Class.create({
42 - baseInitialize: function(element, update, options) {
43 - element = $(element);
44 - this.element = element;
45 - this.update = $(update);
46 - this.hasFocus = false;
47 - this.changed = false;
48 - this.active = false;
49 - this.index = 0;
50 - this.entryCount = 0;
51 - this.oldElementValue = this.element.value;
52 -
53 - if(this.setOptions)
54 - this.setOptions(options);
55 - else
56 - this.options = options || { };
57 -
58 - this.options.paramName = this.options.paramName || this.element.name;
59 - this.options.tokens = this.options.tokens || [];
60 - this.options.frequency = this.options.frequency || 0.4;
61 - this.options.minChars = this.options.minChars || 1;
62 - this.options.onShow = this.options.onShow ||
63 - function(element, update){
64 - if(!update.style.position || update.style.position=='absolute') {
65 - update.style.position = 'absolute';
66 - Position.clone(element, update, {
67 - setHeight: false,
68 - offsetTop: element.offsetHeight
69 - });
70 - }
71 - Effect.Appear(update,{duration:0.15});
72 - };
73 - this.options.onHide = this.options.onHide ||
74 - function(element, update){ new Effect.Fade(update,{duration:0.15}) };
75 -
76 - if(typeof(this.options.tokens) == 'string')
77 - this.options.tokens = new Array(this.options.tokens);
78 - // Force carriage returns as token delimiters anyway
79 - if (!this.options.tokens.include('\n'))
80 - this.options.tokens.push('\n');
81 -
82 - this.observer = null;
83 -
84 - this.element.setAttribute('autocomplete','off');
85 -
86 - Element.hide(this.update);
87 -
88 - Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
89 - Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this));
90 - },
91 -
92 - show: function() {
93 - if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
94 - if(!this.iefix &&
95 - (Prototype.Browser.IE) &&
96 - (Element.getStyle(this.update, 'position')=='absolute')) {
97 - new Insertion.After(this.update,
98 - '<iframe id="' + this.update.id + '_iefix" '+
99 - 'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
100 - 'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
101 - this.iefix = $(this.update.id+'_iefix');
102 - }
103 - if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
104 - },
105 -
106 - fixIEOverlapping: function() {
107 - Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
108 - this.iefix.style.zIndex = 1;
109 - this.update.style.zIndex = 2;
110 - Element.show(this.iefix);
111 - },
112 -
113 - hide: function() {
114 - this.stopIndicator();
115 - if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
116 - if(this.iefix) Element.hide(this.iefix);
117 - },
118 -
119 - startIndicator: function() {
120 - if(this.options.indicator) Element.show(this.options.indicator);
121 - },
122 -
123 - stopIndicator: function() {
124 - if(this.options.indicator) Element.hide(this.options.indicator);
125 - },
126 -
127 - onKeyPress: function(event) {
128 - if(this.active)
129 - switch(event.keyCode) {
130 - case Event.KEY_TAB:
131 - case Event.KEY_RETURN:
132 - this.selectEntry();
133 - Event.stop(event);
134 - case Event.KEY_ESC:
135 - this.hide();
136 - this.active = false;
137 - Event.stop(event);
138 - return;
139 - case Event.KEY_LEFT:
140 - case Event.KEY_RIGHT:
141 - return;
142 - case Event.KEY_UP:
143 - this.markPrevious();
144 - this.render();
145 - Event.stop(event);
146 - return;
147 - case Event.KEY_DOWN:
148 - this.markNext();
149 - this.render();
150 - Event.stop(event);
151 - return;
152 - }
153 - else
154 - if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
155 - (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;
156 -
157 - this.changed = true;
158 - this.hasFocus = true;
159 -
160 - if(this.observer) clearTimeout(this.observer);
161 - this.observer =
162 - setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
163 - },
164 -
165 - activate: function() {
166 - this.changed = false;
167 - this.hasFocus = true;
168 - this.getUpdatedChoices();
169 - },
170 -
171 - onHover: function(event) {
172 - var element = Event.findElement(event, 'LI');
173 - if(this.index != element.autocompleteIndex)
174 - {
175 - this.index = element.autocompleteIndex;
176 - this.render();
177 - }
178 - Event.stop(event);
179 - },
180 -
181 - onClick: function(event) {
182 - var element = Event.findElement(event, 'LI');
183 - this.index = element.autocompleteIndex;
184 - this.selectEntry();
185 - this.hide();
186 - },
187 -
188 - onBlur: function(event) {
189 - // needed to make click events working
190 - setTimeout(this.hide.bind(this), 250);
191 - this.hasFocus = false;
192 - this.active = false;
193 - },
194 -
195 - render: function() {
196 - if(this.entryCount > 0) {
197 - for (var i = 0; i < this.entryCount; i++)
198 - this.index==i ?
199 - Element.addClassName(this.getEntry(i),"selected") :
200 - Element.removeClassName(this.getEntry(i),"selected");
201 - if(this.hasFocus) {
202 - this.show();
203 - this.active = true;
204 - }
205 - } else {
206 - this.active = false;
207 - this.hide();
208 - }
209 - },
210 -
211 - markPrevious: function() {
212 - if(this.index > 0) this.index--;
213 - else this.index = this.entryCount-1;
214 - this.getEntry(this.index).scrollIntoView(true);
215 - },
216 -
217 - markNext: function() {
218 - if(this.index < this.entryCount-1) this.index++;
219 - else this.index = 0;
220 - this.getEntry(this.index).scrollIntoView(false);
221 - },
222 -
223 - getEntry: function(index) {
224 - return this.update.firstChild.childNodes[index];
225 - },
226 -
227 - getCurrentEntry: function() {
228 - return this.getEntry(this.index);
229 - },
230 -
231 - selectEntry: function() {
232 - this.active = false;
233 - this.updateElement(this.getCurrentEntry());
234 - },
235 -
236 - updateElement: function(selectedElement) {
237 - if (this.options.updateElement) {
238 - this.options.updateElement(selectedElement);
239 - return;
240 - }
241 - var value = '';
242 - if (this.options.select) {
243 - var nodes = $(selectedElement).select('.' + this.options.select) || [];
244 - if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
245 - } else
246 - value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
247 -
248 - var bounds = this.getTokenBounds();
249 - if (bounds[0] != -1) {
250 - var newValue = this.element.value.substr(0, bounds[0]);
251 - var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/);
252 - if (whitespace)
253 - newValue += whitespace[0];
254 - this.element.value = newValue + value + this.element.value.substr(bounds[1]);
255 - } else {
256 - this.element.value = value;
257 - }
258 - this.oldElementValue = this.element.value;
259 - this.element.focus();
260 -
261 - if (this.options.afterUpdateElement)
262 - this.options.afterUpdateElement(this.element, selectedElement);
263 - },
264 -
265 - updateChoices: function(choices) {
266 - if(!this.changed && this.hasFocus) {
267 - this.update.innerHTML = choices;
268 - Element.cleanWhitespace(this.update);
269 - Element.cleanWhitespace(this.update.down());
270 -
271 - if(this.update.firstChild && this.update.down().childNodes) {
272 - this.entryCount =
273 - this.update.down().childNodes.length;
274 - for (var i = 0; i < this.entryCount; i++) {
275 - var entry = this.getEntry(i);
276 - entry.autocompleteIndex = i;
277 - this.addObservers(entry);
278 - }
279 - } else {
280 - this.entryCount = 0;
281 - }
282 -
283 - this.stopIndicator();
284 - this.index = 0;
285 -
286 - if(this.entryCount==1 && this.options.autoSelect) {
287 - this.selectEntry();
288 - this.hide();
289 - } else {
290 - this.render();
291 - }
292 - }
293 - },
294 -
295 - addObservers: function(element) {
296 - Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
297 - Event.observe(element, "click", this.onClick.bindAsEventListener(this));
298 - },
299 -
300 - onObserverEvent: function() {
301 - this.changed = false;
302 - this.tokenBounds = null;
303 - if(this.getToken().length>=this.options.minChars) {
304 - this.getUpdatedChoices();
305 - } else {
306 - this.active = false;
307 - this.hide();
308 - }
309 - this.oldElementValue = this.element.value;
310 - },
311 -
312 - getToken: function() {
313 - var bounds = this.getTokenBounds();
314 - return this.element.value.substring(bounds[0], bounds[1]).strip();
315 - },
316 -
317 - getTokenBounds: function() {
318 - if (null != this.tokenBounds) return this.tokenBounds;
319 - var value = this.element.value;
320 - if (value.strip().empty()) return [-1, 0];
321 - var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue);
322 - var offset = (diff == this.oldElementValue.length ? 1 : 0);
323 - var prevTokenPos = -1, nextTokenPos = value.length;
324 - var tp;
325 - for (var index = 0, l = this.options.tokens.length; index < l; ++index) {
326 - tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1);
327 - if (tp > prevTokenPos) prevTokenPos = tp;
328 - tp = value.indexOf(this.options.tokens[index], diff + offset);
329 - if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp;
330 - }
331 - return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]);
332 - }
333 - });
334 -
335 - Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) {
336 - var boundary = Math.min(newS.length, oldS.length);
337 - for (var index = 0; index < boundary; ++index)
338 - if (newS[index] != oldS[index])
339 - return index;
340 - return boundary;
341 - };
342 -
343 - Ajax.Autocompleter = Class.create(Autocompleter.Base, {
344 - initialize: function(element, update, url, options) {
345 - this.baseInitialize(element, update, options);
346 - this.options.asynchronous = true;
347 - this.options.onComplete = this.onComplete.bind(this);
348 - this.options.defaultParams = this.options.parameters || null;
349 - this.url = url;
350 - },
351 -
352 - getUpdatedChoices: function() {
353 - this.startIndicator();
354 -
355 - var entry = encodeURIComponent(this.options.paramName) + '=' +
356 - encodeURIComponent(this.getToken());
357 -
358 - this.options.parameters = this.options.callback ?
359 - this.options.callback(this.element, entry) : entry;
360 -
361 - if(this.options.defaultParams)
362 - this.options.parameters += '&' + this.options.defaultParams;
363 -
364 - new Ajax.Request(this.url, this.options);
365 - },
366 -
367 - onComplete: function(request) {
368 - this.updateChoices(request.responseText);
369 - }
370 - });
371 -
372 - // The local array autocompleter. Used when you'd prefer to
373 - // inject an array of autocompletion options into the page, rather
374 - // than sending out Ajax queries, which can be quite slow sometimes.
375 - //
376 - // The constructor takes four parameters. The first two are, as usual,
377 - // the id of the monitored textbox, and id of the autocompletion menu.
378 - // The third is the array you want to autocomplete from, and the fourth
379 - // is the options block.
380 - //
381 - // Extra local autocompletion options:
382 - // - choices - How many autocompletion choices to offer
383 - //
384 - // - partialSearch - If false, the autocompleter will match entered
385 - // text only at the beginning of strings in the
386 - // autocomplete array. Defaults to true, which will
387 - // match text at the beginning of any *word* in the
388 - // strings in the autocomplete array. If you want to
389 - // search anywhere in the string, additionally set
390 - // the option fullSearch to true (default: off).
391 - //
392 - // - fullSsearch - Search anywhere in autocomplete array strings.
393 - //
394 - // - partialChars - How many characters to enter before triggering
395 - // a partial match (unlike minChars, which defines
396 - // how many characters are required to do any match
397 - // at all). Defaults to 2.
398 - //
399 - // - ignoreCase - Whether to ignore case when autocompleting.
400 - // Defaults to true.
401 - //
402 - // It's possible to pass in a custom function as the 'selector'
403 - // option, if you prefer to write your own autocompletion logic.
404 - // In that case, the other options above will not apply unless
405 - // you support them.
406 -
407 - Autocompleter.Local = Class.create(Autocompleter.Base, {
408 - initialize: function(element, update, array, options) {
409 - this.baseInitialize(element, update, options);
410 - this.options.array = array;
411 - },
412 -
413 - getUpdatedChoices: function() {
414 - this.updateChoices(this.options.selector(this));
415 - },
416 -
417 - setOptions: function(options) {
418 - this.options = Object.extend({
419 - choices: 10,
420 - partialSearch: true,
421 - partialChars: 2,
422 - ignoreCase: true,
423 - fullSearch: false,
424 - selector: function(instance) {
425 - var ret = []; // Beginning matches
426 - var partial = []; // Inside matches
427 - var entry = instance.getToken();
428 - var count = 0;
429 -
430 - for (var i = 0; i < instance.options.array.length &&
431 - ret.length < instance.options.choices ; i++) {
432 -
433 - var elem = instance.options.array[i];
434 - var foundPos = instance.options.ignoreCase ?
435 - elem.toLowerCase().indexOf(entry.toLowerCase()) :
436 - elem.indexOf(entry);
437 -
438 - while (foundPos != -1) {
439 - if (foundPos == 0 && elem.length != entry.length) {
440 - ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
441 - elem.substr(entry.length) + "</li>");
442 - break;
443 - } else if (entry.length >= instance.options.partialChars &&
444 - instance.options.partialSearch && foundPos != -1) {
445 - if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
446 - partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
447 - elem.substr(foundPos, entry.length) + "</strong>" + elem.substr(
448 - foundPos + entry.length) + "</li>");
449 - break;
450 - }
451 - }
452 -
453 - foundPos = instance.options.ignoreCase ?
454 - elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
455 - elem.indexOf(entry, foundPos + 1);
456 -
457 - }
458 - }
459 - if (partial.length)
460 - ret = ret.concat(partial.slice(0, instance.options.choices - ret.length));
461 - return "<ul>" + ret.join('') + "</ul>";
462 - }
463 - }, options || { });
464 - }
465 - });
466 -
467 - // AJAX in-place editor and collection editor
468 - // Full rewrite by Christophe Porteneuve <tdd@tddsworld.com> (April 2007).
469 -
470 - // Use this if you notice weird scrolling problems on some browsers,
471 - // the DOM might be a bit confused when this gets called so do this
472 - // waits 1 ms (with setTimeout) until it does the activation
473 - Field.scrollFreeActivate = function(field) {
474 - setTimeout(function() {
475 - Field.activate(field);
476 - }, 1);
477 - };
478 -
479 - Ajax.InPlaceEditor = Class.create({
480 - initialize: function(element, url, options) {
481 - this.url = url;
482 - this.element = element = $(element);
483 - this.prepareOptions();
484 - this._controls = { };
485 - arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!!
486 - Object.extend(this.options, options || { });
487 - if (!this.options.formId && this.element.id) {
488 - this.options.formId = this.element.id + '-inplaceeditor';
489 - if ($(this.options.formId))
490 - this.options.formId = '';
491 - }
492 - if (this.options.externalControl)
493 - this.options.externalControl = $(this.options.externalControl);
494 - if (!this.options.externalControl)
495 - this.options.externalControlOnly = false;
496 - this._originalBackground = this.element.getStyle('background-color') || 'transparent';
497 - this.element.title = this.options.clickToEditText;
498 - this._boundCancelHandler = this.handleFormCancellation.bind(this);
499 - this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this);
500 - this._boundFailureHandler = this.handleAJAXFailure.bind(this);
501 - this._boundSubmitHandler = this.handleFormSubmission.bind(this);
502 - this._boundWrapperHandler = this.wrapUp.bind(this);
503 - this.registerListeners();
504 - },
505 - checkForEscapeOrReturn: function(e) {
506 - if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return;
507 - if (Event.KEY_ESC == e.keyCode)
508 - this.handleFormCancellation(e);
509 - else if (Event.KEY_RETURN == e.keyCode)
510 - this.handleFormSubmission(e);
511 - },
512 - createControl: function(mode, handler, extraClasses) {
513 - var control = this.options[mode + 'Control'];
514 - var text = this.options[mode + 'Text'];
515 - if ('button' == control) {
516 - var btn = document.createElement('input');
517 - btn.type = 'submit';
518 - btn.value = text;
519 - btn.className = 'editor_' + mode + '_button';
520 - if ('cancel' == mode)
521 - btn.onclick = this._boundCancelHandler;
522 - this._form.appendChild(btn);
523 - this._controls[mode] = btn;
524 - } else if ('link' == control) {
525 - var link = document.createElement('a');
526 - link.href = '#';
527 - link.appendChild(document.createTextNode(text));
528 - link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler;
529 - link.className = 'editor_' + mode + '_link';
530 - if (extraClasses)
531 - link.className += ' ' + extraClasses;
532 - this._form.appendChild(link);
533 - this._controls[mode] = link;
534 - }
535 - },
536 - createEditField: function() {
537 - var text = (this.options.loadTextURL ? this.options.loadingText : this.getText());
538 - var fld;
539 - if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) {
540 - fld = document.createElement('input');
541 - fld.type = 'text';
542 - var size = this.options.size || this.options.cols || 0;
543 - if (0 < size) fld.size = size;
544 - } else {
545 - fld = document.createElement('textarea');
546 - fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows);
547 - fld.cols = this.options.cols || 40;
548 - }
549 - fld.name = this.options.paramName;
550 - fld.value = text; // No HTML breaks conversion anymore
551 - fld.className = 'editor_field';
552 - if (this.options.submitOnBlur)
553 - fld.onblur = this._boundSubmitHandler;
554 - this._controls.editor = fld;
555 - if (this.options.loadTextURL)
556 - this.loadExternalText();
557 - this._form.appendChild(this._controls.editor);
558 - },
559 - createForm: function() {
560 - var ipe = this;
561 - function addText(mode, condition) {
562 - var text = ipe.options['text' + mode + 'Controls'];
563 - if (!text || condition === false) return;
564 - ipe._form.appendChild(document.createTextNode(text));
565 - };
566 - this._form = $(document.createElement('form'));
567 - this._form.id = this.options.formId;
568 - this._form.addClassName(this.options.formClassName);
569 - this._form.onsubmit = this._boundSubmitHandler;
570 - this.createEditField();
571 - if ('textarea' == this._controls.editor.tagName.toLowerCase())
572 - this._form.appendChild(document.createElement('br'));
573 - if (this.options.onFormCustomization)
574 - this.options.onFormCustomization(this, this._form);
575 - addText('Before', this.options.okControl || this.options.cancelControl);
576 - this.createControl('ok', this._boundSubmitHandler);
577 - addText('Between', this.options.okControl && this.options.cancelControl);
578 - this.createControl('cancel', this._boundCancelHandler, 'editor_cancel');
579 - addText('After', this.options.okControl || this.options.cancelControl);
580 - },
581 - destroy: function() {
582 - if (this._oldInnerHTML)
583 - this.element.innerHTML = this._oldInnerHTML;
584 - this.leaveEditMode();
585 - this.unregisterListeners();
586 - },
587 - enterEditMode: function(e) {
588 - if (this._saving || this._editing) return;
589 - this._editing = true;
590 - this.triggerCallback('onEnterEditMode');
591 - if (this.options.externalControl)
592 - this.options.externalControl.hide();
593 - this.element.hide();
594 - this.createForm();
595 - this.element.parentNode.insertBefore(this._form, this.element);
596 - if (!this.options.loadTextURL)
597 - this.postProcessEditField();
598 - if (e) Event.stop(e);
599 - },
600 - enterHover: function(e) {
601 - if (this.options.hoverClassName)
602 - this.element.addClassName(this.options.hoverClassName);
603 - if (this._saving) return;
604 - this.triggerCallback('onEnterHover');
605 - },
606 - getText: function() {
607 - return this.element.innerHTML.unescapeHTML();
608 - },
609 - handleAJAXFailure: function(transport) {
610 - this.triggerCallback('onFailure', transport);
611 - if (this._oldInnerHTML) {
612 - this.element.innerHTML = this._oldInnerHTML;
613 - this._oldInnerHTML = null;
614 - }
615 - },
616 - handleFormCancellation: function(e) {
617 - this.wrapUp();
618 - if (e) Event.stop(e);
619 - },
620 - handleFormSubmission: function(e) {
621 - var form = this._form;
622 - var value = $F(this._controls.editor);
623 - this.prepareSubmission();
624 - var params = this.options.callback(form, value) || '';
625 - if (Object.isString(params))
626 - params = params.toQueryParams();
627 - params.editorId = this.element.id;
628 - if (this.options.htmlResponse) {
629 - var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions);
630 - Object.extend(options, {
631 - parameters: params,
632 - onComplete: this._boundWrapperHandler,
633 - onFailure: this._boundFailureHandler
634 - });
635 - new Ajax.Updater({ success: this.element }, this.url, options);
636 - } else {
637 - var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
638 - Object.extend(options, {
639 - parameters: params,
640 - onComplete: this._boundWrapperHandler,
641 - onFailure: this._boundFailureHandler
642 - });
643 - new Ajax.Request(this.url, options);
644 - }
645 - if (e) Event.stop(e);
646 - },
647 - leaveEditMode: function() {
648 - this.element.removeClassName(this.options.savingClassName);
649 - this.removeForm();
650 - this.leaveHover();
651 - this.element.style.backgroundColor = this._originalBackground;
652 - this.element.show();
653 - if (this.options.externalControl)
654 - this.options.externalControl.show();
655 - this._saving = false;
656 - this._editing = false;
657 - this._oldInnerHTML = null;
658 - this.triggerCallback('onLeaveEditMode');
659 - },
660 - leaveHover: function(e) {
661 - if (this.options.hoverClassName)
662 - this.element.removeClassName(this.options.hoverClassName);
663 - if (this._saving) return;
664 - this.triggerCallback('onLeaveHover');
665 - },
666 - loadExternalText: function() {
667 - this._form.addClassName(this.options.loadingClassName);
668 - this._controls.editor.disabled = true;
669 - var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
670 - Object.extend(options, {
671 - parameters: 'editorId=' + encodeURIComponent(this.element.id),
672 - onComplete: Prototype.emptyFunction,
673 - onSuccess: function(transport) {
674 - this._form.removeClassName(this.options.loadingClassName);
675 - var text = transport.responseText;
676 - if (this.options.stripLoadedTextTags)
677 - text = text.stripTags();
678 - this._controls.editor.value = text;
679 - this._controls.editor.disabled = false;
680 - this.postProcessEditField();
681 - }.bind(this),
682 - onFailure: this._boundFailureHandler
683 - });
684 - new Ajax.Request(this.options.loadTextURL, options);
685 - },
686 - postProcessEditField: function() {
687 - var fpc = this.options.fieldPostCreation;
688 - if (fpc)
689 - $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate']();
690 - },
691 - prepareOptions: function() {
692 - this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions);
693 - Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks);
694 - [this._extraDefaultOptions].flatten().compact().each(function(defs) {
695 - Object.extend(this.options, defs);
696 - }.bind(this));
697 - },
698 - prepareSubmission: function() {
699 - this._saving = true;
700 - this.removeForm();
701 - this.leaveHover();
702 - this.showSaving();
703 - },
704 - registerListeners: function() {
705 - this._listeners = { };
706 - var listener;
707 - $H(Ajax.InPlaceEditor.Listeners).each(function(pair) {
708 - listener = this[pair.value].bind(this);
709 - this._listeners[pair.key] = listener;
710 - if (!this.options.externalControlOnly)
711 - this.element.observe(pair.key, listener);
712 - if (this.options.externalControl)
713 - this.options.externalControl.observe(pair.key, listener);
714 - }.bind(this));
715 - },
716 - removeForm: function() {
717 - if (!this._form) return;
718 - this._form.remove();
719 - this._form = null;
720 - this._controls = { };
721 - },
722 - showSaving: function() {
723 - this._oldInnerHTML = this.element.innerHTML;
724 - this.element.innerHTML = this.options.savingText;
725 - this.element.addClassName(this.options.savingClassName);
726 - this.element.style.backgroundColor = this._originalBackground;
727 - this.element.show();
728 - },
729 - triggerCallback: function(cbName, arg) {
730 - if ('function' == typeof this.options[cbName]) {
731 - this.options[cbName](this, arg);
732 - }
733 - },
734 - unregisterListeners: function() {
735 - $H(this._listeners).each(function(pair) {
736 - if (!this.options.externalControlOnly)
737 - this.element.stopObserving(pair.key, pair.value);
738 - if (this.options.externalControl)
739 - this.options.externalControl.stopObserving(pair.key, pair.value);
740 - }.bind(this));
741 - },
742 - wrapUp: function(transport) {
743 - this.leaveEditMode();
744 - // Can't use triggerCallback due to backward compatibility: requires
745 - // binding + direct element
746 - this._boundComplete(transport, this.element);
747 - }
748 - });
749 -
750 - Object.extend(Ajax.InPlaceEditor.prototype, {
751 - dispose: Ajax.InPlaceEditor.prototype.destroy
752 - });
753 -
754 - Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, {
755 - initialize: function($super, element, url, options) {
756 - this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions;
757 - $super(element, url, options);
758 - },
759 -
760 - createEditField: function() {
761 - var list = document.createElement('select');
762 - list.name = this.options.paramName;
763 - list.size = 1;
764 - this._controls.editor = list;
765 - this._collection = this.options.collection || [];
766 - if (this.options.loadCollectionURL)
767 - this.loadCollection();
768 - else
769 - this.checkForExternalText();
770 - this._form.appendChild(this._controls.editor);
771 - },
772 -
773 - loadCollection: function() {
774 - this._form.addClassName(this.options.loadingClassName);
775 - this.showLoadingText(this.options.loadingCollectionText);
776 - var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
777 - Object.extend(options, {
778 - parameters: 'editorId=' + encodeURIComponent(this.element.id),
779 - onComplete: Prototype.emptyFunction,
780 - onSuccess: function(transport) {
781 - var js = transport.responseText.strip();
782 - if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check
783 - throw('Server returned an invalid collection representation.');
784 - this._collection = eval(js);
785 - this.checkForExternalText();
786 - }.bind(this),
787 - onFailure: this.onFailure
788 - });
789 - new Ajax.Request(this.options.loadCollectionURL, options);
790 - },
791 -
792 - showLoadingText: function(text) {
793 - this._controls.editor.disabled = true;
794 - var tempOption = this._controls.editor.firstChild;
795 - if (!tempOption) {
796 - tempOption = document.createElement('option');
797 - tempOption.value = '';
798 - this._controls.editor.appendChild(tempOption);
799 - tempOption.selected = true;
800 - }
801 - tempOption.update((text || '').stripScripts().stripTags());
802 - },
803 -
804 - checkForExternalText: function() {
805 - this._text = this.getText();
806 - if (this.options.loadTextURL)
807 - this.loadExternalText();
808 - else
809 - this.buildOptionList();
810 - },
811 -
812 - loadExternalText: function() {
813 - this.showLoadingText(this.options.loadingText);
814 - var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
815 - Object.extend(options, {
816 - parameters: 'editorId=' + encodeURIComponent(this.element.id),
817 - onComplete: Prototype.emptyFunction,
818 - onSuccess: function(transport) {
819 - this._text = transport.responseText.strip();
820 - this.buildOptionList();
821 - }.bind(this),
822 - onFailure: this.onFailure
823 - });
824 - new Ajax.Request(this.options.loadTextURL, options);
825 - },
826 -
827 - buildOptionList: function() {
828 - this._form.removeClassName(this.options.loadingClassName);
829 - this._collection = this._collection.map(function(entry) {
830 - return 2 === entry.length ? entry : [entry, entry].flatten();
831 - });
832 - var marker = ('value' in this.options) ? this.options.value : this._text;
833 - var textFound = this._collection.any(function(entry) {
834 - return entry[0] == marker;
835 - }.bind(this));
836 - this._controls.editor.update('');
837 - var option;
838 - this._collection.each(function(entry, index) {
839 - option = document.createElement('option');
840 - option.value = entry[0];
841 - option.selected = textFound ? entry[0] == marker : 0 == index;
842 - option.appendChild(document.createTextNode(entry[1]));
843 - this._controls.editor.appendChild(option);
844 - }.bind(this));
845 - this._controls.editor.disabled = false;
846 - Field.scrollFreeActivate(this._controls.editor);
847 - }
848 - });
849 -
850 - //**** DEPRECATION LAYER FOR InPlace[Collection]Editor! ****
851 - //**** This only exists for a while, in order to let ****
852 - //**** users adapt to the new API. Read up on the new ****
853 - //**** API and convert your code to it ASAP! ****
854 -
855 - Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) {
856 - if (!options) return;
857 - function fallback(name, expr) {
858 - if (name in options || expr === undefined) return;
859 - options[name] = expr;
860 - };
861 - fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' :
862 - options.cancelLink == options.cancelButton == false ? false : undefined)));
863 - fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' :
864 - options.okLink == options.okButton == false ? false : undefined)));
865 - fallback('highlightColor', options.highlightcolor);
866 - fallback('highlightEndColor', options.highlightendcolor);
867 - };
868 -
869 - Object.extend(Ajax.InPlaceEditor, {
870 - DefaultOptions: {
871 - ajaxOptions: { },
872 - autoRows: 3, // Use when multi-line w/ rows == 1
873 - cancelControl: 'link', // 'link'|'button'|false
874 - cancelText: 'cancel',
875 - clickToEditText: 'Click to edit',
876 - externalControl: null, // id|elt
877 - externalControlOnly: false,
878 - fieldPostCreation: 'activate', // 'activate'|'focus'|false
879 - formClassName: 'inplaceeditor-form',
880 - formId: null, // id|elt
881 - highlightColor: '#ffff99',
882 - highlightEndColor: '#ffffff',
883 - hoverClassName: '',
884 - htmlResponse: true,
885 - loadingClassName: 'inplaceeditor-loading',
886 - loadingText: 'Loading...',
887 - okControl: 'button', // 'link'|'button'|false
888 - okText: 'ok',
889 - paramName: 'value',
890 - rows: 1, // If 1 and multi-line, uses autoRows
891 - savingClassName: 'inplaceeditor-saving',
892 - savingText: 'Saving...',
893 - size: 0,
894 - stripLoadedTextTags: false,
895 - submitOnBlur: false,
896 - textAfterControls: '',
897 - textBeforeControls: '',
898 - textBetweenControls: ''
899 - },
900 - DefaultCallbacks: {
901 - callback: function(form) {
902 - return Form.serialize(form);
903 - },
904 - onComplete: function(transport, element) {
905 - // For backward compatibility, this one is bound to the IPE, and passes
906 - // the element directly. It was too often customized, so we don't break it.
907 - new Effect.Highlight(element, {
908 - startcolor: this.options.highlightColor, keepBackgroundImage: true });
909 - },
910 - onEnterEditMode: null,
911 - onEnterHover: function(ipe) {
912 - ipe.element.style.backgroundColor = ipe.options.highlightColor;
913 - if (ipe._effect)
914 - ipe._effect.cancel();
915 - },
916 - onFailure: function(transport, ipe) {
917 - alert('Error communication with the server: ' + transport.responseText.stripTags());
918 - },
919 - onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls.
920 - onLeaveEditMode: null,
921 - onLeaveHover: function(ipe) {
922 - ipe._effect = new Effect.Highlight(ipe.element, {
923 - startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor,
924 - restorecolor: ipe._originalBackground, keepBackgroundImage: true
925 - });
926 - }
927 - },
928 - Listeners: {
929 - click: 'enterEditMode',
930 - keydown: 'checkForEscapeOrReturn',
931 - mouseover: 'enterHover',
932 - mouseout: 'leaveHover'
933 - }
934 - });
935 -
936 - Ajax.InPlaceCollectionEditor.DefaultOptions = {
937 - loadingCollectionText: 'Loading options...'
938 - };
939 -
940 - // Delayed observer, like Form.Element.Observer,
941 - // but waits for delay after last key input
942 - // Ideal for live-search fields
943 -
944 - Form.Element.DelayedObserver = Class.create({
945 - initialize: function(element, delay, callback) {
946 - this.delay = delay || 0.5;
947 - this.element = $(element);
948 - this.callback = callback;
949 - this.timer = null;
950 - this.lastValue = $F(this.element);
951 - Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
952 - },
953 - delayedListener: function(event) {
954 - if(this.lastValue == $F(this.element)) return;
955 - if(this.timer) clearTimeout(this.timer);
956 - this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
957 - this.lastValue = $F(this.element);
958 - },
959 - onTimerEvent: function() {
960 - this.timer = null;
961 - this.callback(this.element, $F(this.element));
962 - }
963 - }); No newline at end of file
This diff has been collapsed as it changes many lines, (973 lines changed) Show them Hide them
@@ -1,973 +0,0
1 - // Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
2 - // (c) 2005-2008 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
3 - //
4 - // script.aculo.us is freely distributable under the terms of an MIT-style license.
5 - // For details, see the script.aculo.us web site: http://script.aculo.us/
6 -
7 - if(Object.isUndefined(Effect))
8 - throw("dragdrop.js requires including script.aculo.us' effects.js library");
9 -
10 - var Droppables = {
11 - drops: [],
12 -
13 - remove: function(element) {
14 - this.drops = this.drops.reject(function(d) { return d.element==$(element) });
15 - },
16 -
17 - add: function(element) {
18 - element = $(element);
19 - var options = Object.extend({
20 - greedy: true,
21 - hoverclass: null,
22 - tree: false
23 - }, arguments[1] || { });
24 -
25 - // cache containers
26 - if(options.containment) {
27 - options._containers = [];
28 - var containment = options.containment;
29 - if(Object.isArray(containment)) {
30 - containment.each( function(c) { options._containers.push($(c)) });
31 - } else {
32 - options._containers.push($(containment));
33 - }
34 - }
35 -
36 - if(options.accept) options.accept = [options.accept].flatten();
37 -
38 - Element.makePositioned(element); // fix IE
39 - options.element = element;
40 -
41 - this.drops.push(options);
42 - },
43 -
44 - findDeepestChild: function(drops) {
45 - deepest = drops[0];
46 -
47 - for (i = 1; i < drops.length; ++i)
48 - if (Element.isParent(drops[i].element, deepest.element))
49 - deepest = drops[i];
50 -
51 - return deepest;
52 - },
53 -
54 - isContained: function(element, drop) {
55 - var containmentNode;
56 - if(drop.tree) {
57 - containmentNode = element.treeNode;
58 - } else {
59 - containmentNode = element.parentNode;
60 - }
61 - return drop._containers.detect(function(c) { return containmentNode == c });
62 - },
63 -
64 - isAffected: function(point, element, drop) {
65 - return (
66 - (drop.element!=element) &&
67 - ((!drop._containers) ||
68 - this.isContained(element, drop)) &&
69 - ((!drop.accept) ||
70 - (Element.classNames(element).detect(
71 - function(v) { return drop.accept.include(v) } ) )) &&
72 - Position.within(drop.element, point[0], point[1]) );
73 - },
74 -
75 - deactivate: function(drop) {
76 - if(drop.hoverclass)
77 - Element.removeClassName(drop.element, drop.hoverclass);
78 - this.last_active = null;
79 - },
80 -
81 - activate: function(drop) {
82 - if(drop.hoverclass)
83 - Element.addClassName(drop.element, drop.hoverclass);
84 - this.last_active = drop;
85 - },
86 -
87 - show: function(point, element) {
88 - if(!this.drops.length) return;
89 - var drop, affected = [];
90 -
91 - this.drops.each( function(drop) {
92 - if(Droppables.isAffected(point, element, drop))
93 - affected.push(drop);
94 - });
95 -
96 - if(affected.length>0)
97 - drop = Droppables.findDeepestChild(affected);
98 -
99 - if(this.last_active && this.last_active != drop) this.deactivate(this.last_active);
100 - if (drop) {
101 - Position.within(drop.element, point[0], point[1]);
102 - if(drop.onHover)
103 - drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
104 -
105 - if (drop != this.last_active) Droppables.activate(drop);
106 - }
107 - },
108 -
109 - fire: function(event, element) {
110 - if(!this.last_active) return;
111 - Position.prepare();
112 -
113 - if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
114 - if (this.last_active.onDrop) {
115 - this.last_active.onDrop(element, this.last_active.element, event);
116 - return true;
117 - }
118 - },
119 -
120 - reset: function() {
121 - if(this.last_active)
122 - this.deactivate(this.last_active);
123 - }
124 - };
125 -
126 - var Draggables = {
127 - drags: [],
128 - observers: [],
129 -
130 - register: function(draggable) {
131 - if(this.drags.length == 0) {
132 - this.eventMouseUp = this.endDrag.bindAsEventListener(this);
133 - this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
134 - this.eventKeypress = this.keyPress.bindAsEventListener(this);
135 -
136 - Event.observe(document, "mouseup", this.eventMouseUp);
137 - Event.observe(document, "mousemove", this.eventMouseMove);
138 - Event.observe(document, "keypress", this.eventKeypress);
139 - }
140 - this.drags.push(draggable);
141 - },
142 -
143 - unregister: function(draggable) {
144 - this.drags = this.drags.reject(function(d) { return d==draggable });
145 - if(this.drags.length == 0) {
146 - Event.stopObserving(document, "mouseup", this.eventMouseUp);
147 - Event.stopObserving(document, "mousemove", this.eventMouseMove);
148 - Event.stopObserving(document, "keypress", this.eventKeypress);
149 - }
150 - },
151 -
152 - activate: function(draggable) {
153 - if(draggable.options.delay) {
154 - this._timeout = setTimeout(function() {
155 - Draggables._timeout = null;
156 - window.focus();
157 - Draggables.activeDraggable = draggable;
158 - }.bind(this), draggable.options.delay);
159 - } else {
160 - window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
161 - this.activeDraggable = draggable;
162 - }
163 - },
164 -
165 - deactivate: function() {
166 - this.activeDraggable = null;
167 - },
168 -
169 - updateDrag: function(event) {
170 - if(!this.activeDraggable) return;
171 - var pointer = [Event.pointerX(event), Event.pointerY(event)];
172 - // Mozilla-based browsers fire successive mousemove events with
173 - // the same coordinates, prevent needless redrawing (moz bug?)
174 - if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
175 - this._lastPointer = pointer;
176 -
177 - this.activeDraggable.updateDrag(event, pointer);
178 - },
179 -
180 - endDrag: function(event) {
181 - if(this._timeout) {
182 - clearTimeout(this._timeout);
183 - this._timeout = null;
184 - }
185 - if(!this.activeDraggable) return;
186 - this._lastPointer = null;
187 - this.activeDraggable.endDrag(event);
188 - this.activeDraggable = null;
189 - },
190 -
191 - keyPress: function(event) {
192 - if(this.activeDraggable)
193 - this.activeDraggable.keyPress(event);
194 - },
195 -
196 - addObserver: function(observer) {
197 - this.observers.push(observer);
198 - this._cacheObserverCallbacks();
199 - },
200 -
201 - removeObserver: function(element) { // element instead of observer fixes mem leaks
202 - this.observers = this.observers.reject( function(o) { return o.element==element });
203 - this._cacheObserverCallbacks();
204 - },
205 -
206 - notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag'
207 - if(this[eventName+'Count'] > 0)
208 - this.observers.each( function(o) {
209 - if(o[eventName]) o[eventName](eventName, draggable, event);
210 - });
211 - if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
212 - },
213 -
214 - _cacheObserverCallbacks: function() {
215 - ['onStart','onEnd','onDrag'].each( function(eventName) {
216 - Draggables[eventName+'Count'] = Draggables.observers.select(
217 - function(o) { return o[eventName]; }
218 - ).length;
219 - });
220 - }
221 - };
222 -
223 - /*--------------------------------------------------------------------------*/
224 -
225 - var Draggable = Class.create({
226 - initialize: function(element) {
227 - var defaults = {
228 - handle: false,
229 - reverteffect: function(element, top_offset, left_offset) {
230 - var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
231 - new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
232 - queue: {scope:'_draggable', position:'end'}
233 - });
234 - },
235 - endeffect: function(element) {
236 - var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0;
237 - new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
238 - queue: {scope:'_draggable', position:'end'},
239 - afterFinish: function(){
240 - Draggable._dragging[element] = false
241 - }
242 - });
243 - },
244 - zindex: 1000,
245 - revert: false,
246 - quiet: false,
247 - scroll: false,
248 - scrollSensitivity: 20,
249 - scrollSpeed: 15,
250 - snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] }
251 - delay: 0
252 - };
253 -
254 - if(!arguments[1] || Object.isUndefined(arguments[1].endeffect))
255 - Object.extend(defaults, {
256 - starteffect: function(element) {
257 - element._opacity = Element.getOpacity(element);
258 - Draggable._dragging[element] = true;
259 - new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});
260 - }
261 - });
262 -
263 - var options = Object.extend(defaults, arguments[1] || { });
264 -
265 - this.element = $(element);
266 -
267 - if(options.handle && Object.isString(options.handle))
268 - this.handle = this.element.down('.'+options.handle, 0);
269 -
270 - if(!this.handle) this.handle = $(options.handle);
271 - if(!this.handle) this.handle = this.element;
272 -
273 - if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
274 - options.scroll = $(options.scroll);
275 - this._isScrollChild = Element.childOf(this.element, options.scroll);
276 - }
277 -
278 - Element.makePositioned(this.element); // fix IE
279 -
280 - this.options = options;
281 - this.dragging = false;
282 -
283 - this.eventMouseDown = this.initDrag.bindAsEventListener(this);
284 - Event.observe(this.handle, "mousedown", this.eventMouseDown);
285 -
286 - Draggables.register(this);
287 - },
288 -
289 - destroy: function() {
290 - Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
291 - Draggables.unregister(this);
292 - },
293 -
294 - currentDelta: function() {
295 - return([
296 - parseInt(Element.getStyle(this.element,'left') || '0'),
297 - parseInt(Element.getStyle(this.element,'top') || '0')]);
298 - },
299 -
300 - initDrag: function(event) {
301 - if(!Object.isUndefined(Draggable._dragging[this.element]) &&
302 - Draggable._dragging[this.element]) return;
303 - if(Event.isLeftClick(event)) {
304 - // abort on form elements, fixes a Firefox issue
305 - var src = Event.element(event);
306 - if((tag_name = src.tagName.toUpperCase()) && (
307 - tag_name=='INPUT' ||
308 - tag_name=='SELECT' ||
309 - tag_name=='OPTION' ||
310 - tag_name=='BUTTON' ||
311 - tag_name=='TEXTAREA')) return;
312 -
313 - var pointer = [Event.pointerX(event), Event.pointerY(event)];
314 - var pos = Position.cumulativeOffset(this.element);
315 - this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
316 -
317 - Draggables.activate(this);
318 - Event.stop(event);
319 - }
320 - },
321 -
322 - startDrag: function(event) {
323 - this.dragging = true;
324 - if(!this.delta)
325 - this.delta = this.currentDelta();
326 -
327 - if(this.options.zindex) {
328 - this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
329 - this.element.style.zIndex = this.options.zindex;
330 - }
331 -
332 - if(this.options.ghosting) {
333 - this._clone = this.element.cloneNode(true);
334 - this._originallyAbsolute = (this.element.getStyle('position') == 'absolute');
335 - if (!this._originallyAbsolute)
336 - Position.absolutize(this.element);
337 - this.element.parentNode.insertBefore(this._clone, this.element);
338 - }
339 -
340 - if(this.options.scroll) {
341 - if (this.options.scroll == window) {
342 - var where = this._getWindowScroll(this.options.scroll);
343 - this.originalScrollLeft = where.left;
344 - this.originalScrollTop = where.top;
345 - } else {
346 - this.originalScrollLeft = this.options.scroll.scrollLeft;
347 - this.originalScrollTop = this.options.scroll.scrollTop;
348 - }
349 - }
350 -
351 - Draggables.notify('onStart', this, event);
352 -
353 - if(this.options.starteffect) this.options.starteffect(this.element);
354 - },
355 -
356 - updateDrag: function(event, pointer) {
357 - if(!this.dragging) this.startDrag(event);
358 -
359 - if(!this.options.quiet){
360 - Position.prepare();
361 - Droppables.show(pointer, this.element);
362 - }
363 -
364 - Draggables.notify('onDrag', this, event);
365 -
366 - this.draw(pointer);
367 - if(this.options.change) this.options.change(this);
368 -
369 - if(this.options.scroll) {
370 - this.stopScrolling();
371 -
372 - var p;
373 - if (this.options.scroll == window) {
374 - with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
375 - } else {
376 - p = Position.page(this.options.scroll);
377 - p[0] += this.options.scroll.scrollLeft + Position.deltaX;
378 - p[1] += this.options.scroll.scrollTop + Position.deltaY;
379 - p.push(p[0]+this.options.scroll.offsetWidth);
380 - p.push(p[1]+this.options.scroll.offsetHeight);
381 - }
382 - var speed = [0,0];
383 - if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
384 - if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
385 - if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
386 - if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
387 - this.startScrolling(speed);
388 - }
389 -
390 - // fix AppleWebKit rendering
391 - if(Prototype.Browser.WebKit) window.scrollBy(0,0);
392 -
393 - Event.stop(event);
394 - },
395 -
396 - finishDrag: function(event, success) {
397 - this.dragging = false;
398 -
399 - if(this.options.quiet){
400 - Position.prepare();
401 - var pointer = [Event.pointerX(event), Event.pointerY(event)];
402 - Droppables.show(pointer, this.element);
403 - }
404 -
405 - if(this.options.ghosting) {
406 - if (!this._originallyAbsolute)
407 - Position.relativize(this.element);
408 - delete this._originallyAbsolute;
409 - Element.remove(this._clone);
410 - this._clone = null;
411 - }
412 -
413 - var dropped = false;
414 - if(success) {
415 - dropped = Droppables.fire(event, this.element);
416 - if (!dropped) dropped = false;
417 - }
418 - if(dropped && this.options.onDropped) this.options.onDropped(this.element);
419 - Draggables.notify('onEnd', this, event);
420 -
421 - var revert = this.options.revert;
422 - if(revert && Object.isFunction(revert)) revert = revert(this.element);
423 -
424 - var d = this.currentDelta();
425 - if(revert && this.options.reverteffect) {
426 - if (dropped == 0 || revert != 'failure')
427 - this.options.reverteffect(this.element,
428 - d[1]-this.delta[1], d[0]-this.delta[0]);
429 - } else {
430 - this.delta = d;
431 - }
432 -
433 - if(this.options.zindex)
434 - this.element.style.zIndex = this.originalZ;
435 -
436 - if(this.options.endeffect)
437 - this.options.endeffect(this.element);
438 -
439 - Draggables.deactivate(this);
440 - Droppables.reset();
441 - },
442 -
443 - keyPress: function(event) {
444 - if(event.keyCode!=Event.KEY_ESC) return;
445 - this.finishDrag(event, false);
446 - Event.stop(event);
447 - },
448 -
449 - endDrag: function(event) {
450 - if(!this.dragging) return;
451 - this.stopScrolling();
452 - this.finishDrag(event, true);
453 - Event.stop(event);
454 - },
455 -
456 - draw: function(point) {
457 - var pos = Position.cumulativeOffset(this.element);
458 - if(this.options.ghosting) {
459 - var r = Position.realOffset(this.element);
460 - pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
461 - }
462 -
463 - var d = this.currentDelta();
464 - pos[0] -= d[0]; pos[1] -= d[1];
465 -
466 - if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
467 - pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
468 - pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
469 - }
470 -
471 - var p = [0,1].map(function(i){
472 - return (point[i]-pos[i]-this.offset[i])
473 - }.bind(this));
474 -
475 - if(this.options.snap) {
476 - if(Object.isFunction(this.options.snap)) {
477 - p = this.options.snap(p[0],p[1],this);
478 - } else {
479 - if(Object.isArray(this.options.snap)) {
480 - p = p.map( function(v, i) {
481 - return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this));
482 - } else {
483 - p = p.map( function(v) {
484 - return (v/this.options.snap).round()*this.options.snap }.bind(this));
485 - }
486 - }}
487 -
488 - var style = this.element.style;
489 - if((!this.options.constraint) || (this.options.constraint=='horizontal'))
490 - style.left = p[0] + "px";
491 - if((!this.options.constraint) || (this.options.constraint=='vertical'))
492 - style.top = p[1] + "px";
493 -
494 - if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
495 - },
496 -
497 - stopScrolling: function() {
498 - if(this.scrollInterval) {
499 - clearInterval(this.scrollInterval);
500 - this.scrollInterval = null;
501 - Draggables._lastScrollPointer = null;
502 - }
503 - },
504 -
505 - startScrolling: function(speed) {
506 - if(!(speed[0] || speed[1])) return;
507 - this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
508 - this.lastScrolled = new Date();
509 - this.scrollInterval = setInterval(this.scroll.bind(this), 10);
510 - },
511 -
512 - scroll: function() {
513 - var current = new Date();
514 - var delta = current - this.lastScrolled;
515 - this.lastScrolled = current;
516 - if(this.options.scroll == window) {
517 - with (this._getWindowScroll(this.options.scroll)) {
518 - if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
519 - var d = delta / 1000;
520 - this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );
521 - }
522 - }
523 - } else {
524 - this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
525 - this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000;
526 - }
527 -
528 - Position.prepare();
529 - Droppables.show(Draggables._lastPointer, this.element);
530 - Draggables.notify('onDrag', this);
531 - if (this._isScrollChild) {
532 - Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
533 - Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
534 - Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
535 - if (Draggables._lastScrollPointer[0] < 0)
536 - Draggables._lastScrollPointer[0] = 0;
537 - if (Draggables._lastScrollPointer[1] < 0)
538 - Draggables._lastScrollPointer[1] = 0;
539 - this.draw(Draggables._lastScrollPointer);
540 - }
541 -
542 - if(this.options.change) this.options.change(this);
543 - },
544 -
545 - _getWindowScroll: function(w) {
546 - var T, L, W, H;
547 - with (w.document) {
548 - if (w.document.documentElement && documentElement.scrollTop) {
549 - T = documentElement.scrollTop;
550 - L = documentElement.scrollLeft;
551 - } else if (w.document.body) {
552 - T = body.scrollTop;
553 - L = body.scrollLeft;
554 - }
555 - if (w.innerWidth) {
556 - W = w.innerWidth;
557 - H = w.innerHeight;
558 - } else if (w.document.documentElement && documentElement.clientWidth) {
559 - W = documentElement.clientWidth;
560 - H = documentElement.clientHeight;
561 - } else {
562 - W = body.offsetWidth;
563 - H = body.offsetHeight;
564 - }
565 - }
566 - return { top: T, left: L, width: W, height: H };
567 - }
568 - });
569 -
570 - Draggable._dragging = { };
571 -
572 - /*--------------------------------------------------------------------------*/
573 -
574 - var SortableObserver = Class.create({
575 - initialize: function(element, observer) {
576 - this.element = $(element);
577 - this.observer = observer;
578 - this.lastValue = Sortable.serialize(this.element);
579 - },
580 -
581 - onStart: function() {
582 - this.lastValue = Sortable.serialize(this.element);
583 - },
584 -
585 - onEnd: function() {
586 - Sortable.unmark();
587 - if(this.lastValue != Sortable.serialize(this.element))
588 - this.observer(this.element)
589 - }
590 - });
591 -
592 - var Sortable = {
593 - SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
594 -
595 - sortables: { },
596 -
597 - _findRootElement: function(element) {
598 - while (element.tagName.toUpperCase() != "BODY") {
599 - if(element.id && Sortable.sortables[element.id]) return element;
600 - element = element.parentNode;
601 - }
602 - },
603 -
604 - options: function(element) {
605 - element = Sortable._findRootElement($(element));
606 - if(!element) return;
607 - return Sortable.sortables[element.id];
608 - },
609 -
610 - destroy: function(element){
611 - element = $(element);
612 - var s = Sortable.sortables[element.id];
613 -
614 - if(s) {
615 - Draggables.removeObserver(s.element);
616 - s.droppables.each(function(d){ Droppables.remove(d) });
617 - s.draggables.invoke('destroy');
618 -
619 - delete Sortable.sortables[s.element.id];
620 - }
621 - },
622 -
623 - create: function(element) {
624 - element = $(element);
625 - var options = Object.extend({
626 - element: element,
627 - tag: 'li', // assumes li children, override with tag: 'tagname'
628 - dropOnEmpty: false,
629 - tree: false,
630 - treeTag: 'ul',
631 - overlap: 'vertical', // one of 'vertical', 'horizontal'
632 - constraint: 'vertical', // one of 'vertical', 'horizontal', false
633 - containment: element, // also takes array of elements (or id's); or false
634 - handle: false, // or a CSS class
635 - only: false,
636 - delay: 0,
637 - hoverclass: null,
638 - ghosting: false,
639 - quiet: false,
640 - scroll: false,
641 - scrollSensitivity: 20,
642 - scrollSpeed: 15,
643 - format: this.SERIALIZE_RULE,
644 -
645 - // these take arrays of elements or ids and can be
646 - // used for better initialization performance
647 - elements: false,
648 - handles: false,
649 -
650 - onChange: Prototype.emptyFunction,
651 - onUpdate: Prototype.emptyFunction
652 - }, arguments[1] || { });
653 -
654 - // clear any old sortable with same element
655 - this.destroy(element);
656 -
657 - // build options for the draggables
658 - var options_for_draggable = {
659 - revert: true,
660 - quiet: options.quiet,
661 - scroll: options.scroll,
662 - scrollSpeed: options.scrollSpeed,
663 - scrollSensitivity: options.scrollSensitivity,
664 - delay: options.delay,
665 - ghosting: options.ghosting,
666 - constraint: options.constraint,
667 - handle: options.handle };
668 -
669 - if(options.starteffect)
670 - options_for_draggable.starteffect = options.starteffect;
671 -
672 - if(options.reverteffect)
673 - options_for_draggable.reverteffect = options.reverteffect;
674 - else
675 - if(options.ghosting) options_for_draggable.reverteffect = function(element) {
676 - element.style.top = 0;
677 - element.style.left = 0;
678 - };
679 -
680 - if(options.endeffect)
681 - options_for_draggable.endeffect = options.endeffect;
682 -
683 - if(options.zindex)
684 - options_for_draggable.zindex = options.zindex;
685 -
686 - // build options for the droppables
687 - var options_for_droppable = {
688 - overlap: options.overlap,
689 - containment: options.containment,
690 - tree: options.tree,
691 - hoverclass: options.hoverclass,
692 - onHover: Sortable.onHover
693 - };
694 -
695 - var options_for_tree = {
696 - onHover: Sortable.onEmptyHover,
697 - overlap: options.overlap,
698 - containment: options.containment,
699 - hoverclass: options.hoverclass
700 - };
701 -
702 - // fix for gecko engine
703 - Element.cleanWhitespace(element);
704 -
705 - options.draggables = [];
706 - options.droppables = [];
707 -
708 - // drop on empty handling
709 - if(options.dropOnEmpty || options.tree) {
710 - Droppables.add(element, options_for_tree);
711 - options.droppables.push(element);
712 - }
713 -
714 - (options.elements || this.findElements(element, options) || []).each( function(e,i) {
715 - var handle = options.handles ? $(options.handles[i]) :
716 - (options.handle ? $(e).select('.' + options.handle)[0] : e);
717 - options.draggables.push(
718 - new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
719 - Droppables.add(e, options_for_droppable);
720 - if(options.tree) e.treeNode = element;
721 - options.droppables.push(e);
722 - });
723 -
724 - if(options.tree) {
725 - (Sortable.findTreeElements(element, options) || []).each( function(e) {
726 - Droppables.add(e, options_for_tree);
727 - e.treeNode = element;
728 - options.droppables.push(e);
729 - });
730 - }
731 -
732 - // keep reference
733 - this.sortables[element.id] = options;
734 -
735 - // for onupdate
736 - Draggables.addObserver(new SortableObserver(element, options.onUpdate));
737 -
738 - },
739 -
740 - // return all suitable-for-sortable elements in a guaranteed order
741 - findElements: function(element, options) {
742 - return Element.findChildren(
743 - element, options.only, options.tree ? true : false, options.tag);
744 - },
745 -
746 - findTreeElements: function(element, options) {
747 - return Element.findChildren(
748 - element, options.only, options.tree ? true : false, options.treeTag);
749 - },
750 -
751 - onHover: function(element, dropon, overlap) {
752 - if(Element.isParent(dropon, element)) return;
753 -
754 - if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
755 - return;
756 - } else if(overlap>0.5) {
757 - Sortable.mark(dropon, 'before');
758 - if(dropon.previousSibling != element) {
759 - var oldParentNode = element.parentNode;
760 - element.style.visibility = "hidden"; // fix gecko rendering
761 - dropon.parentNode.insertBefore(element, dropon);
762 - if(dropon.parentNode!=oldParentNode)
763 - Sortable.options(oldParentNode).onChange(element);
764 - Sortable.options(dropon.parentNode).onChange(element);
765 - }
766 - } else {
767 - Sortable.mark(dropon, 'after');
768 - var nextElement = dropon.nextSibling || null;
769 - if(nextElement != element) {
770 - var oldParentNode = element.parentNode;
771 - element.style.visibility = "hidden"; // fix gecko rendering
772 - dropon.parentNode.insertBefore(element, nextElement);
773 - if(dropon.parentNode!=oldParentNode)
774 - Sortable.options(oldParentNode).onChange(element);
775 - Sortable.options(dropon.parentNode).onChange(element);
776 - }
777 - }
778 - },
779 -
780 - onEmptyHover: function(element, dropon, overlap) {
781 - var oldParentNode = element.parentNode;
782 - var droponOptions = Sortable.options(dropon);
783 -
784 - if(!Element.isParent(dropon, element)) {
785 - var index;
786 -
787 - var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});
788 - var child = null;
789 -
790 - if(children) {
791 - var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
792 -
793 - for (index = 0; index < children.length; index += 1) {
794 - if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
795 - offset -= Element.offsetSize (children[index], droponOptions.overlap);
796 - } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
797 - child = index + 1 < children.length ? children[index + 1] : null;
798 - break;
799 - } else {
800 - child = children[index];
801 - break;
802 - }
803 - }
804 - }
805 -
806 - dropon.insertBefore(element, child);
807 -
808 - Sortable.options(oldParentNode).onChange(element);
809 - droponOptions.onChange(element);
810 - }
811 - },
812 -
813 - unmark: function() {
814 - if(Sortable._marker) Sortable._marker.hide();
815 - },
816 -
817 - mark: function(dropon, position) {
818 - // mark on ghosting only
819 - var sortable = Sortable.options(dropon.parentNode);
820 - if(sortable && !sortable.ghosting) return;
821 -
822 - if(!Sortable._marker) {
823 - Sortable._marker =
824 - ($('dropmarker') || Element.extend(document.createElement('DIV'))).
825 - hide().addClassName('dropmarker').setStyle({position:'absolute'});
826 - document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
827 - }
828 - var offsets = Position.cumulativeOffset(dropon);
829 - Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});
830 -
831 - if(position=='after')
832 - if(sortable.overlap == 'horizontal')
833 - Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
834 - else
835 - Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});
836 -
837 - Sortable._marker.show();
838 - },
839 -
840 - _tree: function(element, options, parent) {
841 - var children = Sortable.findElements(element, options) || [];
842 -
843 - for (var i = 0; i < children.length; ++i) {
844 - var match = children[i].id.match(options.format);
845 -
846 - if (!match) continue;
847 -
848 - var child = {
849 - id: encodeURIComponent(match ? match[1] : null),
850 - element: element,
851 - parent: parent,
852 - children: [],
853 - position: parent.children.length,
854 - container: $(children[i]).down(options.treeTag)
855 - };
856 -
857 - /* Get the element containing the children and recurse over it */
858 - if (child.container)
859 - this._tree(child.container, options, child);
860 -
861 - parent.children.push (child);
862 - }
863 -
864 - return parent;
865 - },
866 -
867 - tree: function(element) {
868 - element = $(element);
869 - var sortableOptions = this.options(element);
870 - var options = Object.extend({
871 - tag: sortableOptions.tag,
872 - treeTag: sortableOptions.treeTag,
873 - only: sortableOptions.only,
874 - name: element.id,
875 - format: sortableOptions.format
876 - }, arguments[1] || { });
877 -
878 - var root = {
879 - id: null,
880 - parent: null,
881 - children: [],
882 - container: element,
883 - position: 0
884 - };
885 -
886 - return Sortable._tree(element, options, root);
887 - },
888 -
889 - /* Construct a [i] index for a particular node */
890 - _constructIndex: function(node) {
891 - var index = '';
892 - do {
893 - if (node.id) index = '[' + node.position + ']' + index;
894 - } while ((node = node.parent) != null);
895 - return index;
896 - },
897 -
898 - sequence: function(element) {
899 - element = $(element);
900 - var options = Object.extend(this.options(element), arguments[1] || { });
901 -
902 - return $(this.findElements(element, options) || []).map( function(item) {
903 - return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
904 - });
905 - },
906 -
907 - setSequence: function(element, new_sequence) {
908 - element = $(element);
909 - var options = Object.extend(this.options(element), arguments[2] || { });
910 -
911 - var nodeMap = { };
912 - this.findElements(element, options).each( function(n) {
913 - if (n.id.match(options.format))
914 - nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
915 - n.parentNode.removeChild(n);
916 - });
917 -
918 - new_sequence.each(function(ident) {
919 - var n = nodeMap[ident];
920 - if (n) {
921 - n[1].appendChild(n[0]);
922 - delete nodeMap[ident];
923 - }
924 - });
925 - },
926 -
927 - serialize: function(element) {
928 - element = $(element);
929 - var options = Object.extend(Sortable.options(element), arguments[1] || { });
930 - var name = encodeURIComponent(
931 - (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
932 -
933 - if (options.tree) {
934 - return Sortable.tree(element, arguments[1]).children.map( function (item) {
935 - return [name + Sortable._constructIndex(item) + "[id]=" +
936 - encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
937 - }).flatten().join('&');
938 - } else {
939 - return Sortable.sequence(element, arguments[1]).map( function(item) {
940 - return name + "[]=" + encodeURIComponent(item);
941 - }).join('&');
942 - }
943 - }
944 - };
945 -
946 - // Returns true if child is contained within element
947 - Element.isParent = function(child, element) {
948 - if (!child.parentNode || child == element) return false;
949 - if (child.parentNode == element) return true;
950 - return Element.isParent(child.parentNode, element);
951 - };
952 -
953 - Element.findChildren = function(element, only, recursive, tagName) {
954 - if(!element.hasChildNodes()) return null;
955 - tagName = tagName.toUpperCase();
956 - if(only) only = [only].flatten();
957 - var elements = [];
958 - $A(element.childNodes).each( function(e) {
959 - if(e.tagName && e.tagName.toUpperCase()==tagName &&
960 - (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
961 - elements.push(e);
962 - if(recursive) {
963 - var grandchildren = Element.findChildren(e, only, recursive, tagName);
964 - if(grandchildren) elements.push(grandchildren);
965 - }
966 - });
967 -
968 - return (elements.length>0 ? elements.flatten() : []);
969 - };
970 -
971 - Element.offsetSize = function (element, type) {
972 - return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
973 - }; No newline at end of file
This diff has been collapsed as it changes many lines, (1128 lines changed) Show them Hide them
@@ -1,1128 +0,0
1 - // Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
2 - // Contributors:
3 - // Justin Palmer (http://encytemedia.com/)
4 - // Mark Pilgrim (http://diveintomark.org/)
5 - // Martin Bialasinki
6 - //
7 - // script.aculo.us is freely distributable under the terms of an MIT-style license.
8 - // For details, see the script.aculo.us web site: http://script.aculo.us/
9 -
10 - // converts rgb() and #xxx to #xxxxxx format,
11 - // returns self (or first argument) if not convertable
12 - String.prototype.parseColor = function() {
13 - var color = '#';
14 - if (this.slice(0,4) == 'rgb(') {
15 - var cols = this.slice(4,this.length-1).split(',');
16 - var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
17 - } else {
18 - if (this.slice(0,1) == '#') {
19 - if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
20 - if (this.length==7) color = this.toLowerCase();
21 - }
22 - }
23 - return (color.length==7 ? color : (arguments[0] || this));
24 - };
25 -
26 - /*--------------------------------------------------------------------------*/
27 -
28 - Element.collectTextNodes = function(element) {
29 - return $A($(element).childNodes).collect( function(node) {
30 - return (node.nodeType==3 ? node.nodeValue :
31 - (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
32 - }).flatten().join('');
33 - };
34 -
35 - Element.collectTextNodesIgnoreClass = function(element, className) {
36 - return $A($(element).childNodes).collect( function(node) {
37 - return (node.nodeType==3 ? node.nodeValue :
38 - ((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
39 - Element.collectTextNodesIgnoreClass(node, className) : ''));
40 - }).flatten().join('');
41 - };
42 -
43 - Element.setContentZoom = function(element, percent) {
44 - element = $(element);
45 - element.setStyle({fontSize: (percent/100) + 'em'});
46 - if (Prototype.Browser.WebKit) window.scrollBy(0,0);
47 - return element;
48 - };
49 -
50 - Element.getInlineOpacity = function(element){
51 - return $(element).style.opacity || '';
52 - };
53 -
54 - Element.forceRerendering = function(element) {
55 - try {
56 - element = $(element);
57 - var n = document.createTextNode(' ');
58 - element.appendChild(n);
59 - element.removeChild(n);
60 - } catch(e) { }
61 - };
62 -
63 - /*--------------------------------------------------------------------------*/
64 -
65 - var Effect = {
66 - _elementDoesNotExistError: {
67 - name: 'ElementDoesNotExistError',
68 - message: 'The specified DOM element does not exist, but is required for this effect to operate'
69 - },
70 - Transitions: {
71 - linear: Prototype.K,
72 - sinoidal: function(pos) {
73 - return (-Math.cos(pos*Math.PI)/2) + .5;
74 - },
75 - reverse: function(pos) {
76 - return 1-pos;
77 - },
78 - flicker: function(pos) {
79 - var pos = ((-Math.cos(pos*Math.PI)/4) + .75) + Math.random()/4;
80 - return pos > 1 ? 1 : pos;
81 - },
82 - wobble: function(pos) {
83 - return (-Math.cos(pos*Math.PI*(9*pos))/2) + .5;
84 - },
85 - pulse: function(pos, pulses) {
86 - return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5;
87 - },
88 - spring: function(pos) {
89 - return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
90 - },
91 - none: function(pos) {
92 - return 0;
93 - },
94 - full: function(pos) {
95 - return 1;
96 - }
97 - },
98 - DefaultOptions: {
99 - duration: 1.0, // seconds
100 - fps: 100, // 100= assume 66fps max.
101 - sync: false, // true for combining
102 - from: 0.0,
103 - to: 1.0,
104 - delay: 0.0,
105 - queue: 'parallel'
106 - },
107 - tagifyText: function(element) {
108 - var tagifyStyle = 'position:relative';
109 - if (Prototype.Browser.IE) tagifyStyle += ';zoom:1';
110 -
111 - element = $(element);
112 - $A(element.childNodes).each( function(child) {
113 - if (child.nodeType==3) {
114 - child.nodeValue.toArray().each( function(character) {
115 - element.insertBefore(
116 - new Element('span', {style: tagifyStyle}).update(
117 - character == ' ' ? String.fromCharCode(160) : character),
118 - child);
119 - });
120 - Element.remove(child);
121 - }
122 - });
123 - },
124 - multiple: function(element, effect) {
125 - var elements;
126 - if (((typeof element == 'object') ||
127 - Object.isFunction(element)) &&
128 - (element.length))
129 - elements = element;
130 - else
131 - elements = $(element).childNodes;
132 -
133 - var options = Object.extend({
134 - speed: 0.1,
135 - delay: 0.0
136 - }, arguments[2] || { });
137 - var masterDelay = options.delay;
138 -
139 - $A(elements).each( function(element, index) {
140 - new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
141 - });
142 - },
143 - PAIRS: {
144 - 'slide': ['SlideDown','SlideUp'],
145 - 'blind': ['BlindDown','BlindUp'],
146 - 'appear': ['Appear','Fade']
147 - },
148 - toggle: function(element, effect) {
149 - element = $(element);
150 - effect = (effect || 'appear').toLowerCase();
151 - var options = Object.extend({
152 - queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
153 - }, arguments[2] || { });
154 - Effect[element.visible() ?
155 - Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
156 - }
157 - };
158 -
159 - Effect.DefaultOptions.transition = Effect.Transitions.sinoidal;
160 -
161 - /* ------------- core effects ------------- */
162 -
163 - Effect.ScopedQueue = Class.create(Enumerable, {
164 - initialize: function() {
165 - this.effects = [];
166 - this.interval = null;
167 - },
168 - _each: function(iterator) {
169 - this.effects._each(iterator);
170 - },
171 - add: function(effect) {
172 - var timestamp = new Date().getTime();
173 -
174 - var position = Object.isString(effect.options.queue) ?
175 - effect.options.queue : effect.options.queue.position;
176 -
177 - switch(position) {
178 - case 'front':
179 - // move unstarted effects after this effect
180 - this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
181 - e.startOn += effect.finishOn;
182 - e.finishOn += effect.finishOn;
183 - });
184 - break;
185 - case 'with-last':
186 - timestamp = this.effects.pluck('startOn').max() || timestamp;
187 - break;
188 - case 'end':
189 - // start effect after last queued effect has finished
190 - timestamp = this.effects.pluck('finishOn').max() || timestamp;
191 - break;
192 - }
193 -
194 - effect.startOn += timestamp;
195 - effect.finishOn += timestamp;
196 -
197 - if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
198 - this.effects.push(effect);
199 -
200 - if (!this.interval)
201 - this.interval = setInterval(this.loop.bind(this), 15);
202 - },
203 - remove: function(effect) {
204 - this.effects = this.effects.reject(function(e) { return e==effect });
205 - if (this.effects.length == 0) {
206 - clearInterval(this.interval);
207 - this.interval = null;
208 - }
209 - },
210 - loop: function() {
211 - var timePos = new Date().getTime();
212 - for(var i=0, len=this.effects.length;i<len;i++)
213 - this.effects[i] && this.effects[i].loop(timePos);
214 - }
215 - });
216 -
217 - Effect.Queues = {
218 - instances: $H(),
219 - get: function(queueName) {
220 - if (!Object.isString(queueName)) return queueName;
221 -
222 - return this.instances.get(queueName) ||
223 - this.instances.set(queueName, new Effect.ScopedQueue());
224 - }
225 - };
226 - Effect.Queue = Effect.Queues.get('global');
227 -
228 - Effect.Base = Class.create({
229 - position: null,
230 - start: function(options) {
231 - function codeForEvent(options,eventName){
232 - return (
233 - (options[eventName+'Internal'] ? 'this.options.'+eventName+'Internal(this);' : '') +
234 - (options[eventName] ? 'this.options.'+eventName+'(this);' : '')
235 - );
236 - }
237 - if (options && options.transition === false) options.transition = Effect.Transitions.linear;
238 - this.options = Object.extend(Object.extend({ },Effect.DefaultOptions), options || { });
239 - this.currentFrame = 0;
240 - this.state = 'idle';
241 - this.startOn = this.options.delay*1000;
242 - this.finishOn = this.startOn+(this.options.duration*1000);
243 - this.fromToDelta = this.options.to-this.options.from;
244 - this.totalTime = this.finishOn-this.startOn;
245 - this.totalFrames = this.options.fps*this.options.duration;
246 -
247 - this.render = (function() {
248 - function dispatch(effect, eventName) {
249 - if (effect.options[eventName + 'Internal'])
250 - effect.options[eventName + 'Internal'](effect);
251 - if (effect.options[eventName])
252 - effect.options[eventName](effect);
253 - }
254 -
255 - return function(pos) {
256 - if (this.state === "idle") {
257 - this.state = "running";
258 - dispatch(this, 'beforeSetup');
259 - if (this.setup) this.setup();
260 - dispatch(this, 'afterSetup');
261 - }
262 - if (this.state === "running") {
263 - pos = (this.options.transition(pos) * this.fromToDelta) + this.options.from;
264 - this.position = pos;
265 - dispatch(this, 'beforeUpdate');
266 - if (this.update) this.update(pos);
267 - dispatch(this, 'afterUpdate');
268 - }
269 - };
270 - })();
271 -
272 - this.event('beforeStart');
273 - if (!this.options.sync)
274 - Effect.Queues.get(Object.isString(this.options.queue) ?
275 - 'global' : this.options.queue.scope).add(this);
276 - },
277 - loop: function(timePos) {
278 - if (timePos >= this.startOn) {
279 - if (timePos >= this.finishOn) {
280 - this.render(1.0);
281 - this.cancel();
282 - this.event('beforeFinish');
283 - if (this.finish) this.finish();
284 - this.event('afterFinish');
285 - return;
286 - }
287 - var pos = (timePos - this.startOn) / this.totalTime,
288 - frame = (pos * this.totalFrames).round();
289 - if (frame > this.currentFrame) {
290 - this.render(pos);
291 - this.currentFrame = frame;
292 - }
293 - }
294 - },
295 - cancel: function() {
296 - if (!this.options.sync)
297 - Effect.Queues.get(Object.isString(this.options.queue) ?
298 - 'global' : this.options.queue.scope).remove(this);
299 - this.state = 'finished';
300 - },
301 - event: function(eventName) {
302 - if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
303 - if (this.options[eventName]) this.options[eventName](this);
304 - },
305 - inspect: function() {
306 - var data = $H();
307 - for(property in this)
308 - if (!Object.isFunction(this[property])) data.set(property, this[property]);
309 - return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
310 - }
311 - });
312 -
313 - Effect.Parallel = Class.create(Effect.Base, {
314 - initialize: function(effects) {
315 - this.effects = effects || [];
316 - this.start(arguments[1]);
317 - },
318 - update: function(position) {
319 - this.effects.invoke('render', position);
320 - },
321 - finish: function(position) {
322 - this.effects.each( function(effect) {
323 - effect.render(1.0);
324 - effect.cancel();
325 - effect.event('beforeFinish');
326 - if (effect.finish) effect.finish(position);
327 - effect.event('afterFinish');
328 - });
329 - }
330 - });
331 -
332 - Effect.Tween = Class.create(Effect.Base, {
333 - initialize: function(object, from, to) {
334 - object = Object.isString(object) ? $(object) : object;
335 - var args = $A(arguments), method = args.last(),
336 - options = args.length == 5 ? args[3] : null;
337 - this.method = Object.isFunction(method) ? method.bind(object) :
338 - Object.isFunction(object[method]) ? object[method].bind(object) :
339 - function(value) { object[method] = value };
340 - this.start(Object.extend({ from: from, to: to }, options || { }));
341 - },
342 - update: function(position) {
343 - this.method(position);
344 - }
345 - });
346 -
347 - Effect.Event = Class.create(Effect.Base, {
348 - initialize: function() {
349 - this.start(Object.extend({ duration: 0 }, arguments[0] || { }));
350 - },
351 - update: Prototype.emptyFunction
352 - });
353 -
354 - Effect.Opacity = Class.create(Effect.Base, {
355 - initialize: function(element) {
356 - this.element = $(element);
357 - if (!this.element) throw(Effect._elementDoesNotExistError);
358 - // make this work on IE on elements without 'layout'
359 - if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
360 - this.element.setStyle({zoom: 1});
361 - var options = Object.extend({
362 - from: this.element.getOpacity() || 0.0,
363 - to: 1.0
364 - }, arguments[1] || { });
365 - this.start(options);
366 - },
367 - update: function(position) {
368 - this.element.setOpacity(position);
369 - }
370 - });
371 -
372 - Effect.Move = Class.create(Effect.Base, {
373 - initialize: function(element) {
374 - this.element = $(element);
375 - if (!this.element) throw(Effect._elementDoesNotExistError);
376 - var options = Object.extend({
377 - x: 0,
378 - y: 0,
379 - mode: 'relative'
380 - }, arguments[1] || { });
381 - this.start(options);
382 - },
383 - setup: function() {
384 - this.element.makePositioned();
385 - this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
386 - this.originalTop = parseFloat(this.element.getStyle('top') || '0');
387 - if (this.options.mode == 'absolute') {
388 - this.options.x = this.options.x - this.originalLeft;
389 - this.options.y = this.options.y - this.originalTop;
390 - }
391 - },
392 - update: function(position) {
393 - this.element.setStyle({
394 - left: (this.options.x * position + this.originalLeft).round() + 'px',
395 - top: (this.options.y * position + this.originalTop).round() + 'px'
396 - });
397 - }
398 - });
399 -
400 - // for backwards compatibility
401 - Effect.MoveBy = function(element, toTop, toLeft) {
402 - return new Effect.Move(element,
403 - Object.extend({ x: toLeft, y: toTop }, arguments[3] || { }));
404 - };
405 -
406 - Effect.Scale = Class.create(Effect.Base, {
407 - initialize: function(element, percent) {
408 - this.element = $(element);
409 - if (!this.element) throw(Effect._elementDoesNotExistError);
410 - var options = Object.extend({
411 - scaleX: true,
412 - scaleY: true,
413 - scaleContent: true,
414 - scaleFromCenter: false,
415 - scaleMode: 'box', // 'box' or 'contents' or { } with provided values
416 - scaleFrom: 100.0,
417 - scaleTo: percent
418 - }, arguments[2] || { });
419 - this.start(options);
420 - },
421 - setup: function() {
422 - this.restoreAfterFinish = this.options.restoreAfterFinish || false;
423 - this.elementPositioning = this.element.getStyle('position');
424 -
425 - this.originalStyle = { };
426 - ['top','left','width','height','fontSize'].each( function(k) {
427 - this.originalStyle[k] = this.element.style[k];
428 - }.bind(this));
429 -
430 - this.originalTop = this.element.offsetTop;
431 - this.originalLeft = this.element.offsetLeft;
432 -
433 - var fontSize = this.element.getStyle('font-size') || '100%';
434 - ['em','px','%','pt'].each( function(fontSizeType) {
435 - if (fontSize.indexOf(fontSizeType)>0) {
436 - this.fontSize = parseFloat(fontSize);
437 - this.fontSizeType = fontSizeType;
438 - }
439 - }.bind(this));
440 -
441 - this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
442 -
443 - this.dims = null;
444 - if (this.options.scaleMode=='box')
445 - this.dims = [this.element.offsetHeight, this.element.offsetWidth];
446 - if (/^content/.test(this.options.scaleMode))
447 - this.dims = [this.element.scrollHeight, this.element.scrollWidth];
448 - if (!this.dims)
449 - this.dims = [this.options.scaleMode.originalHeight,
450 - this.options.scaleMode.originalWidth];
451 - },
452 - update: function(position) {
453 - var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
454 - if (this.options.scaleContent && this.fontSize)
455 - this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
456 - this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
457 - },
458 - finish: function(position) {
459 - if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
460 - },
461 - setDimensions: function(height, width) {
462 - var d = { };
463 - if (this.options.scaleX) d.width = width.round() + 'px';
464 - if (this.options.scaleY) d.height = height.round() + 'px';
465 - if (this.options.scaleFromCenter) {
466 - var topd = (height - this.dims[0])/2;
467 - var leftd = (width - this.dims[1])/2;
468 - if (this.elementPositioning == 'absolute') {
469 - if (this.options.scaleY) d.top = this.originalTop-topd + 'px';
470 - if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
471 - } else {
472 - if (this.options.scaleY) d.top = -topd + 'px';
473 - if (this.options.scaleX) d.left = -leftd + 'px';
474 - }
475 - }
476 - this.element.setStyle(d);
477 - }
478 - });
479 -
480 - Effect.Highlight = Class.create(Effect.Base, {
481 - initialize: function(element) {
482 - this.element = $(element);
483 - if (!this.element) throw(Effect._elementDoesNotExistError);
484 - var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { });
485 - this.start(options);
486 - },
487 - setup: function() {
488 - // Prevent executing on elements not in the layout flow
489 - if (this.element.getStyle('display')=='none') { this.cancel(); return; }
490 - // Disable background image during the effect
491 - this.oldStyle = { };
492 - if (!this.options.keepBackgroundImage) {
493 - this.oldStyle.backgroundImage = this.element.getStyle('background-image');
494 - this.element.setStyle({backgroundImage: 'none'});
495 - }
496 - if (!this.options.endcolor)
497 - this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
498 - if (!this.options.restorecolor)
499 - this.options.restorecolor = this.element.getStyle('background-color');
500 - // init color calculations
501 - this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
502 - this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
503 - },
504 - update: function(position) {
505 - this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
506 - return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) });
507 - },
508 - finish: function() {
509 - this.element.setStyle(Object.extend(this.oldStyle, {
510 - backgroundColor: this.options.restorecolor
511 - }));
512 - }
513 - });
514 -
515 - Effect.ScrollTo = function(element) {
516 - var options = arguments[1] || { },
517 - scrollOffsets = document.viewport.getScrollOffsets(),
518 - elementOffsets = $(element).cumulativeOffset();
519 -
520 - if (options.offset) elementOffsets[1] += options.offset;
521 -
522 - return new Effect.Tween(null,
523 - scrollOffsets.top,
524 - elementOffsets[1],
525 - options,
526 - function(p){ scrollTo(scrollOffsets.left, p.round()); }
527 - );
528 - };
529 -
530 - /* ------------- combination effects ------------- */
531 -
532 - Effect.Fade = function(element) {
533 - element = $(element);
534 - var oldOpacity = element.getInlineOpacity();
535 - var options = Object.extend({
536 - from: element.getOpacity() || 1.0,
537 - to: 0.0,
538 - afterFinishInternal: function(effect) {
539 - if (effect.options.to!=0) return;
540 - effect.element.hide().setStyle({opacity: oldOpacity});
541 - }
542 - }, arguments[1] || { });
543 - return new Effect.Opacity(element,options);
544 - };
545 -
546 - Effect.Appear = function(element) {
547 - element = $(element);
548 - var options = Object.extend({
549 - from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
550 - to: 1.0,
551 - // force Safari to render floated elements properly
552 - afterFinishInternal: function(effect) {
553 - effect.element.forceRerendering();
554 - },
555 - beforeSetup: function(effect) {
556 - effect.element.setOpacity(effect.options.from).show();
557 - }}, arguments[1] || { });
558 - return new Effect.Opacity(element,options);
559 - };
560 -
561 - Effect.Puff = function(element) {
562 - element = $(element);
563 - var oldStyle = {
564 - opacity: element.getInlineOpacity(),
565 - position: element.getStyle('position'),
566 - top: element.style.top,
567 - left: element.style.left,
568 - width: element.style.width,
569 - height: element.style.height
570 - };
571 - return new Effect.Parallel(
572 - [ new Effect.Scale(element, 200,
573 - { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
574 - new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
575 - Object.extend({ duration: 1.0,
576 - beforeSetupInternal: function(effect) {
577 - Position.absolutize(effect.effects[0].element);
578 - },
579 - afterFinishInternal: function(effect) {
580 - effect.effects[0].element.hide().setStyle(oldStyle); }
581 - }, arguments[1] || { })
582 - );
583 - };
584 -
585 - Effect.BlindUp = function(element) {
586 - element = $(element);
587 - element.makeClipping();
588 - return new Effect.Scale(element, 0,
589 - Object.extend({ scaleContent: false,
590 - scaleX: false,
591 - restoreAfterFinish: true,
592 - afterFinishInternal: function(effect) {
593 - effect.element.hide().undoClipping();
594 - }
595 - }, arguments[1] || { })
596 - );
597 - };
598 -
599 - Effect.BlindDown = function(element) {
600 - element = $(element);
601 - var elementDimensions = element.getDimensions();
602 - return new Effect.Scale(element, 100, Object.extend({
603 - scaleContent: false,
604 - scaleX: false,
605 - scaleFrom: 0,
606 - scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
607 - restoreAfterFinish: true,
608 - afterSetup: function(effect) {
609 - effect.element.makeClipping().setStyle({height: '0px'}).show();
610 - },
611 - afterFinishInternal: function(effect) {
612 - effect.element.undoClipping();
613 - }
614 - }, arguments[1] || { }));
615 - };
616 -
617 - Effect.SwitchOff = function(element) {
618 - element = $(element);
619 - var oldOpacity = element.getInlineOpacity();
620 - return new Effect.Appear(element, Object.extend({
621 - duration: 0.4,
622 - from: 0,
623 - transition: Effect.Transitions.flicker,
624 - afterFinishInternal: function(effect) {
625 - new Effect.Scale(effect.element, 1, {
626 - duration: 0.3, scaleFromCenter: true,
627 - scaleX: false, scaleContent: false, restoreAfterFinish: true,
628 - beforeSetup: function(effect) {
629 - effect.element.makePositioned().makeClipping();
630 - },
631 - afterFinishInternal: function(effect) {
632 - effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
633 - }
634 - });
635 - }
636 - }, arguments[1] || { }));
637 - };
638 -
639 - Effect.DropOut = function(element) {
640 - element = $(element);
641 - var oldStyle = {
642 - top: element.getStyle('top'),
643 - left: element.getStyle('left'),
644 - opacity: element.getInlineOpacity() };
645 - return new Effect.Parallel(
646 - [ new Effect.Move(element, {x: 0, y: 100, sync: true }),
647 - new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
648 - Object.extend(
649 - { duration: 0.5,
650 - beforeSetup: function(effect) {
651 - effect.effects[0].element.makePositioned();
652 - },
653 - afterFinishInternal: function(effect) {
654 - effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
655 - }
656 - }, arguments[1] || { }));
657 - };
658 -
659 - Effect.Shake = function(element) {
660 - element = $(element);
661 - var options = Object.extend({
662 - distance: 20,
663 - duration: 0.5
664 - }, arguments[1] || {});
665 - var distance = parseFloat(options.distance);
666 - var split = parseFloat(options.duration) / 10.0;
667 - var oldStyle = {
668 - top: element.getStyle('top'),
669 - left: element.getStyle('left') };
670 - return new Effect.Move(element,
671 - { x: distance, y: 0, duration: split, afterFinishInternal: function(effect) {
672 - new Effect.Move(effect.element,
673 - { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
674 - new Effect.Move(effect.element,
675 - { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
676 - new Effect.Move(effect.element,
677 - { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
678 - new Effect.Move(effect.element,
679 - { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
680 - new Effect.Move(effect.element,
681 - { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) {
682 - effect.element.undoPositioned().setStyle(oldStyle);
683 - }}); }}); }}); }}); }}); }});
684 - };
685 -
686 - Effect.SlideDown = function(element) {
687 - element = $(element).cleanWhitespace();
688 - // SlideDown need to have the content of the element wrapped in a container element with fixed height!
689 - var oldInnerBottom = element.down().getStyle('bottom');
690 - var elementDimensions = element.getDimensions();
691 - return new Effect.Scale(element, 100, Object.extend({
692 - scaleContent: false,
693 - scaleX: false,
694 - scaleFrom: window.opera ? 0 : 1,
695 - scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
696 - restoreAfterFinish: true,
697 - afterSetup: function(effect) {
698 - effect.element.makePositioned();
699 - effect.element.down().makePositioned();
700 - if (window.opera) effect.element.setStyle({top: ''});
701 - effect.element.makeClipping().setStyle({height: '0px'}).show();
702 - },
703 - afterUpdateInternal: function(effect) {
704 - effect.element.down().setStyle({bottom:
705 - (effect.dims[0] - effect.element.clientHeight) + 'px' });
706 - },
707 - afterFinishInternal: function(effect) {
708 - effect.element.undoClipping().undoPositioned();
709 - effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
710 - }, arguments[1] || { })
711 - );
712 - };
713 -
714 - Effect.SlideUp = function(element) {
715 - element = $(element).cleanWhitespace();
716 - var oldInnerBottom = element.down().getStyle('bottom');
717 - var elementDimensions = element.getDimensions();
718 - return new Effect.Scale(element, window.opera ? 0 : 1,
719 - Object.extend({ scaleContent: false,
720 - scaleX: false,
721 - scaleMode: 'box',
722 - scaleFrom: 100,
723 - scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
724 - restoreAfterFinish: true,
725 - afterSetup: function(effect) {
726 - effect.element.makePositioned();
727 - effect.element.down().makePositioned();
728 - if (window.opera) effect.element.setStyle({top: ''});
729 - effect.element.makeClipping().show();
730 - },
731 - afterUpdateInternal: function(effect) {
732 - effect.element.down().setStyle({bottom:
733 - (effect.dims[0] - effect.element.clientHeight) + 'px' });
734 - },
735 - afterFinishInternal: function(effect) {
736 - effect.element.hide().undoClipping().undoPositioned();
737 - effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom});
738 - }
739 - }, arguments[1] || { })
740 - );
741 - };
742 -
743 - // Bug in opera makes the TD containing this element expand for a instance after finish
744 - Effect.Squish = function(element) {
745 - return new Effect.Scale(element, window.opera ? 1 : 0, {
746 - restoreAfterFinish: true,
747 - beforeSetup: function(effect) {
748 - effect.element.makeClipping();
749 - },
750 - afterFinishInternal: function(effect) {
751 - effect.element.hide().undoClipping();
752 - }
753 - });
754 - };
755 -
756 - Effect.Grow = function(element) {
757 - element = $(element);
758 - var options = Object.extend({
759 - direction: 'center',
760 - moveTransition: Effect.Transitions.sinoidal,
761 - scaleTransition: Effect.Transitions.sinoidal,
762 - opacityTransition: Effect.Transitions.full
763 - }, arguments[1] || { });
764 - var oldStyle = {
765 - top: element.style.top,
766 - left: element.style.left,
767 - height: element.style.height,
768 - width: element.style.width,
769 - opacity: element.getInlineOpacity() };
770 -
771 - var dims = element.getDimensions();
772 - var initialMoveX, initialMoveY;
773 - var moveX, moveY;
774 -
775 - switch (options.direction) {
776 - case 'top-left':
777 - initialMoveX = initialMoveY = moveX = moveY = 0;
778 - break;
779 - case 'top-right':
780 - initialMoveX = dims.width;
781 - initialMoveY = moveY = 0;
782 - moveX = -dims.width;
783 - break;
784 - case 'bottom-left':
785 - initialMoveX = moveX = 0;
786 - initialMoveY = dims.height;
787 - moveY = -dims.height;
788 - break;
789 - case 'bottom-right':
790 - initialMoveX = dims.width;
791 - initialMoveY = dims.height;
792 - moveX = -dims.width;
793 - moveY = -dims.height;
794 - break;
795 - case 'center':
796 - initialMoveX = dims.width / 2;
797 - initialMoveY = dims.height / 2;
798 - moveX = -dims.width / 2;
799 - moveY = -dims.height / 2;
800 - break;
801 - }
802 -
803 - return new Effect.Move(element, {
804 - x: initialMoveX,
805 - y: initialMoveY,
806 - duration: 0.01,
807 - beforeSetup: function(effect) {
808 - effect.element.hide().makeClipping().makePositioned();
809 - },
810 - afterFinishInternal: function(effect) {
811 - new Effect.Parallel(
812 - [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
813 - new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
814 - new Effect.Scale(effect.element, 100, {
815 - scaleMode: { originalHeight: dims.height, originalWidth: dims.width },
816 - sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
817 - ], Object.extend({
818 - beforeSetup: function(effect) {
819 - effect.effects[0].element.setStyle({height: '0px'}).show();
820 - },
821 - afterFinishInternal: function(effect) {
822 - effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);
823 - }
824 - }, options)
825 - );
826 - }
827 - });
828 - };
829 -
830 - Effect.Shrink = function(element) {
831 - element = $(element);
832 - var options = Object.extend({
833 - direction: 'center',
834 - moveTransition: Effect.Transitions.sinoidal,
835 - scaleTransition: Effect.Transitions.sinoidal,
836 - opacityTransition: Effect.Transitions.none
837 - }, arguments[1] || { });
838 - var oldStyle = {
839 - top: element.style.top,
840 - left: element.style.left,
841 - height: element.style.height,
842 - width: element.style.width,
843 - opacity: element.getInlineOpacity() };
844 -
845 - var dims = element.getDimensions();
846 - var moveX, moveY;
847 -
848 - switch (options.direction) {
849 - case 'top-left':
850 - moveX = moveY = 0;
851 - break;
852 - case 'top-right':
853 - moveX = dims.width;
854 - moveY = 0;
855 - break;
856 - case 'bottom-left':
857 - moveX = 0;
858 - moveY = dims.height;
859 - break;
860 - case 'bottom-right':
861 - moveX = dims.width;
862 - moveY = dims.height;
863 - break;
864 - case 'center':
865 - moveX = dims.width / 2;
866 - moveY = dims.height / 2;
867 - break;
868 - }
869 -
870 - return new Effect.Parallel(
871 - [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
872 - new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
873 - new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
874 - ], Object.extend({
875 - beforeStartInternal: function(effect) {
876 - effect.effects[0].element.makePositioned().makeClipping();
877 - },
878 - afterFinishInternal: function(effect) {
879 - effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
880 - }, options)
881 - );
882 - };
883 -
884 - Effect.Pulsate = function(element) {
885 - element = $(element);
886 - var options = arguments[1] || { },
887 - oldOpacity = element.getInlineOpacity(),
888 - transition = options.transition || Effect.Transitions.linear,
889 - reverser = function(pos){
890 - return 1 - transition((-Math.cos((pos*(options.pulses||5)*2)*Math.PI)/2) + .5);
891 - };
892 -
893 - return new Effect.Opacity(element,
894 - Object.extend(Object.extend({ duration: 2.0, from: 0,
895 - afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
896 - }, options), {transition: reverser}));
897 - };
898 -
899 - Effect.Fold = function(element) {
900 - element = $(element);
901 - var oldStyle = {
902 - top: element.style.top,
903 - left: element.style.left,
904 - width: element.style.width,
905 - height: element.style.height };
906 - element.makeClipping();
907 - return new Effect.Scale(element, 5, Object.extend({
908 - scaleContent: false,
909 - scaleX: false,
910 - afterFinishInternal: function(effect) {
911 - new Effect.Scale(element, 1, {
912 - scaleContent: false,
913 - scaleY: false,
914 - afterFinishInternal: function(effect) {
915 - effect.element.hide().undoClipping().setStyle(oldStyle);
916 - } });
917 - }}, arguments[1] || { }));
918 - };
919 -
920 - Effect.Morph = Class.create(Effect.Base, {
921 - initialize: function(element) {
922 - this.element = $(element);
923 - if (!this.element) throw(Effect._elementDoesNotExistError);
924 - var options = Object.extend({
925 - style: { }
926 - }, arguments[1] || { });
927 -
928 - if (!Object.isString(options.style)) this.style = $H(options.style);
929 - else {
930 - if (options.style.include(':'))
931 - this.style = options.style.parseStyle();
932 - else {
933 - this.element.addClassName(options.style);
934 - this.style = $H(this.element.getStyles());
935 - this.element.removeClassName(options.style);
936 - var css = this.element.getStyles();
937 - this.style = this.style.reject(function(style) {
938 - return style.value == css[style.key];
939 - });
940 - options.afterFinishInternal = function(effect) {
941 - effect.element.addClassName(effect.options.style);
942 - effect.transforms.each(function(transform) {
943 - effect.element.style[transform.style] = '';
944 - });
945 - };
946 - }
947 - }
948 - this.start(options);
949 - },
950 -
951 - setup: function(){
952 - function parseColor(color){
953 - if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
954 - color = color.parseColor();
955 - return $R(0,2).map(function(i){
956 - return parseInt( color.slice(i*2+1,i*2+3), 16 );
957 - });
958 - }
959 - this.transforms = this.style.map(function(pair){
960 - var property = pair[0], value = pair[1], unit = null;
961 -
962 - if (value.parseColor('#zzzzzz') != '#zzzzzz') {
963 - value = value.parseColor();
964 - unit = 'color';
965 - } else if (property == 'opacity') {
966 - value = parseFloat(value);
967 - if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
968 - this.element.setStyle({zoom: 1});
969 - } else if (Element.CSS_LENGTH.test(value)) {
970 - var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
971 - value = parseFloat(components[1]);
972 - unit = (components.length == 3) ? components[2] : null;
973 - }
974 -
975 - var originalValue = this.element.getStyle(property);
976 - return {
977 - style: property.camelize(),
978 - originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0),
979 - targetValue: unit=='color' ? parseColor(value) : value,
980 - unit: unit
981 - };
982 - }.bind(this)).reject(function(transform){
983 - return (
984 - (transform.originalValue == transform.targetValue) ||
985 - (
986 - transform.unit != 'color' &&
987 - (isNaN(transform.originalValue) || isNaN(transform.targetValue))
988 - )
989 - );
990 - });
991 - },
992 - update: function(position) {
993 - var style = { }, transform, i = this.transforms.length;
994 - while(i--)
995 - style[(transform = this.transforms[i]).style] =
996 - transform.unit=='color' ? '#'+
997 - (Math.round(transform.originalValue[0]+
998 - (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
999 - (Math.round(transform.originalValue[1]+
1000 - (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +
1001 - (Math.round(transform.originalValue[2]+
1002 - (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
1003 - (transform.originalValue +
1004 - (transform.targetValue - transform.originalValue) * position).toFixed(3) +
1005 - (transform.unit === null ? '' : transform.unit);
1006 - this.element.setStyle(style, true);
1007 - }
1008 - });
1009 -
1010 - Effect.Transform = Class.create({
1011 - initialize: function(tracks){
1012 - this.tracks = [];
1013 - this.options = arguments[1] || { };
1014 - this.addTracks(tracks);
1015 - },
1016 - addTracks: function(tracks){
1017 - tracks.each(function(track){
1018 - track = $H(track);
1019 - var data = track.values().first();
1020 - this.tracks.push($H({
1021 - ids: track.keys().first(),
1022 - effect: Effect.Morph,
1023 - options: { style: data }
1024 - }));
1025 - }.bind(this));
1026 - return this;
1027 - },
1028 - play: function(){
1029 - return new Effect.Parallel(
1030 - this.tracks.map(function(track){
1031 - var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options');
1032 - var elements = [$(ids) || $$(ids)].flatten();
1033 - return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) });
1034 - }).flatten(),
1035 - this.options
1036 - );
1037 - }
1038 - });
1039 -
1040 - Element.CSS_PROPERTIES = $w(
1041 - 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' +
1042 - 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
1043 - 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
1044 - 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
1045 - 'fontSize fontWeight height left letterSpacing lineHeight ' +
1046 - 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
1047 - 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
1048 - 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
1049 - 'right textIndent top width wordSpacing zIndex');
1050 -
1051 - Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
1052 -
1053 - String.__parseStyleElement = document.createElement('div');
1054 - String.prototype.parseStyle = function(){
1055 - var style, styleRules = $H();
1056 - if (Prototype.Browser.WebKit)
1057 - style = new Element('div',{style:this}).style;
1058 - else {
1059 - String.__parseStyleElement.innerHTML = '<div style="' + this + '"></div>';
1060 - style = String.__parseStyleElement.childNodes[0].style;
1061 - }
1062 -
1063 - Element.CSS_PROPERTIES.each(function(property){
1064 - if (style[property]) styleRules.set(property, style[property]);
1065 - });
1066 -
1067 - if (Prototype.Browser.IE && this.include('opacity'))
1068 - styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]);
1069 -
1070 - return styleRules;
1071 - };
1072 -
1073 - if (document.defaultView && document.defaultView.getComputedStyle) {
1074 - Element.getStyles = function(element) {
1075 - var css = document.defaultView.getComputedStyle($(element), null);
1076 - return Element.CSS_PROPERTIES.inject({ }, function(styles, property) {
1077 - styles[property] = css[property];
1078 - return styles;
1079 - });
1080 - };
1081 - } else {
1082 - Element.getStyles = function(element) {
1083 - element = $(element);
1084 - var css = element.currentStyle, styles;
1085 - styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) {
1086 - results[property] = css[property];
1087 - return results;
1088 - });
1089 - if (!styles.opacity) styles.opacity = element.getOpacity();
1090 - return styles;
1091 - };
1092 - }
1093 -
1094 - Effect.Methods = {
1095 - morph: function(element, style) {
1096 - element = $(element);
1097 - new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { }));
1098 - return element;
1099 - },
1100 - visualEffect: function(element, effect, options) {
1101 - element = $(element);
1102 - var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1);
1103 - new Effect[klass](element, options);
1104 - return element;
1105 - },
1106 - highlight: function(element, options) {
1107 - element = $(element);
1108 - new Effect.Highlight(element, options);
1109 - return element;
1110 - }
1111 - };
1112 -
1113 - $w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+
1114 - 'pulsate shake puff squish switchOff dropOut').each(
1115 - function(effect) {
1116 - Effect.Methods[effect] = function(element, options){
1117 - element = $(element);
1118 - Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options);
1119 - return element;
1120 - };
1121 - }
1122 - );
1123 -
1124 - $w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each(
1125 - function(f) { Effect.Methods[f] = Element[f]; }
1126 - );
1127 -
1128 - Element.addMethods(Effect.Methods); No newline at end of file
This diff has been collapsed as it changes many lines, (4320 lines changed) Show them Hide them
@@ -1,4320 +0,0
1 - /* Prototype JavaScript framework, version 1.6.0.3
2 - * (c) 2005-2008 Sam Stephenson
3 - *
4 - * Prototype is freely distributable under the terms of an MIT-style license.
5 - * For details, see the Prototype web site: http://www.prototypejs.org/
6 - *
7 - *--------------------------------------------------------------------------*/
8 -
9 - var Prototype = {
10 - Version: '1.6.0.3',
11 -
12 - Browser: {
13 - IE: !!(window.attachEvent &&
14 - navigator.userAgent.indexOf('Opera') === -1),
15 - Opera: navigator.userAgent.indexOf('Opera') > -1,
16 - WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
17 - Gecko: navigator.userAgent.indexOf('Gecko') > -1 &&
18 - navigator.userAgent.indexOf('KHTML') === -1,
19 - MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
20 - },
21 -
22 - BrowserFeatures: {
23 - XPath: !!document.evaluate,
24 - SelectorsAPI: !!document.querySelector,
25 - ElementExtensions: !!window.HTMLElement,
26 - SpecificElementExtensions:
27 - document.createElement('div')['__proto__'] &&
28 - document.createElement('div')['__proto__'] !==
29 - document.createElement('form')['__proto__']
30 - },
31 -
32 - ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
33 - JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
34 -
35 - emptyFunction: function() { },
36 - K: function(x) { return x }
37 - };
38 -
39 - if (Prototype.Browser.MobileSafari)
40 - Prototype.BrowserFeatures.SpecificElementExtensions = false;
41 -
42 -
43 - /* Based on Alex Arnell's inheritance implementation. */
44 - var Class = {
45 - create: function() {
46 - var parent = null, properties = $A(arguments);
47 - if (Object.isFunction(properties[0]))
48 - parent = properties.shift();
49 -
50 - function klass() {
51 - this.initialize.apply(this, arguments);
52 - }
53 -
54 - Object.extend(klass, Class.Methods);
55 - klass.superclass = parent;
56 - klass.subclasses = [];
57 -
58 - if (parent) {
59 - var subclass = function() { };
60 - subclass.prototype = parent.prototype;
61 - klass.prototype = new subclass;
62 - parent.subclasses.push(klass);
63 - }
64 -
65 - for (var i = 0; i < properties.length; i++)
66 - klass.addMethods(properties[i]);
67 -
68 - if (!klass.prototype.initialize)
69 - klass.prototype.initialize = Prototype.emptyFunction;
70 -
71 - klass.prototype.constructor = klass;
72 -
73 - return klass;
74 - }
75 - };
76 -
77 - Class.Methods = {
78 - addMethods: function(source) {
79 - var ancestor = this.superclass && this.superclass.prototype;
80 - var properties = Object.keys(source);
81 -
82 - if (!Object.keys({ toString: true }).length)
83 - properties.push("toString", "valueOf");
84 -
85 - for (var i = 0, length = properties.length; i < length; i++) {
86 - var property = properties[i], value = source[property];
87 - if (ancestor && Object.isFunction(value) &&
88 - value.argumentNames().first() == "$super") {
89 - var method = value;
90 - value = (function(m) {
91 - return function() { return ancestor[m].apply(this, arguments) };
92 - })(property).wrap(method);
93 -
94 - value.valueOf = method.valueOf.bind(method);
95 - value.toString = method.toString.bind(method);
96 - }
97 - this.prototype[property] = value;
98 - }
99 -
100 - return this;
101 - }
102 - };
103 -
104 - var Abstract = { };
105 -
106 - Object.extend = function(destination, source) {
107 - for (var property in source)
108 - destination[property] = source[property];
109 - return destination;
110 - };
111 -
112 - Object.extend(Object, {
113 - inspect: function(object) {
114 - try {
115 - if (Object.isUndefined(object)) return 'undefined';
116 - if (object === null) return 'null';
117 - return object.inspect ? object.inspect() : String(object);
118 - } catch (e) {
119 - if (e instanceof RangeError) return '...';
120 - throw e;
121 - }
122 - },
123 -
124 - toJSON: function(object) {
125 - var type = typeof object;
126 - switch (type) {
127 - case 'undefined':
128 - case 'function':
129 - case 'unknown': return;
130 - case 'boolean': return object.toString();
131 - }
132 -
133 - if (object === null) return 'null';
134 - if (object.toJSON) return object.toJSON();
135 - if (Object.isElement(object)) return;
136 -
137 - var results = [];
138 - for (var property in object) {
139 - var value = Object.toJSON(object[property]);
140 - if (!Object.isUndefined(value))
141 - results.push(property.toJSON() + ': ' + value);
142 - }
143 -
144 - return '{' + results.join(', ') + '}';
145 - },
146 -
147 - toQueryString: function(object) {
148 - return $H(object).toQueryString();
149 - },
150 -
151 - toHTML: function(object) {
152 - return object && object.toHTML ? object.toHTML() : String.interpret(object);
153 - },
154 -
155 - keys: function(object) {
156 - var keys = [];
157 - for (var property in object)
158 - keys.push(property);
159 - return keys;
160 - },
161 -
162 - values: function(object) {
163 - var values = [];
164 - for (var property in object)
165 - values.push(object[property]);
166 - return values;
167 - },
168 -
169 - clone: function(object) {
170 - return Object.extend({ }, object);
171 - },
172 -
173 - isElement: function(object) {
174 - return !!(object && object.nodeType == 1);
175 - },
176 -
177 - isArray: function(object) {
178 - return object != null && typeof object == "object" &&
179 - 'splice' in object && 'join' in object;
180 - },
181 -
182 - isHash: function(object) {
183 - return object instanceof Hash;
184 - },
185 -
186 - isFunction: function(object) {
187 - return typeof object == "function";
188 - },
189 -
190 - isString: function(object) {
191 - return typeof object == "string";
192 - },
193 -
194 - isNumber: function(object) {
195 - return typeof object == "number";
196 - },
197 -
198 - isUndefined: function(object) {
199 - return typeof object == "undefined";
200 - }
201 - });
202 -
203 - Object.extend(Function.prototype, {
204 - argumentNames: function() {
205 - var names = this.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1]
206 - .replace(/\s+/g, '').split(',');
207 - return names.length == 1 && !names[0] ? [] : names;
208 - },
209 -
210 - bind: function() {
211 - if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
212 - var __method = this, args = $A(arguments), object = args.shift();
213 - return function() {
214 - return __method.apply(object, args.concat($A(arguments)));
215 - }
216 - },
217 -
218 - bindAsEventListener: function() {
219 - var __method = this, args = $A(arguments), object = args.shift();
220 - return function(event) {
221 - return __method.apply(object, [event || window.event].concat(args));
222 - }
223 - },
224 -
225 - curry: function() {
226 - if (!arguments.length) return this;
227 - var __method = this, args = $A(arguments);
228 - return function() {
229 - return __method.apply(this, args.concat($A(arguments)));
230 - }
231 - },
232 -
233 - delay: function() {
234 - var __method = this, args = $A(arguments), timeout = args.shift() * 1000;
235 - return window.setTimeout(function() {
236 - return __method.apply(__method, args);
237 - }, timeout);
238 - },
239 -
240 - defer: function() {
241 - var args = [0.01].concat($A(arguments));
242 - return this.delay.apply(this, args);
243 - },
244 -
245 - wrap: function(wrapper) {
246 - var __method = this;
247 - return function() {
248 - return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));
249 - }
250 - },
251 -
252 - methodize: function() {
253 - if (this._methodized) return this._methodized;
254 - var __method = this;
255 - return this._methodized = function() {
256 - return __method.apply(null, [this].concat($A(arguments)));
257 - };
258 - }
259 - });
260 -
261 - Date.prototype.toJSON = function() {
262 - return '"' + this.getUTCFullYear() + '-' +
263 - (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
264 - this.getUTCDate().toPaddedString(2) + 'T' +
265 - this.getUTCHours().toPaddedString(2) + ':' +
266 - this.getUTCMinutes().toPaddedString(2) + ':' +
267 - this.getUTCSeconds().toPaddedString(2) + 'Z"';
268 - };
269 -
270 - var Try = {
271 - these: function() {
272 - var returnValue;
273 -
274 - for (var i = 0, length = arguments.length; i < length; i++) {
275 - var lambda = arguments[i];
276 - try {
277 - returnValue = lambda();
278 - break;
279 - } catch (e) { }
280 - }
281 -
282 - return returnValue;
283 - }
284 - };
285 -
286 - RegExp.prototype.match = RegExp.prototype.test;
287 -
288 - RegExp.escape = function(str) {
289 - return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
290 - };
291 -
292 - /*--------------------------------------------------------------------------*/
293 -
294 - var PeriodicalExecuter = Class.create({
295 - initialize: function(callback, frequency) {
296 - this.callback = callback;
297 - this.frequency = frequency;
298 - this.currentlyExecuting = false;
299 -
300 - this.registerCallback();
301 - },
302 -
303 - registerCallback: function() {
304 - this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
305 - },
306 -
307 - execute: function() {
308 - this.callback(this);
309 - },
310 -
311 - stop: function() {
312 - if (!this.timer) return;
313 - clearInterval(this.timer);
314 - this.timer = null;
315 - },
316 -
317 - onTimerEvent: function() {
318 - if (!this.currentlyExecuting) {
319 - try {
320 - this.currentlyExecuting = true;
321 - this.execute();
322 - } finally {
323 - this.currentlyExecuting = false;
324 - }
325 - }
326 - }
327 - });
328 - Object.extend(String, {
329 - interpret: function(value) {
330 - return value == null ? '' : String(value);
331 - },
332 - specialChar: {
333 - '\b': '\\b',
334 - '\t': '\\t',
335 - '\n': '\\n',
336 - '\f': '\\f',
337 - '\r': '\\r',
338 - '\\': '\\\\'
339 - }
340 - });
341 -
342 - Object.extend(String.prototype, {
343 - gsub: function(pattern, replacement) {
344 - var result = '', source = this, match;
345 - replacement = arguments.callee.prepareReplacement(replacement);
346 -
347 - while (source.length > 0) {
348 - if (match = source.match(pattern)) {
349 - result += source.slice(0, match.index);
350 - result += String.interpret(replacement(match));
351 - source = source.slice(match.index + match[0].length);
352 - } else {
353 - result += source, source = '';
354 - }
355 - }
356 - return result;
357 - },
358 -
359 - sub: function(pattern, replacement, count) {
360 - replacement = this.gsub.prepareReplacement(replacement);
361 - count = Object.isUndefined(count) ? 1 : count;
362 -
363 - return this.gsub(pattern, function(match) {
364 - if (--count < 0) return match[0];
365 - return replacement(match);
366 - });
367 - },
368 -
369 - scan: function(pattern, iterator) {
370 - this.gsub(pattern, iterator);
371 - return String(this);
372 - },
373 -
374 - truncate: function(length, truncation) {
375 - length = length || 30;
376 - truncation = Object.isUndefined(truncation) ? '...' : truncation;
377 - return this.length > length ?
378 - this.slice(0, length - truncation.length) + truncation : String(this);
379 - },
380 -
381 - strip: function() {
382 - return this.replace(/^\s+/, '').replace(/\s+$/, '');
383 - },
384 -
385 - stripTags: function() {
386 - return this.replace(/<\/?[^>]+>/gi, '');
387 - },
388 -
389 - stripScripts: function() {
390 - return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
391 - },
392 -
393 - extractScripts: function() {
394 - var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
395 - var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
396 - return (this.match(matchAll) || []).map(function(scriptTag) {
397 - return (scriptTag.match(matchOne) || ['', ''])[1];
398 - });
399 - },
400 -
401 - evalScripts: function() {
402 - return this.extractScripts().map(function(script) { return eval(script) });
403 - },
404 -
405 - escapeHTML: function() {
406 - var self = arguments.callee;
407 - self.text.data = this;
408 - return self.div.innerHTML;
409 - },
410 -
411 - unescapeHTML: function() {
412 - var div = new Element('div');
413 - div.innerHTML = this.stripTags();
414 - return div.childNodes[0] ? (div.childNodes.length > 1 ?
415 - $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
416 - div.childNodes[0].nodeValue) : '';
417 - },
418 -
419 - toQueryParams: function(separator) {
420 - var match = this.strip().match(/([^?#]*)(#.*)?$/);
421 - if (!match) return { };
422 -
423 - return match[1].split(separator || '&').inject({ }, function(hash, pair) {
424 - if ((pair = pair.split('='))[0]) {
425 - var key = decodeURIComponent(pair.shift());
426 - var value = pair.length > 1 ? pair.join('=') : pair[0];
427 - if (value != undefined) value = decodeURIComponent(value);
428 -
429 - if (key in hash) {
430 - if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
431 - hash[key].push(value);
432 - }
433 - else hash[key] = value;
434 - }
435 - return hash;
436 - });
437 - },
438 -
439 - toArray: function() {
440 - return this.split('');
441 - },
442 -
443 - succ: function() {
444 - return this.slice(0, this.length - 1) +
445 - String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
446 - },
447 -
448 - times: function(count) {
449 - return count < 1 ? '' : new Array(count + 1).join(this);
450 - },
451 -
452 - camelize: function() {
453 - var parts = this.split('-'), len = parts.length;
454 - if (len == 1) return parts[0];
455 -
456 - var camelized = this.charAt(0) == '-'
457 - ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
458 - : parts[0];
459 -
460 - for (var i = 1; i < len; i++)
461 - camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
462 -
463 - return camelized;
464 - },
465 -
466 - capitalize: function() {
467 - return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
468 - },
469 -
470 - underscore: function() {
471 - return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
472 - },
473 -
474 - dasherize: function() {
475 - return this.gsub(/_/,'-');
476 - },
477 -
478 - inspect: function(useDoubleQuotes) {
479 - var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
480 - var character = String.specialChar[match[0]];
481 - return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
482 - });
483 - if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
484 - return "'" + escapedString.replace(/'/g, '\\\'') + "'";
485 - },
486 -
487 - toJSON: function() {
488 - return this.inspect(true);
489 - },
490 -
491 - unfilterJSON: function(filter) {
492 - return this.sub(filter || Prototype.JSONFilter, '#{1}');
493 - },
494 -
495 - isJSON: function() {
496 - var str = this;
497 - if (str.blank()) return false;
498 - str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
499 - return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
500 - },
501 -
502 - evalJSON: function(sanitize) {
503 - var json = this.unfilterJSON();
504 - try {
505 - if (!sanitize || json.isJSON()) return eval('(' + json + ')');
506 - } catch (e) { }
507 - throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
508 - },
509 -
510 - include: function(pattern) {
511 - return this.indexOf(pattern) > -1;
512 - },
513 -
514 - startsWith: function(pattern) {
515 - return this.indexOf(pattern) === 0;
516 - },
517 -
518 - endsWith: function(pattern) {
519 - var d = this.length - pattern.length;
520 - return d >= 0 && this.lastIndexOf(pattern) === d;
521 - },
522 -
523 - empty: function() {
524 - return this == '';
525 - },
526 -
527 - blank: function() {
528 - return /^\s*$/.test(this);
529 - },
530 -
531 - interpolate: function(object, pattern) {
532 - return new Template(this, pattern).evaluate(object);
533 - }
534 - });
535 -
536 - if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
537 - escapeHTML: function() {
538 - return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
539 - },
540 - unescapeHTML: function() {
541 - return this.stripTags().replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
542 - }
543 - });
544 -
545 - String.prototype.gsub.prepareReplacement = function(replacement) {
546 - if (Object.isFunction(replacement)) return replacement;
547 - var template = new Template(replacement);
548 - return function(match) { return template.evaluate(match) };
549 - };
550 -
551 - String.prototype.parseQuery = String.prototype.toQueryParams;
552 -
553 - Object.extend(String.prototype.escapeHTML, {
554 - div: document.createElement('div'),
555 - text: document.createTextNode('')
556 - });
557 -
558 - String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text);
559 -
560 - var Template = Class.create({
561 - initialize: function(template, pattern) {
562 - this.template = template.toString();
563 - this.pattern = pattern || Template.Pattern;
564 - },
565 -
566 - evaluate: function(object) {
567 - if (Object.isFunction(object.toTemplateReplacements))
568 - object = object.toTemplateReplacements();
569 -
570 - return this.template.gsub(this.pattern, function(match) {
571 - if (object == null) return '';
572 -
573 - var before = match[1] || '';
574 - if (before == '\\') return match[2];
575 -
576 - var ctx = object, expr = match[3];
577 - var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
578 - match = pattern.exec(expr);
579 - if (match == null) return before;
580 -
581 - while (match != null) {
582 - var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1];
583 - ctx = ctx[comp];
584 - if (null == ctx || '' == match[3]) break;
585 - expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
586 - match = pattern.exec(expr);
587 - }
588 -
589 - return before + String.interpret(ctx);
590 - });
591 - }
592 - });
593 - Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
594 -
595 - var $break = { };
596 -
597 - var Enumerable = {
598 - each: function(iterator, context) {
599 - var index = 0;
600 - try {
601 - this._each(function(value) {
602 - iterator.call(context, value, index++);
603 - });
604 - } catch (e) {
605 - if (e != $break) throw e;
606 - }
607 - return this;
608 - },
609 -
610 - eachSlice: function(number, iterator, context) {
611 - var index = -number, slices = [], array = this.toArray();
612 - if (number < 1) return array;
613 - while ((index += number) < array.length)
614 - slices.push(array.slice(index, index+number));
615 - return slices.collect(iterator, context);
616 - },
617 -
618 - all: function(iterator, context) {
619 - iterator = iterator || Prototype.K;
620 - var result = true;
621 - this.each(function(value, index) {
622 - result = result && !!iterator.call(context, value, index);
623 - if (!result) throw $break;
624 - });
625 - return result;
626 - },
627 -
628 - any: function(iterator, context) {
629 - iterator = iterator || Prototype.K;
630 - var result = false;
631 - this.each(function(value, index) {
632 - if (result = !!iterator.call(context, value, index))
633 - throw $break;
634 - });
635 - return result;
636 - },
637 -
638 - collect: function(iterator, context) {
639 - iterator = iterator || Prototype.K;
640 - var results = [];
641 - this.each(function(value, index) {
642 - results.push(iterator.call(context, value, index));
643 - });
644 - return results;
645 - },
646 -
647 - detect: function(iterator, context) {
648 - var result;
649 - this.each(function(value, index) {
650 - if (iterator.call(context, value, index)) {
651 - result = value;
652 - throw $break;
653 - }
654 - });
655 - return result;
656 - },
657 -
658 - findAll: function(iterator, context) {
659 - var results = [];
660 - this.each(function(value, index) {
661 - if (iterator.call(context, value, index))
662 - results.push(value);
663 - });
664 - return results;
665 - },
666 -
667 - grep: function(filter, iterator, context) {
668 - iterator = iterator || Prototype.K;
669 - var results = [];
670 -
671 - if (Object.isString(filter))
672 - filter = new RegExp(filter);
673 -
674 - this.each(function(value, index) {
675 - if (filter.match(value))
676 - results.push(iterator.call(context, value, index));
677 - });
678 - return results;
679 - },
680 -
681 - include: function(object) {
682 - if (Object.isFunction(this.indexOf))
683 - if (this.indexOf(object) != -1) return true;
684 -
685 - var found = false;
686 - this.each(function(value) {
687 - if (value == object) {
688 - found = true;
689 - throw $break;
690 - }
691 - });
692 - return found;
693 - },
694 -
695 - inGroupsOf: function(number, fillWith) {
696 - fillWith = Object.isUndefined(fillWith) ? null : fillWith;
697 - return this.eachSlice(number, function(slice) {
698 - while(slice.length < number) slice.push(fillWith);
699 - return slice;
700 - });
701 - },
702 -
703 - inject: function(memo, iterator, context) {
704 - this.each(function(value, index) {
705 - memo = iterator.call(context, memo, value, index);
706 - });
707 - return memo;
708 - },
709 -
710 - invoke: function(method) {
711 - var args = $A(arguments).slice(1);
712 - return this.map(function(value) {
713 - return value[method].apply(value, args);
714 - });
715 - },
716 -
717 - max: function(iterator, context) {
718 - iterator = iterator || Prototype.K;
719 - var result;
720 - this.each(function(value, index) {
721 - value = iterator.call(context, value, index);
722 - if (result == null || value >= result)
723 - result = value;
724 - });
725 - return result;
726 - },
727 -
728 - min: function(iterator, context) {
729 - iterator = iterator || Prototype.K;
730 - var result;
731 - this.each(function(value, index) {
732 - value = iterator.call(context, value, index);
733 - if (result == null || value < result)
734 - result = value;
735 - });
736 - return result;
737 - },
738 -
739 - partition: function(iterator, context) {
740 - iterator = iterator || Prototype.K;
741 - var trues = [], falses = [];
742 - this.each(function(value, index) {
743 - (iterator.call(context, value, index) ?
744 - trues : falses).push(value);
745 - });
746 - return [trues, falses];
747 - },
748 -
749 - pluck: function(property) {
750 - var results = [];
751 - this.each(function(value) {
752 - results.push(value[property]);
753 - });
754 - return results;
755 - },
756 -
757 - reject: function(iterator, context) {
758 - var results = [];
759 - this.each(function(value, index) {
760 - if (!iterator.call(context, value, index))
761 - results.push(value);
762 - });
763 - return results;
764 - },
765 -
766 - sortBy: function(iterator, context) {
767 - return this.map(function(value, index) {
768 - return {
769 - value: value,
770 - criteria: iterator.call(context, value, index)
771 - };
772 - }).sort(function(left, right) {
773 - var a = left.criteria, b = right.criteria;
774 - return a < b ? -1 : a > b ? 1 : 0;
775 - }).pluck('value');
776 - },
777 -
778 - toArray: function() {
779 - return this.map();
780 - },
781 -
782 - zip: function() {
783 - var iterator = Prototype.K, args = $A(arguments);
784 - if (Object.isFunction(args.last()))
785 - iterator = args.pop();
786 -
787 - var collections = [this].concat(args).map($A);
788 - return this.map(function(value, index) {
789 - return iterator(collections.pluck(index));
790 - });
791 - },
792 -
793 - size: function() {
794 - return this.toArray().length;
795 - },
796 -
797 - inspect: function() {
798 - return '#<Enumerable:' + this.toArray().inspect() + '>';
799 - }
800 - };
801 -
802 - Object.extend(Enumerable, {
803 - map: Enumerable.collect,
804 - find: Enumerable.detect,
805 - select: Enumerable.findAll,
806 - filter: Enumerable.findAll,
807 - member: Enumerable.include,
808 - entries: Enumerable.toArray,
809 - every: Enumerable.all,
810 - some: Enumerable.any
811 - });
812 - function $A(iterable) {
813 - if (!iterable) return [];
814 - if (iterable.toArray) return iterable.toArray();
815 - var length = iterable.length || 0, results = new Array(length);
816 - while (length--) results[length] = iterable[length];
817 - return results;
818 - }
819 -
820 - if (Prototype.Browser.WebKit) {
821 - $A = function(iterable) {
822 - if (!iterable) return [];
823 - // In Safari, only use the `toArray` method if it's not a NodeList.
824 - // A NodeList is a function, has an function `item` property, and a numeric
825 - // `length` property. Adapted from Google Doctype.
826 - if (!(typeof iterable === 'function' && typeof iterable.length ===
827 - 'number' && typeof iterable.item === 'function') && iterable.toArray)
828 - return iterable.toArray();
829 - var length = iterable.length || 0, results = new Array(length);
830 - while (length--) results[length] = iterable[length];
831 - return results;
832 - };
833 - }
834 -
835 - Array.from = $A;
836 -
837 - Object.extend(Array.prototype, Enumerable);
838 -
839 - if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse;
840 -
841 - Object.extend(Array.prototype, {
842 - _each: function(iterator) {
843 - for (var i = 0, length = this.length; i < length; i++)
844 - iterator(this[i]);
845 - },
846 -
847 - clear: function() {
848 - this.length = 0;
849 - return this;
850 - },
851 -
852 - first: function() {
853 - return this[0];
854 - },
855 -
856 - last: function() {
857 - return this[this.length - 1];
858 - },
859 -
860 - compact: function() {
861 - return this.select(function(value) {
862 - return value != null;
863 - });
864 - },
865 -
866 - flatten: function() {
867 - return this.inject([], function(array, value) {
868 - return array.concat(Object.isArray(value) ?
869 - value.flatten() : [value]);
870 - });
871 - },
872 -
873 - without: function() {
874 - var values = $A(arguments);
875 - return this.select(function(value) {
876 - return !values.include(value);
877 - });
878 - },
879 -
880 - reverse: function(inline) {
881 - return (inline !== false ? this : this.toArray())._reverse();
882 - },
883 -
884 - reduce: function() {
885 - return this.length > 1 ? this : this[0];
886 - },
887 -
888 - uniq: function(sorted) {
889 - return this.inject([], function(array, value, index) {
890 - if (0 == index || (sorted ? array.last() != value : !array.include(value)))
891 - array.push(value);
892 - return array;
893 - });
894 - },
895 -
896 - intersect: function(array) {
897 - return this.uniq().findAll(function(item) {
898 - return array.detect(function(value) { return item === value });
899 - });
900 - },
901 -
902 - clone: function() {
903 - return [].concat(this);
904 - },
905 -
906 - size: function() {
907 - return this.length;
908 - },
909 -
910 - inspect: function() {
911 - return '[' + this.map(Object.inspect).join(', ') + ']';
912 - },
913 -
914 - toJSON: function() {
915 - var results = [];
916 - this.each(function(object) {
917 - var value = Object.toJSON(object);
918 - if (!Object.isUndefined(value)) results.push(value);
919 - });
920 - return '[' + results.join(', ') + ']';
921 - }
922 - });
923 -
924 - // use native browser JS 1.6 implementation if available
925 - if (Object.isFunction(Array.prototype.forEach))
926 - Array.prototype._each = Array.prototype.forEach;
927 -
928 - if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) {
929 - i || (i = 0);
930 - var length = this.length;
931 - if (i < 0) i = length + i;
932 - for (; i < length; i++)
933 - if (this[i] === item) return i;
934 - return -1;
935 - };
936 -
937 - if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) {
938 - i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
939 - var n = this.slice(0, i).reverse().indexOf(item);
940 - return (n < 0) ? n : i - n - 1;
941 - };
942 -
943 - Array.prototype.toArray = Array.prototype.clone;
944 -
945 - function $w(string) {
946 - if (!Object.isString(string)) return [];
947 - string = string.strip();
948 - return string ? string.split(/\s+/) : [];
949 - }
950 -
951 - if (Prototype.Browser.Opera){
952 - Array.prototype.concat = function() {
953 - var array = [];
954 - for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
955 - for (var i = 0, length = arguments.length; i < length; i++) {
956 - if (Object.isArray(arguments[i])) {
957 - for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
958 - array.push(arguments[i][j]);
959 - } else {
960 - array.push(arguments[i]);
961 - }
962 - }
963 - return array;
964 - };
965 - }
966 - Object.extend(Number.prototype, {
967 - toColorPart: function() {
968 - return this.toPaddedString(2, 16);
969 - },
970 -
971 - succ: function() {
972 - return this + 1;
973 - },
974 -
975 - times: function(iterator, context) {
976 - $R(0, this, true).each(iterator, context);
977 - return this;
978 - },
979 -
980 - toPaddedString: function(length, radix) {
981 - var string = this.toString(radix || 10);
982 - return '0'.times(length - string.length) + string;
983 - },
984 -
985 - toJSON: function() {
986 - return isFinite(this) ? this.toString() : 'null';
987 - }
988 - });
989 -
990 - $w('abs round ceil floor').each(function(method){
991 - Number.prototype[method] = Math[method].methodize();
992 - });
993 - function $H(object) {
994 - return new Hash(object);
995 - };
996 -
997 - var Hash = Class.create(Enumerable, (function() {
998 -
999 - function toQueryPair(key, value) {
1000 - if (Object.isUndefined(value)) return key;
1001 - return key + '=' + encodeURIComponent(String.interpret(value));
1002 - }
1003 -
1004 - return {
1005 - initialize: function(object) {
1006 - this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
1007 - },
1008 -
1009 - _each: function(iterator) {
1010 - for (var key in this._object) {
1011 - var value = this._object[key], pair = [key, value];
1012 - pair.key = key;
1013 - pair.value = value;
1014 - iterator(pair);
1015 - }
1016 - },
1017 -
1018 - set: function(key, value) {
1019 - return this._object[key] = value;
1020 - },
1021 -
1022 - get: function(key) {
1023 - // simulating poorly supported hasOwnProperty
1024 - if (this._object[key] !== Object.prototype[key])
1025 - return this._object[key];
1026 - },
1027 -
1028 - unset: function(key) {
1029 - var value = this._object[key];
1030 - delete this._object[key];
1031 - return value;
1032 - },
1033 -
1034 - toObject: function() {
1035 - return Object.clone(this._object);
1036 - },
1037 -
1038 - keys: function() {
1039 - return this.pluck('key');
1040 - },
1041 -
1042 - values: function() {
1043 - return this.pluck('value');
1044 - },
1045 -
1046 - index: function(value) {
1047 - var match = this.detect(function(pair) {
1048 - return pair.value === value;
1049 - });
1050 - return match && match.key;
1051 - },
1052 -
1053 - merge: function(object) {
1054 - return this.clone().update(object);
1055 - },
1056 -
1057 - update: function(object) {
1058 - return new Hash(object).inject(this, function(result, pair) {
1059 - result.set(pair.key, pair.value);
1060 - return result;
1061 - });
1062 - },
1063 -
1064 - toQueryString: function() {
1065 - return this.inject([], function(results, pair) {
1066 - var key = encodeURIComponent(pair.key), values = pair.value;
1067 -
1068 - if (values && typeof values == 'object') {
1069 - if (Object.isArray(values))
1070 - return results.concat(values.map(toQueryPair.curry(key)));
1071 - } else results.push(toQueryPair(key, values));
1072 - return results;
1073 - }).join('&');
1074 - },
1075 -
1076 - inspect: function() {
1077 - return '#<Hash:{' + this.map(function(pair) {
1078 - return pair.map(Object.inspect).join(': ');
1079 - }).join(', ') + '}>';
1080 - },
1081 -
1082 - toJSON: function() {
1083 - return Object.toJSON(this.toObject());
1084 - },
1085 -
1086 - clone: function() {
1087 - return new Hash(this);
1088 - }
1089 - }
1090 - })());
1091 -
1092 - Hash.prototype.toTemplateReplacements = Hash.prototype.toObject;
1093 - Hash.from = $H;
1094 - var ObjectRange = Class.create(Enumerable, {
1095 - initialize: function(start, end, exclusive) {
1096 - this.start = start;
1097 - this.end = end;
1098 - this.exclusive = exclusive;
1099 - },
1100 -
1101 - _each: function(iterator) {
1102 - var value = this.start;
1103 - while (this.include(value)) {
1104 - iterator(value);
1105 - value = value.succ();
1106 - }
1107 - },
1108 -
1109 - include: function(value) {
1110 - if (value < this.start)
1111 - return false;
1112 - if (this.exclusive)
1113 - return value < this.end;
1114 - return value <= this.end;
1115 - }
1116 - });
1117 -
1118 - var $R = function(start, end, exclusive) {
1119 - return new ObjectRange(start, end, exclusive);
1120 - };
1121 -
1122 - var Ajax = {
1123 - getTransport: function() {
1124 - return Try.these(
1125 - function() {return new XMLHttpRequest()},
1126 - function() {return new ActiveXObject('Msxml2.XMLHTTP')},
1127 - function() {return new ActiveXObject('Microsoft.XMLHTTP')}
1128 - ) || false;
1129 - },
1130 -
1131 - activeRequestCount: 0
1132 - };
1133 -
1134 - Ajax.Responders = {
1135 - responders: [],
1136 -
1137 - _each: function(iterator) {
1138 - this.responders._each(iterator);
1139 - },
1140 -
1141 - register: function(responder) {
1142 - if (!this.include(responder))
1143 - this.responders.push(responder);
1144 - },
1145 -
1146 - unregister: function(responder) {
1147 - this.responders = this.responders.without(responder);
1148 - },
1149 -
1150 - dispatch: function(callback, request, transport, json) {
1151 - this.each(function(responder) {
1152 - if (Object.isFunction(responder[callback])) {
1153 - try {
1154 - responder[callback].apply(responder, [request, transport, json]);
1155 - } catch (e) { }
1156 - }
1157 - });
1158 - }
1159 - };
1160 -
1161 - Object.extend(Ajax.Responders, Enumerable);
1162 -
1163 - Ajax.Responders.register({
1164 - onCreate: function() { Ajax.activeRequestCount++ },
1165 - onComplete: function() { Ajax.activeRequestCount-- }
1166 - });
1167 -
1168 - Ajax.Base = Class.create({
1169 - initialize: function(options) {
1170 - this.options = {
1171 - method: 'post',
1172 - asynchronous: true,
1173 - contentType: 'application/x-www-form-urlencoded',
1174 - encoding: 'UTF-8',
1175 - parameters: '',
1176 - evalJSON: true,
1177 - evalJS: true
1178 - };
1179 - Object.extend(this.options, options || { });
1180 -
1181 - this.options.method = this.options.method.toLowerCase();
1182 -
1183 - if (Object.isString(this.options.parameters))
1184 - this.options.parameters = this.options.parameters.toQueryParams();
1185 - else if (Object.isHash(this.options.parameters))
1186 - this.options.parameters = this.options.parameters.toObject();
1187 - }
1188 - });
1189 -
1190 - Ajax.Request = Class.create(Ajax.Base, {
1191 - _complete: false,
1192 -
1193 - initialize: function($super, url, options) {
1194 - $super(options);
1195 - this.transport = Ajax.getTransport();
1196 - this.request(url);
1197 - },
1198 -
1199 - request: function(url) {
1200 - this.url = url;
1201 - this.method = this.options.method;
1202 - var params = Object.clone(this.options.parameters);
1203 -
1204 - if (!['get', 'post'].include(this.method)) {
1205 - // simulate other verbs over post
1206 - params['_method'] = this.method;
1207 - this.method = 'post';
1208 - }
1209 -
1210 - this.parameters = params;
1211 -
1212 - if (params = Object.toQueryString(params)) {
1213 - // when GET, append parameters to URL
1214 - if (this.method == 'get')
1215 - this.url += (this.url.include('?') ? '&' : '?') + params;
1216 - else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
1217 - params += '&_=';
1218 - }
1219 -
1220 - try {
1221 - var response = new Ajax.Response(this);
1222 - if (this.options.onCreate) this.options.onCreate(response);
1223 - Ajax.Responders.dispatch('onCreate', this, response);
1224 -
1225 - this.transport.open(this.method.toUpperCase(), this.url,
1226 - this.options.asynchronous);
1227 -
1228 - if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
1229 -
1230 - this.transport.onreadystatechange = this.onStateChange.bind(this);
1231 - this.setRequestHeaders();
1232 -
1233 - this.body = this.method == 'post' ? (this.options.postBody || params) : null;
1234 - this.transport.send(this.body);
1235 -
1236 - /* Force Firefox to handle ready state 4 for synchronous requests */
1237 - if (!this.options.asynchronous && this.transport.overrideMimeType)
1238 - this.onStateChange();
1239 -
1240 - }
1241 - catch (e) {
1242 - this.dispatchException(e);
1243 - }
1244 - },
1245 -
1246 - onStateChange: function() {
1247 - var readyState = this.transport.readyState;
1248 - if (readyState > 1 && !((readyState == 4) && this._complete))
1249 - this.respondToReadyState(this.transport.readyState);
1250 - },
1251 -
1252 - setRequestHeaders: function() {
1253 - var headers = {
1254 - 'X-Requested-With': 'XMLHttpRequest',
1255 - 'X-Prototype-Version': Prototype.Version,
1256 - 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
1257 - };
1258 -
1259 - if (this.method == 'post') {
1260 - headers['Content-type'] = this.options.contentType +
1261 - (this.options.encoding ? '; charset=' + this.options.encoding : '');
1262 -
1263 - /* Force "Connection: close" for older Mozilla browsers to work
1264 - * around a bug where XMLHttpRequest sends an incorrect
1265 - * Content-length header. See Mozilla Bugzilla #246651.
1266 - */
1267 - if (this.transport.overrideMimeType &&
1268 - (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
1269 - headers['Connection'] = 'close';
1270 - }
1271 -
1272 - // user-defined headers
1273 - if (typeof this.options.requestHeaders == 'object') {
1274 - var extras = this.options.requestHeaders;
1275 -
1276 - if (Object.isFunction(extras.push))
1277 - for (var i = 0, length = extras.length; i < length; i += 2)
1278 - headers[extras[i]] = extras[i+1];
1279 - else
1280 - $H(extras).each(function(pair) { headers[pair.key] = pair.value });
1281 - }
1282 -
1283 - for (var name in headers)
1284 - this.transport.setRequestHeader(name, headers[name]);
1285 - },
1286 -
1287 - success: function() {
1288 - var status = this.getStatus();
1289 - return !status || (status >= 200 && status < 300);
1290 - },
1291 -
1292 - getStatus: function() {
1293 - try {
1294 - return this.transport.status || 0;
1295 - } catch (e) { return 0 }
1296 - },
1297 -
1298 - respondToReadyState: function(readyState) {
1299 - var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);
1300 -
1301 - if (state == 'Complete') {
1302 - try {
1303 - this._complete = true;
1304 - (this.options['on' + response.status]
1305 - || this.options['on' + (this.success() ? 'Success' : 'Failure')]
1306 - || Prototype.emptyFunction)(response, response.headerJSON);
1307 - } catch (e) {
1308 - this.dispatchException(e);
1309 - }
1310 -
1311 - var contentType = response.getHeader('Content-type');
1312 - if (this.options.evalJS == 'force'
1313 - || (this.options.evalJS && this.isSameOrigin() && contentType
1314 - && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
1315 - this.evalResponse();
1316 - }
1317 -
1318 - try {
1319 - (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
1320 - Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
1321 - } catch (e) {
1322 - this.dispatchException(e);
1323 - }
1324 -
1325 - if (state == 'Complete') {
1326 - // avoid memory leak in MSIE: clean up
1327 - this.transport.onreadystatechange = Prototype.emptyFunction;
1328 - }
1329 - },
1330 -
1331 - isSameOrigin: function() {
1332 - var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
1333 - return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
1334 - protocol: location.protocol,
1335 - domain: document.domain,
1336 - port: location.port ? ':' + location.port : ''
1337 - }));
1338 - },
1339 -
1340 - getHeader: function(name) {
1341 - try {
1342 - return this.transport.getResponseHeader(name) || null;
1343 - } catch (e) { return null }
1344 - },
1345 -
1346 - evalResponse: function() {
1347 - try {
1348 - return eval((this.transport.responseText || '').unfilterJSON());
1349 - } catch (e) {
1350 - this.dispatchException(e);
1351 - }
1352 - },
1353 -
1354 - dispatchException: function(exception) {
1355 - (this.options.onException || Prototype.emptyFunction)(this, exception);
1356 - Ajax.Responders.dispatch('onException', this, exception);
1357 - }
1358 - });
1359 -
1360 - Ajax.Request.Events =
1361 - ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
1362 -
1363 - Ajax.Response = Class.create({
1364 - initialize: function(request){
1365 - this.request = request;
1366 - var transport = this.transport = request.transport,
1367 - readyState = this.readyState = transport.readyState;
1368 -
1369 - if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
1370 - this.status = this.getStatus();
1371 - this.statusText = this.getStatusText();
1372 - this.responseText = String.interpret(transport.responseText);
1373 - this.headerJSON = this._getHeaderJSON();
1374 - }
1375 -
1376 - if(readyState == 4) {
1377 - var xml = transport.responseXML;
1378 - this.responseXML = Object.isUndefined(xml) ? null : xml;
1379 - this.responseJSON = this._getResponseJSON();
1380 - }
1381 - },
1382 -
1383 - status: 0,
1384 - statusText: '',
1385 -
1386 - getStatus: Ajax.Request.prototype.getStatus,
1387 -
1388 - getStatusText: function() {
1389 - try {
1390 - return this.transport.statusText || '';
1391 - } catch (e) { return '' }
1392 - },
1393 -
1394 - getHeader: Ajax.Request.prototype.getHeader,
1395 -
1396 - getAllHeaders: function() {
1397 - try {
1398 - return this.getAllResponseHeaders();
1399 - } catch (e) { return null }
1400 - },
1401 -
1402 - getResponseHeader: function(name) {
1403 - return this.transport.getResponseHeader(name);
1404 - },
1405 -
1406 - getAllResponseHeaders: function() {
1407 - return this.transport.getAllResponseHeaders();
1408 - },
1409 -
1410 - _getHeaderJSON: function() {
1411 - var json = this.getHeader('X-JSON');
1412 - if (!json) return null;
1413 - json = decodeURIComponent(escape(json));
1414 - try {
1415 - return json.evalJSON(this.request.options.sanitizeJSON ||
1416 - !this.request.isSameOrigin());
1417 - } catch (e) {
1418 - this.request.dispatchException(e);
1419 - }
1420 - },
1421 -
1422 - _getResponseJSON: function() {
1423 - var options = this.request.options;
1424 - if (!options.evalJSON || (options.evalJSON != 'force' &&
1425 - !(this.getHeader('Content-type') || '').include('application/json')) ||
1426 - this.responseText.blank())
1427 - return null;
1428 - try {
1429 - return this.responseText.evalJSON(options.sanitizeJSON ||
1430 - !this.request.isSameOrigin());
1431 - } catch (e) {
1432 - this.request.dispatchException(e);
1433 - }
1434 - }
1435 - });
1436 -
1437 - Ajax.Updater = Class.create(Ajax.Request, {
1438 - initialize: function($super, container, url, options) {
1439 - this.container = {
1440 - success: (container.success || container),
1441 - failure: (container.failure || (container.success ? null : container))
1442 - };
1443 -
1444 - options = Object.clone(options);
1445 - var onComplete = options.onComplete;
1446 - options.onComplete = (function(response, json) {
1447 - this.updateContent(response.responseText);
1448 - if (Object.isFunction(onComplete)) onComplete(response, json);
1449 - }).bind(this);
1450 -
1451 - $super(url, options);
1452 - },
1453 -
1454 - updateContent: function(responseText) {
1455 - var receiver = this.container[this.success() ? 'success' : 'failure'],
1456 - options = this.options;
1457 -
1458 - if (!options.evalScripts) responseText = responseText.stripScripts();
1459 -
1460 - if (receiver = $(receiver)) {
1461 - if (options.insertion) {
1462 - if (Object.isString(options.insertion)) {
1463 - var insertion = { }; insertion[options.insertion] = responseText;
1464 - receiver.insert(insertion);
1465 - }
1466 - else options.insertion(receiver, responseText);
1467 - }
1468 - else receiver.update(responseText);
1469 - }
1470 - }
1471 - });
1472 -
1473 - Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
1474 - initialize: function($super, container, url, options) {
1475 - $super(options);
1476 - this.onComplete = this.options.onComplete;
1477 -
1478 - this.frequency = (this.options.frequency || 2);
1479 - this.decay = (this.options.decay || 1);
1480 -
1481 - this.updater = { };
1482 - this.container = container;
1483 - this.url = url;
1484 -
1485 - this.start();
1486 - },
1487 -
1488 - start: function() {
1489 - this.options.onComplete = this.updateComplete.bind(this);
1490 - this.onTimerEvent();
1491 - },
1492 -
1493 - stop: function() {
1494 - this.updater.options.onComplete = undefined;
1495 - clearTimeout(this.timer);
1496 - (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
1497 - },
1498 -
1499 - updateComplete: function(response) {
1500 - if (this.options.decay) {
1501 - this.decay = (response.responseText == this.lastText ?
1502 - this.decay * this.options.decay : 1);
1503 -
1504 - this.lastText = response.responseText;
1505 - }
1506 - this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
1507 - },
1508 -
1509 - onTimerEvent: function() {
1510 - this.updater = new Ajax.Updater(this.container, this.url, this.options);
1511 - }
1512 - });
1513 - function $(element) {
1514 - if (arguments.length > 1) {
1515 - for (var i = 0, elements = [], length = arguments.length; i < length; i++)
1516 - elements.push($(arguments[i]));
1517 - return elements;
1518 - }
1519 - if (Object.isString(element))
1520 - element = document.getElementById(element);
1521 - return Element.extend(element);
1522 - }
1523 -
1524 - if (Prototype.BrowserFeatures.XPath) {
1525 - document._getElementsByXPath = function(expression, parentElement) {
1526 - var results = [];
1527 - var query = document.evaluate(expression, $(parentElement) || document,
1528 - null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
1529 - for (var i = 0, length = query.snapshotLength; i < length; i++)
1530 - results.push(Element.extend(query.snapshotItem(i)));
1531 - return results;
1532 - };
1533 - }
1534 -
1535 - /*--------------------------------------------------------------------------*/
1536 -
1537 - if (!window.Node) var Node = { };
1538 -
1539 - if (!Node.ELEMENT_NODE) {
1540 - // DOM level 2 ECMAScript Language Binding
1541 - Object.extend(Node, {
1542 - ELEMENT_NODE: 1,
1543 - ATTRIBUTE_NODE: 2,
1544 - TEXT_NODE: 3,
1545 - CDATA_SECTION_NODE: 4,
1546 - ENTITY_REFERENCE_NODE: 5,
1547 - ENTITY_NODE: 6,
1548 - PROCESSING_INSTRUCTION_NODE: 7,
1549 - COMMENT_NODE: 8,
1550 - DOCUMENT_NODE: 9,
1551 - DOCUMENT_TYPE_NODE: 10,
1552 - DOCUMENT_FRAGMENT_NODE: 11,
1553 - NOTATION_NODE: 12
1554 - });
1555 - }
1556 -
1557 - (function() {
1558 - var element = this.Element;
1559 - this.Element = function(tagName, attributes) {
1560 - attributes = attributes || { };
1561 - tagName = tagName.toLowerCase();
1562 - var cache = Element.cache;
1563 - if (Prototype.Browser.IE && attributes.name) {
1564 - tagName = '<' + tagName + ' name="' + attributes.name + '">';
1565 - delete attributes.name;
1566 - return Element.writeAttribute(document.createElement(tagName), attributes);
1567 - }
1568 - if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
1569 - return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
1570 - };
1571 - Object.extend(this.Element, element || { });
1572 - if (element) this.Element.prototype = element.prototype;
1573 - }).call(window);
1574 -
1575 - Element.cache = { };
1576 -
1577 - Element.Methods = {
1578 - visible: function(element) {
1579 - return $(element).style.display != 'none';
1580 - },
1581 -
1582 - toggle: function(element) {
1583 - element = $(element);
1584 - Element[Element.visible(element) ? 'hide' : 'show'](element);
1585 - return element;
1586 - },
1587 -
1588 - hide: function(element) {
1589 - element = $(element);
1590 - element.style.display = 'none';
1591 - return element;
1592 - },
1593 -
1594 - show: function(element) {
1595 - element = $(element);
1596 - element.style.display = '';
1597 - return element;
1598 - },
1599 -
1600 - remove: function(element) {
1601 - element = $(element);
1602 - element.parentNode.removeChild(element);
1603 - return element;
1604 - },
1605 -
1606 - update: function(element, content) {
1607 - element = $(element);
1608 - if (content && content.toElement) content = content.toElement();
1609 - if (Object.isElement(content)) return element.update().insert(content);
1610 - content = Object.toHTML(content);
1611 - element.innerHTML = content.stripScripts();
1612 - content.evalScripts.bind(content).defer();
1613 - return element;
1614 - },
1615 -
1616 - replace: function(element, content) {
1617 - element = $(element);
1618 - if (content && content.toElement) content = content.toElement();
1619 - else if (!Object.isElement(content)) {
1620 - content = Object.toHTML(content);
1621 - var range = element.ownerDocument.createRange();
1622 - range.selectNode(element);
1623 - content.evalScripts.bind(content).defer();
1624 - content = range.createContextualFragment(content.stripScripts());
1625 - }
1626 - element.parentNode.replaceChild(content, element);
1627 - return element;
1628 - },
1629 -
1630 - insert: function(element, insertions) {
1631 - element = $(element);
1632 -
1633 - if (Object.isString(insertions) || Object.isNumber(insertions) ||
1634 - Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
1635 - insertions = {bottom:insertions};
1636 -
1637 - var content, insert, tagName, childNodes;
1638 -
1639 - for (var position in insertions) {
1640 - content = insertions[position];
1641 - position = position.toLowerCase();
1642 - insert = Element._insertionTranslations[position];
1643 -
1644 - if (content && content.toElement) content = content.toElement();
1645 - if (Object.isElement(content)) {
1646 - insert(element, content);
1647 - continue;
1648 - }
1649 -
1650 - content = Object.toHTML(content);
1651 -
1652 - tagName = ((position == 'before' || position == 'after')
1653 - ? element.parentNode : element).tagName.toUpperCase();
1654 -
1655 - childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
1656 -
1657 - if (position == 'top' || position == 'after') childNodes.reverse();
1658 - childNodes.each(insert.curry(element));
1659 -
1660 - content.evalScripts.bind(content).defer();
1661 - }
1662 -
1663 - return element;
1664 - },
1665 -
1666 - wrap: function(element, wrapper, attributes) {
1667 - element = $(element);
1668 - if (Object.isElement(wrapper))
1669 - $(wrapper).writeAttribute(attributes || { });
1670 - else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);
1671 - else wrapper = new Element('div', wrapper);
1672 - if (element.parentNode)
1673 - element.parentNode.replaceChild(wrapper, element);
1674 - wrapper.appendChild(element);
1675 - return wrapper;
1676 - },
1677 -
1678 - inspect: function(element) {
1679 - element = $(element);
1680 - var result = '<' + element.tagName.toLowerCase();
1681 - $H({'id': 'id', 'className': 'class'}).each(function(pair) {
1682 - var property = pair.first(), attribute = pair.last();
1683 - var value = (element[property] || '').toString();
1684 - if (value) result += ' ' + attribute + '=' + value.inspect(true);
1685 - });
1686 - return result + '>';
1687 - },
1688 -
1689 - recursivelyCollect: function(element, property) {
1690 - element = $(element);
1691 - var elements = [];
1692 - while (element = element[property])
1693 - if (element.nodeType == 1)
1694 - elements.push(Element.extend(element));
1695 - return elements;
1696 - },
1697 -
1698 - ancestors: function(element) {
1699 - return $(element).recursivelyCollect('parentNode');
1700 - },
1701 -
1702 - descendants: function(element) {
1703 - return $(element).select("*");
1704 - },
1705 -
1706 - firstDescendant: function(element) {
1707 - element = $(element).firstChild;
1708 - while (element && element.nodeType != 1) element = element.nextSibling;
1709 - return $(element);
1710 - },
1711 -
1712 - immediateDescendants: function(element) {
1713 - if (!(element = $(element).firstChild)) return [];
1714 - while (element && element.nodeType != 1) element = element.nextSibling;
1715 - if (element) return [element].concat($(element).nextSiblings());
1716 - return [];
1717 - },
1718 -
1719 - previousSiblings: function(element) {
1720 - return $(element).recursivelyCollect('previousSibling');
1721 - },
1722 -
1723 - nextSiblings: function(element) {
1724 - return $(element).recursivelyCollect('nextSibling');
1725 - },
1726 -
1727 - siblings: function(element) {
1728 - element = $(element);
1729 - return element.previousSiblings().reverse().concat(element.nextSiblings());
1730 - },
1731 -
1732 - match: function(element, selector) {
1733 - if (Object.isString(selector))
1734 - selector = new Selector(selector);
1735 - return selector.match($(element));
1736 - },
1737 -
1738 - up: function(element, expression, index) {
1739 - element = $(element);
1740 - if (arguments.length == 1) return $(element.parentNode);
1741 - var ancestors = element.ancestors();
1742 - return Object.isNumber(expression) ? ancestors[expression] :
1743 - Selector.findElement(ancestors, expression, index);
1744 - },
1745 -
1746 - down: function(element, expression, index) {
1747 - element = $(element);
1748 - if (arguments.length == 1) return element.firstDescendant();
1749 - return Object.isNumber(expression) ? element.descendants()[expression] :
1750 - Element.select(element, expression)[index || 0];
1751 - },
1752 -
1753 - previous: function(element, expression, index) {
1754 - element = $(element);
1755 - if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
1756 - var previousSiblings = element.previousSiblings();
1757 - return Object.isNumber(expression) ? previousSiblings[expression] :
1758 - Selector.findElement(previousSiblings, expression, index);
1759 - },
1760 -
1761 - next: function(element, expression, index) {
1762 - element = $(element);
1763 - if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
1764 - var nextSiblings = element.nextSiblings();
1765 - return Object.isNumber(expression) ? nextSiblings[expression] :
1766 - Selector.findElement(nextSiblings, expression, index);
1767 - },
1768 -
1769 - select: function() {
1770 - var args = $A(arguments), element = $(args.shift());
1771 - return Selector.findChildElements(element, args);
1772 - },
1773 -
1774 - adjacent: function() {
1775 - var args = $A(arguments), element = $(args.shift());
1776 - return Selector.findChildElements(element.parentNode, args).without(element);
1777 - },
1778 -
1779 - identify: function(element) {
1780 - element = $(element);
1781 - var id = element.readAttribute('id'), self = arguments.callee;
1782 - if (id) return id;
1783 - do { id = 'anonymous_element_' + self.counter++ } while ($(id));
1784 - element.writeAttribute('id', id);
1785 - return id;
1786 - },
1787 -
1788 - readAttribute: function(element, name) {
1789 - element = $(element);
1790 - if (Prototype.Browser.IE) {
1791 - var t = Element._attributeTranslations.read;
1792 - if (t.values[name]) return t.values[name](element, name);
1793 - if (t.names[name]) name = t.names[name];
1794 - if (name.include(':')) {
1795 - return (!element.attributes || !element.attributes[name]) ? null :
1796 - element.attributes[name].value;
1797 - }
1798 - }
1799 - return element.getAttribute(name);
1800 - },
1801 -
1802 - writeAttribute: function(element, name, value) {
1803 - element = $(element);
1804 - var attributes = { }, t = Element._attributeTranslations.write;
1805 -
1806 - if (typeof name == 'object') attributes = name;
1807 - else attributes[name] = Object.isUndefined(value) ? true : value;
1808 -
1809 - for (var attr in attributes) {
1810 - name = t.names[attr] || attr;
1811 - value = attributes[attr];
1812 - if (t.values[attr]) name = t.values[attr](element, value);
1813 - if (value === false || value === null)
1814 - element.removeAttribute(name);
1815 - else if (value === true)
1816 - element.setAttribute(name, name);
1817 - else element.setAttribute(name, value);
1818 - }
1819 - return element;
1820 - },
1821 -
1822 - getHeight: function(element) {
1823 - return $(element).getDimensions().height;
1824 - },
1825 -
1826 - getWidth: function(element) {
1827 - return $(element).getDimensions().width;
1828 - },
1829 -
1830 - classNames: function(element) {
1831 - return new Element.ClassNames(element);
1832 - },
1833 -
1834 - hasClassName: function(element, className) {
1835 - if (!(element = $(element))) return;
1836 - var elementClassName = element.className;
1837 - return (elementClassName.length > 0 && (elementClassName == className ||
1838 - new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
1839 - },
1840 -
1841 - addClassName: function(element, className) {
1842 - if (!(element = $(element))) return;
1843 - if (!element.hasClassName(className))
1844 - element.className += (element.className ? ' ' : '') + className;
1845 - return element;
1846 - },
1847 -
1848 - removeClassName: function(element, className) {
1849 - if (!(element = $(element))) return;
1850 - element.className = element.className.replace(
1851 - new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
1852 - return element;
1853 - },
1854 -
1855 - toggleClassName: function(element, className) {
1856 - if (!(element = $(element))) return;
1857 - return element[element.hasClassName(className) ?
1858 - 'removeClassName' : 'addClassName'](className);
1859 - },
1860 -
1861 - // removes whitespace-only text node children
1862 - cleanWhitespace: function(element) {
1863 - element = $(element);
1864 - var node = element.firstChild;
1865 - while (node) {
1866 - var nextNode = node.nextSibling;
1867 - if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
1868 - element.removeChild(node);
1869 - node = nextNode;
1870 - }
1871 - return element;
1872 - },
1873 -
1874 - empty: function(element) {
1875 - return $(element).innerHTML.blank();
1876 - },
1877 -
1878 - descendantOf: function(element, ancestor) {
1879 - element = $(element), ancestor = $(ancestor);
1880 -
1881 - if (element.compareDocumentPosition)
1882 - return (element.compareDocumentPosition(ancestor) & 8) === 8;
1883 -
1884 - if (ancestor.contains)
1885 - return ancestor.contains(element) && ancestor !== element;
1886 -
1887 - while (element = element.parentNode)
1888 - if (element == ancestor) return true;
1889 -
1890 - return false;
1891 - },
1892 -
1893 - scrollTo: function(element) {
1894 - element = $(element);
1895 - var pos = element.cumulativeOffset();
1896 - window.scrollTo(pos[0], pos[1]);
1897 - return element;
1898 - },
1899 -
1900 - getStyle: function(element, style) {
1901 - element = $(element);
1902 - style = style == 'float' ? 'cssFloat' : style.camelize();
1903 - var value = element.style[style];
1904 - if (!value || value == 'auto') {
1905 - var css = document.defaultView.getComputedStyle(element, null);
1906 - value = css ? css[style] : null;
1907 - }
1908 - if (style == 'opacity') return value ? parseFloat(value) : 1.0;
1909 - return value == 'auto' ? null : value;
1910 - },
1911 -
1912 - getOpacity: function(element) {
1913 - return $(element).getStyle('opacity');
1914 - },
1915 -
1916 - setStyle: function(element, styles) {
1917 - element = $(element);
1918 - var elementStyle = element.style, match;
1919 - if (Object.isString(styles)) {
1920 - element.style.cssText += ';' + styles;
1921 - return styles.include('opacity') ?
1922 - element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
1923 - }
1924 - for (var property in styles)
1925 - if (property == 'opacity') element.setOpacity(styles[property]);
1926 - else
1927 - elementStyle[(property == 'float' || property == 'cssFloat') ?
1928 - (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
1929 - property] = styles[property];
1930 -
1931 - return element;
1932 - },
1933 -
1934 - setOpacity: function(element, value) {
1935 - element = $(element);
1936 - element.style.opacity = (value == 1 || value === '') ? '' :
1937 - (value < 0.00001) ? 0 : value;
1938 - return element;
1939 - },
1940 -
1941 - getDimensions: function(element) {
1942 - element = $(element);
1943 - var display = element.getStyle('display');
1944 - if (display != 'none' && display != null) // Safari bug
1945 - return {width: element.offsetWidth, height: element.offsetHeight};
1946 -
1947 - // All *Width and *Height properties give 0 on elements with display none,
1948 - // so enable the element temporarily
1949 - var els = element.style;
1950 - var originalVisibility = els.visibility;
1951 - var originalPosition = els.position;
1952 - var originalDisplay = els.display;
1953 - els.visibility = 'hidden';
1954 - els.position = 'absolute';
1955 - els.display = 'block';
1956 - var originalWidth = element.clientWidth;
1957 - var originalHeight = element.clientHeight;
1958 - els.display = originalDisplay;
1959 - els.position = originalPosition;
1960 - els.visibility = originalVisibility;
1961 - return {width: originalWidth, height: originalHeight};
1962 - },
1963 -
1964 - makePositioned: function(element) {
1965 - element = $(element);
1966 - var pos = Element.getStyle(element, 'position');
1967 - if (pos == 'static' || !pos) {
1968 - element._madePositioned = true;
1969 - element.style.position = 'relative';
1970 - // Opera returns the offset relative to the positioning context, when an
1971 - // element is position relative but top and left have not been defined
1972 - if (Prototype.Browser.Opera) {
1973 - element.style.top = 0;
1974 - element.style.left = 0;
1975 - }
1976 - }
1977 - return element;
1978 - },
1979 -
1980 - undoPositioned: function(element) {
1981 - element = $(element);
1982 - if (element._madePositioned) {
1983 - element._madePositioned = undefined;
1984 - element.style.position =
1985 - element.style.top =
1986 - element.style.left =
1987 - element.style.bottom =
1988 - element.style.right = '';
1989 - }
1990 - return element;
1991 - },
1992 -
1993 - makeClipping: function(element) {
1994 - element = $(element);
1995 - if (element._overflow) return element;
1996 - element._overflow = Element.getStyle(element, 'overflow') || 'auto';
1997 - if (element._overflow !== 'hidden')
1998 - element.style.overflow = 'hidden';
1999 - return element;
2000 - },
2001 -
2002 - undoClipping: function(element) {
2003 - element = $(element);
2004 - if (!element._overflow) return element;
2005 - element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
2006 - element._overflow = null;
2007 - return element;
2008 - },
2009 -
2010 - cumulativeOffset: function(element) {
2011 - var valueT = 0, valueL = 0;
2012 - do {
2013 - valueT += element.offsetTop || 0;
2014 - valueL += element.offsetLeft || 0;
2015 - element = element.offsetParent;
2016 - } while (element);
2017 - return Element._returnOffset(valueL, valueT);
2018 - },
2019 -
2020 - positionedOffset: function(element) {
2021 - var valueT = 0, valueL = 0;
2022 - do {
2023 - valueT += element.offsetTop || 0;
2024 - valueL += element.offsetLeft || 0;
2025 - element = element.offsetParent;
2026 - if (element) {
2027 - if (element.tagName.toUpperCase() == 'BODY') break;
2028 - var p = Element.getStyle(element, 'position');
2029 - if (p !== 'static') break;
2030 - }
2031 - } while (element);
2032 - return Element._returnOffset(valueL, valueT);
2033 - },
2034 -
2035 - absolutize: function(element) {
2036 - element = $(element);
2037 - if (element.getStyle('position') == 'absolute') return element;
2038 - // Position.prepare(); // To be done manually by Scripty when it needs it.
2039 -
2040 - var offsets = element.positionedOffset();
2041 - var top = offsets[1];
2042 - var left = offsets[0];
2043 - var width = element.clientWidth;
2044 - var height = element.clientHeight;
2045 -
2046 - element._originalLeft = left - parseFloat(element.style.left || 0);
2047 - element._originalTop = top - parseFloat(element.style.top || 0);
2048 - element._originalWidth = element.style.width;
2049 - element._originalHeight = element.style.height;
2050 -
2051 - element.style.position = 'absolute';
2052 - element.style.top = top + 'px';
2053 - element.style.left = left + 'px';
2054 - element.style.width = width + 'px';
2055 - element.style.height = height + 'px';
2056 - return element;
2057 - },
2058 -
2059 - relativize: function(element) {
2060 - element = $(element);
2061 - if (element.getStyle('position') == 'relative') return element;
2062 - // Position.prepare(); // To be done manually by Scripty when it needs it.
2063 -
2064 - element.style.position = 'relative';
2065 - var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
2066 - var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
2067 -
2068 - element.style.top = top + 'px';
2069 - element.style.left = left + 'px';
2070 - element.style.height = element._originalHeight;
2071 - element.style.width = element._originalWidth;
2072 - return element;
2073 - },
2074 -
2075 - cumulativeScrollOffset: function(element) {
2076 - var valueT = 0, valueL = 0;
2077 - do {
2078 - valueT += element.scrollTop || 0;
2079 - valueL += element.scrollLeft || 0;
2080 - element = element.parentNode;
2081 - } while (element);
2082 - return Element._returnOffset(valueL, valueT);
2083 - },
2084 -
2085 - getOffsetParent: function(element) {
2086 - if (element.offsetParent) return $(element.offsetParent);
2087 - if (element == document.body) return $(element);
2088 -
2089 - while ((element = element.parentNode) && element != document.body)
2090 - if (Element.getStyle(element, 'position') != 'static')
2091 - return $(element);
2092 -
2093 - return $(document.body);
2094 - },
2095 -
2096 - viewportOffset: function(forElement) {
2097 - var valueT = 0, valueL = 0;
2098 -
2099 - var element = forElement;
2100 - do {
2101 - valueT += element.offsetTop || 0;
2102 - valueL += element.offsetLeft || 0;
2103 -
2104 - // Safari fix
2105 - if (element.offsetParent == document.body &&
2106 - Element.getStyle(element, 'position') == 'absolute') break;
2107 -
2108 - } while (element = element.offsetParent);
2109 -
2110 - element = forElement;
2111 - do {
2112 - if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) {
2113 - valueT -= element.scrollTop || 0;
2114 - valueL -= element.scrollLeft || 0;
2115 - }
2116 - } while (element = element.parentNode);
2117 -
2118 - return Element._returnOffset(valueL, valueT);
2119 - },
2120 -
2121 - clonePosition: function(element, source) {
2122 - var options = Object.extend({
2123 - setLeft: true,
2124 - setTop: true,
2125 - setWidth: true,
2126 - setHeight: true,
2127 - offsetTop: 0,
2128 - offsetLeft: 0
2129 - }, arguments[2] || { });
2130 -
2131 - // find page position of source
2132 - source = $(source);
2133 - var p = source.viewportOffset();
2134 -
2135 - // find coordinate system to use
2136 - element = $(element);
2137 - var delta = [0, 0];
2138 - var parent = null;
2139 - // delta [0,0] will do fine with position: fixed elements,
2140 - // position:absolute needs offsetParent deltas
2141 - if (Element.getStyle(element, 'position') == 'absolute') {
2142 - parent = element.getOffsetParent();
2143 - delta = parent.viewportOffset();
2144 - }
2145 -
2146 - // correct by body offsets (fixes Safari)
2147 - if (parent == document.body) {
2148 - delta[0] -= document.body.offsetLeft;
2149 - delta[1] -= document.body.offsetTop;
2150 - }
2151 -
2152 - // set position
2153 - if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
2154 - if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
2155 - if (options.setWidth) element.style.width = source.offsetWidth + 'px';
2156 - if (options.setHeight) element.style.height = source.offsetHeight + 'px';
2157 - return element;
2158 - }
2159 - };
2160 -
2161 - Element.Methods.identify.counter = 1;
2162 -
2163 - Object.extend(Element.Methods, {
2164 - getElementsBySelector: Element.Methods.select,
2165 - childElements: Element.Methods.immediateDescendants
2166 - });
2167 -
2168 - Element._attributeTranslations = {
2169 - write: {
2170 - names: {
2171 - className: 'class',
2172 - htmlFor: 'for'
2173 - },
2174 - values: { }
2175 - }
2176 - };
2177 -
2178 - if (Prototype.Browser.Opera) {
2179 - Element.Methods.getStyle = Element.Methods.getStyle.wrap(
2180 - function(proceed, element, style) {
2181 - switch (style) {
2182 - case 'left': case 'top': case 'right': case 'bottom':
2183 - if (proceed(element, 'position') === 'static') return null;
2184 - case 'height': case 'width':
2185 - // returns '0px' for hidden elements; we want it to return null
2186 - if (!Element.visible(element)) return null;
2187 -
2188 - // returns the border-box dimensions rather than the content-box
2189 - // dimensions, so we subtract padding and borders from the value
2190 - var dim = parseInt(proceed(element, style), 10);
2191 -
2192 - if (dim !== element['offset' + style.capitalize()])
2193 - return dim + 'px';
2194 -
2195 - var properties;
2196 - if (style === 'height') {
2197 - properties = ['border-top-width', 'padding-top',
2198 - 'padding-bottom', 'border-bottom-width'];
2199 - }
2200 - else {
2201 - properties = ['border-left-width', 'padding-left',
2202 - 'padding-right', 'border-right-width'];
2203 - }
2204 - return properties.inject(dim, function(memo, property) {
2205 - var val = proceed(element, property);
2206 - return val === null ? memo : memo - parseInt(val, 10);
2207 - }) + 'px';
2208 - default: return proceed(element, style);
2209 - }
2210 - }
2211 - );
2212 -
2213 - Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
2214 - function(proceed, element, attribute) {
2215 - if (attribute === 'title') return element.title;
2216 - return proceed(element, attribute);
2217 - }
2218 - );
2219 - }
2220 -
2221 - else if (Prototype.Browser.IE) {
2222 - // IE doesn't report offsets correctly for static elements, so we change them
2223 - // to "relative" to get the values, then change them back.
2224 - Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(
2225 - function(proceed, element) {
2226 - element = $(element);
2227 - // IE throws an error if element is not in document
2228 - try { element.offsetParent }
2229 - catch(e) { return $(document.body) }
2230 - var position = element.getStyle('position');
2231 - if (position !== 'static') return proceed(element);
2232 - element.setStyle({ position: 'relative' });
2233 - var value = proceed(element);
2234 - element.setStyle({ position: position });
2235 - return value;
2236 - }
2237 - );
2238 -
2239 - $w('positionedOffset viewportOffset').each(function(method) {
2240 - Element.Methods[method] = Element.Methods[method].wrap(
2241 - function(proceed, element) {
2242 - element = $(element);
2243 - try { element.offsetParent }
2244 - catch(e) { return Element._returnOffset(0,0) }
2245 - var position = element.getStyle('position');
2246 - if (position !== 'static') return proceed(element);
2247 - // Trigger hasLayout on the offset parent so that IE6 reports
2248 - // accurate offsetTop and offsetLeft values for position: fixed.
2249 - var offsetParent = element.getOffsetParent();
2250 - if (offsetParent && offsetParent.getStyle('position') === 'fixed')
2251 - offsetParent.setStyle({ zoom: 1 });
2252 - element.setStyle({ position: 'relative' });
2253 - var value = proceed(element);
2254 - element.setStyle({ position: position });
2255 - return value;
2256 - }
2257 - );
2258 - });
2259 -
2260 - Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap(
2261 - function(proceed, element) {
2262 - try { element.offsetParent }
2263 - catch(e) { return Element._returnOffset(0,0) }
2264 - return proceed(element);
2265 - }
2266 - );
2267 -
2268 - Element.Methods.getStyle = function(element, style) {
2269 - element = $(element);
2270 - style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
2271 - var value = element.style[style];
2272 - if (!value && element.currentStyle) value = element.currentStyle[style];
2273 -
2274 - if (style == 'opacity') {
2275 - if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
2276 - if (value[1]) return parseFloat(value[1]) / 100;
2277 - return 1.0;
2278 - }
2279 -
2280 - if (value == 'auto') {
2281 - if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
2282 - return element['offset' + style.capitalize()] + 'px';
2283 - return null;
2284 - }
2285 - return value;
2286 - };
2287 -
2288 - Element.Methods.setOpacity = function(element, value) {
2289 - function stripAlpha(filter){
2290 - return filter.replace(/alpha\([^\)]*\)/gi,'');
2291 - }
2292 - element = $(element);
2293 - var currentStyle = element.currentStyle;
2294 - if ((currentStyle && !currentStyle.hasLayout) ||
2295 - (!currentStyle && element.style.zoom == 'normal'))
2296 - element.style.zoom = 1;
2297 -
2298 - var filter = element.getStyle('filter'), style = element.style;
2299 - if (value == 1 || value === '') {
2300 - (filter = stripAlpha(filter)) ?
2301 - style.filter = filter : style.removeAttribute('filter');
2302 - return element;
2303 - } else if (value < 0.00001) value = 0;
2304 - style.filter = stripAlpha(filter) +
2305 - 'alpha(opacity=' + (value * 100) + ')';
2306 - return element;
2307 - };
2308 -
2309 - Element._attributeTranslations = {
2310 - read: {
2311 - names: {
2312 - 'class': 'className',
2313 - 'for': 'htmlFor'
2314 - },
2315 - values: {
2316 - _getAttr: function(element, attribute) {
2317 - return element.getAttribute(attribute, 2);
2318 - },
2319 - _getAttrNode: function(element, attribute) {
2320 - var node = element.getAttributeNode(attribute);
2321 - return node ? node.value : "";
2322 - },
2323 - _getEv: function(element, attribute) {
2324 - attribute = element.getAttribute(attribute);
2325 - return attribute ? attribute.toString().slice(23, -2) : null;
2326 - },
2327 - _flag: function(element, attribute) {
2328 - return $(element).hasAttribute(attribute) ? attribute : null;
2329 - },
2330 - style: function(element) {
2331 - return element.style.cssText.toLowerCase();
2332 - },
2333 - title: function(element) {
2334 - return element.title;
2335 - }
2336 - }
2337 - }
2338 - };
2339 -
2340 - Element._attributeTranslations.write = {
2341 - names: Object.extend({
2342 - cellpadding: 'cellPadding',
2343 - cellspacing: 'cellSpacing'
2344 - }, Element._attributeTranslations.read.names),
2345 - values: {
2346 - checked: function(element, value) {
2347 - element.checked = !!value;
2348 - },
2349 -
2350 - style: function(element, value) {
2351 - element.style.cssText = value ? value : '';
2352 - }
2353 - }
2354 - };
2355 -
2356 - Element._attributeTranslations.has = {};
2357 -
2358 - $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
2359 - 'encType maxLength readOnly longDesc frameBorder').each(function(attr) {
2360 - Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
2361 - Element._attributeTranslations.has[attr.toLowerCase()] = attr;
2362 - });
2363 -
2364 - (function(v) {
2365 - Object.extend(v, {
2366 - href: v._getAttr,
2367 - src: v._getAttr,
2368 - type: v._getAttr,
2369 - action: v._getAttrNode,
2370 - disabled: v._flag,
2371 - checked: v._flag,
2372 - readonly: v._flag,
2373 - multiple: v._flag,
2374 - onload: v._getEv,
2375 - onunload: v._getEv,
2376 - onclick: v._getEv,
2377 - ondblclick: v._getEv,
2378 - onmousedown: v._getEv,
2379 - onmouseup: v._getEv,
2380 - onmouseover: v._getEv,
2381 - onmousemove: v._getEv,
2382 - onmouseout: v._getEv,
2383 - onfocus: v._getEv,
2384 - onblur: v._getEv,
2385 - onkeypress: v._getEv,
2386 - onkeydown: v._getEv,
2387 - onkeyup: v._getEv,
2388 - onsubmit: v._getEv,
2389 - onreset: v._getEv,
2390 - onselect: v._getEv,
2391 - onchange: v._getEv
2392 - });
2393 - })(Element._attributeTranslations.read.values);
2394 - }
2395 -
2396 - else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
2397 - Element.Methods.setOpacity = function(element, value) {
2398 - element = $(element);
2399 - element.style.opacity = (value == 1) ? 0.999999 :
2400 - (value === '') ? '' : (value < 0.00001) ? 0 : value;
2401 - return element;
2402 - };
2403 - }
2404 -
2405 - else if (Prototype.Browser.WebKit) {
2406 - Element.Methods.setOpacity = function(element, value) {
2407 - element = $(element);
2408 - element.style.opacity = (value == 1 || value === '') ? '' :
2409 - (value < 0.00001) ? 0 : value;
2410 -
2411 - if (value == 1)
2412 - if(element.tagName.toUpperCase() == 'IMG' && element.width) {
2413 - element.width++; element.width--;
2414 - } else try {
2415 - var n = document.createTextNode(' ');
2416 - element.appendChild(n);
2417 - element.removeChild(n);
2418 - } catch (e) { }
2419 -
2420 - return element;
2421 - };
2422 -
2423 - // Safari returns margins on body which is incorrect if the child is absolutely
2424 - // positioned. For performance reasons, redefine Element#cumulativeOffset for
2425 - // KHTML/WebKit only.
2426 - Element.Methods.cumulativeOffset = function(element) {
2427 - var valueT = 0, valueL = 0;
2428 - do {
2429 - valueT += element.offsetTop || 0;
2430 - valueL += element.offsetLeft || 0;
2431 - if (element.offsetParent == document.body)
2432 - if (Element.getStyle(element, 'position') == 'absolute') break;
2433 -
2434 - element = element.offsetParent;
2435 - } while (element);
2436 -
2437 - return Element._returnOffset(valueL, valueT);
2438 - };
2439 - }
2440 -
2441 - if (Prototype.Browser.IE || Prototype.Browser.Opera) {
2442 - // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements
2443 - Element.Methods.update = function(element, content) {
2444 - element = $(element);
2445 -
2446 - if (content && content.toElement) content = content.toElement();
2447 - if (Object.isElement(content)) return element.update().insert(content);
2448 -
2449 - content = Object.toHTML(content);
2450 - var tagName = element.tagName.toUpperCase();
2451 -
2452 - if (tagName in Element._insertionTranslations.tags) {
2453 - $A(element.childNodes).each(function(node) { element.removeChild(node) });
2454 - Element._getContentFromAnonymousElement(tagName, content.stripScripts())
2455 - .each(function(node) { element.appendChild(node) });
2456 - }
2457 - else element.innerHTML = content.stripScripts();
2458 -
2459 - content.evalScripts.bind(content).defer();
2460 - return element;
2461 - };
2462 - }
2463 -
2464 - if ('outerHTML' in document.createElement('div')) {
2465 - Element.Methods.replace = function(element, content) {
2466 - element = $(element);
2467 -
2468 - if (content && content.toElement) content = content.toElement();
2469 - if (Object.isElement(content)) {
2470 - element.parentNode.replaceChild(content, element);
2471 - return element;
2472 - }
2473 -
2474 - content = Object.toHTML(content);
2475 - var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
2476 -
2477 - if (Element._insertionTranslations.tags[tagName]) {
2478 - var nextSibling = element.next();
2479 - var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
2480 - parent.removeChild(element);
2481 - if (nextSibling)
2482 - fragments.each(function(node) { parent.insertBefore(node, nextSibling) });
2483 - else
2484 - fragments.each(function(node) { parent.appendChild(node) });
2485 - }
2486 - else element.outerHTML = content.stripScripts();
2487 -
2488 - content.evalScripts.bind(content).defer();
2489 - return element;
2490 - };
2491 - }
2492 -
2493 - Element._returnOffset = function(l, t) {
2494 - var result = [l, t];
2495 - result.left = l;
2496 - result.top = t;
2497 - return result;
2498 - };
2499 -
2500 - Element._getContentFromAnonymousElement = function(tagName, html) {
2501 - var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
2502 - if (t) {
2503 - div.innerHTML = t[0] + html + t[1];
2504 - t[2].times(function() { div = div.firstChild });
2505 - } else div.innerHTML = html;
2506 - return $A(div.childNodes);
2507 - };
2508 -
2509 - Element._insertionTranslations = {
2510 - before: function(element, node) {
2511 - element.parentNode.insertBefore(node, element);
2512 - },
2513 - top: function(element, node) {
2514 - element.insertBefore(node, element.firstChild);
2515 - },
2516 - bottom: function(element, node) {
2517 - element.appendChild(node);
2518 - },
2519 - after: function(element, node) {
2520 - element.parentNode.insertBefore(node, element.nextSibling);
2521 - },
2522 - tags: {
2523 - TABLE: ['<table>', '</table>', 1],
2524 - TBODY: ['<table><tbody>', '</tbody></table>', 2],
2525 - TR: ['<table><tbody><tr>', '</tr></tbody></table>', 3],
2526 - TD: ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
2527 - SELECT: ['<select>', '</select>', 1]
2528 - }
2529 - };
2530 -
2531 - (function() {
2532 - Object.extend(this.tags, {
2533 - THEAD: this.tags.TBODY,
2534 - TFOOT: this.tags.TBODY,
2535 - TH: this.tags.TD
2536 - });
2537 - }).call(Element._insertionTranslations);
2538 -
2539 - Element.Methods.Simulated = {
2540 - hasAttribute: function(element, attribute) {
2541 - attribute = Element._attributeTranslations.has[attribute] || attribute;
2542 - var node = $(element).getAttributeNode(attribute);
2543 - return !!(node && node.specified);
2544 - }
2545 - };
2546 -
2547 - Element.Methods.ByTag = { };
2548 -
2549 - Object.extend(Element, Element.Methods);
2550 -
2551 - if (!Prototype.BrowserFeatures.ElementExtensions &&
2552 - document.createElement('div')['__proto__']) {
2553 - window.HTMLElement = { };
2554 - window.HTMLElement.prototype = document.createElement('div')['__proto__'];
2555 - Prototype.BrowserFeatures.ElementExtensions = true;
2556 - }
2557 -
2558 - Element.extend = (function() {
2559 - if (Prototype.BrowserFeatures.SpecificElementExtensions)
2560 - return Prototype.K;
2561 -
2562 - var Methods = { }, ByTag = Element.Methods.ByTag;
2563 -
2564 - var extend = Object.extend(function(element) {
2565 - if (!element || element._extendedByPrototype ||
2566 - element.nodeType != 1 || element == window) return element;
2567 -
2568 - var methods = Object.clone(Methods),
2569 - tagName = element.tagName.toUpperCase(), property, value;
2570 -
2571 - // extend methods for specific tags
2572 - if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
2573 -
2574 - for (property in methods) {
2575 - value = methods[property];
2576 - if (Object.isFunction(value) && !(property in element))
2577 - element[property] = value.methodize();
2578 - }
2579 -
2580 - element._extendedByPrototype = Prototype.emptyFunction;
2581 - return element;
2582 -
2583 - }, {
2584 - refresh: function() {
2585 - // extend methods for all tags (Safari doesn't need this)
2586 - if (!Prototype.BrowserFeatures.ElementExtensions) {
2587 - Object.extend(Methods, Element.Methods);
2588 - Object.extend(Methods, Element.Methods.Simulated);
2589 - }
2590 - }
2591 - });
2592 -
2593 - extend.refresh();
2594 - return extend;
2595 - })();
2596 -
2597 - Element.hasAttribute = function(element, attribute) {
2598 - if (element.hasAttribute) return element.hasAttribute(attribute);
2599 - return Element.Methods.Simulated.hasAttribute(element, attribute);
2600 - };
2601 -
2602 - Element.addMethods = function(methods) {
2603 - var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
2604 -
2605 - if (!methods) {
2606 - Object.extend(Form, Form.Methods);
2607 - Object.extend(Form.Element, Form.Element.Methods);
2608 - Object.extend(Element.Methods.ByTag, {
2609 - "FORM": Object.clone(Form.Methods),
2610 - "INPUT": Object.clone(Form.Element.Methods),
2611 - "SELECT": Object.clone(Form.Element.Methods),
2612 - "TEXTAREA": Object.clone(Form.Element.Methods)
2613 - });
2614 - }
2615 -
2616 - if (arguments.length == 2) {
2617 - var tagName = methods;
2618 - methods = arguments[1];
2619 - }
2620 -
2621 - if (!tagName) Object.extend(Element.Methods, methods || { });
2622 - else {
2623 - if (Object.isArray(tagName)) tagName.each(extend);
2624 - else extend(tagName);
2625 - }
2626 -
2627 - function extend(tagName) {
2628 - tagName = tagName.toUpperCase();
2629 - if (!Element.Methods.ByTag[tagName])
2630 - Element.Methods.ByTag[tagName] = { };
2631 - Object.extend(Element.Methods.ByTag[tagName], methods);
2632 - }
2633 -
2634 - function copy(methods, destination, onlyIfAbsent) {
2635 - onlyIfAbsent = onlyIfAbsent || false;
2636 - for (var property in methods) {
2637 - var value = methods[property];
2638 - if (!Object.isFunction(value)) continue;
2639 - if (!onlyIfAbsent || !(property in destination))
2640 - destination[property] = value.methodize();
2641 - }
2642 - }
2643 -
2644 - function findDOMClass(tagName) {
2645 - var klass;
2646 - var trans = {
2647 - "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
2648 - "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
2649 - "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
2650 - "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
2651 - "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
2652 - "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
2653 - "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
2654 - "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
2655 - "FrameSet", "IFRAME": "IFrame"
2656 - };
2657 - if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
2658 - if (window[klass]) return window[klass];
2659 - klass = 'HTML' + tagName + 'Element';
2660 - if (window[klass]) return window[klass];
2661 - klass = 'HTML' + tagName.capitalize() + 'Element';
2662 - if (window[klass]) return window[klass];
2663 -
2664 - window[klass] = { };
2665 - window[klass].prototype = document.createElement(tagName)['__proto__'];
2666 - return window[klass];
2667 - }
2668 -
2669 - if (F.ElementExtensions) {
2670 - copy(Element.Methods, HTMLElement.prototype);
2671 - copy(Element.Methods.Simulated, HTMLElement.prototype, true);
2672 - }
2673 -
2674 - if (F.SpecificElementExtensions) {
2675 - for (var tag in Element.Methods.ByTag) {
2676 - var klass = findDOMClass(tag);
2677 - if (Object.isUndefined(klass)) continue;
2678 - copy(T[tag], klass.prototype);
2679 - }
2680 - }
2681 -
2682 - Object.extend(Element, Element.Methods);
2683 - delete Element.ByTag;
2684 -
2685 - if (Element.extend.refresh) Element.extend.refresh();
2686 - Element.cache = { };
2687 - };
2688 -
2689 - document.viewport = {
2690 - getDimensions: function() {
2691 - var dimensions = { }, B = Prototype.Browser;
2692 - $w('width height').each(function(d) {
2693 - var D = d.capitalize();
2694 - if (B.WebKit && !document.evaluate) {
2695 - // Safari <3.0 needs self.innerWidth/Height
2696 - dimensions[d] = self['inner' + D];
2697 - } else if (B.Opera && parseFloat(window.opera.version()) < 9.5) {
2698 - // Opera <9.5 needs document.body.clientWidth/Height
2699 - dimensions[d] = document.body['client' + D]
2700 - } else {
2701 - dimensions[d] = document.documentElement['client' + D];
2702 - }
2703 - });
2704 - return dimensions;
2705 - },
2706 -
2707 - getWidth: function() {
2708 - return this.getDimensions().width;
2709 - },
2710 -
2711 - getHeight: function() {
2712 - return this.getDimensions().height;
2713 - },
2714 -
2715 - getScrollOffsets: function() {
2716 - return Element._returnOffset(
2717 - window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
2718 - window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
2719 - }
2720 - };
2721 - /* Portions of the Selector class are derived from Jack Slocum's DomQuery,
2722 - * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
2723 - * license. Please see http://www.yui-ext.com/ for more information. */
2724 -
2725 - var Selector = Class.create({
2726 - initialize: function(expression) {
2727 - this.expression = expression.strip();
2728 -
2729 - if (this.shouldUseSelectorsAPI()) {
2730 - this.mode = 'selectorsAPI';
2731 - } else if (this.shouldUseXPath()) {
2732 - this.mode = 'xpath';
2733 - this.compileXPathMatcher();
2734 - } else {
2735 - this.mode = "normal";
2736 - this.compileMatcher();
2737 - }
2738 -
2739 - },
2740 -
2741 - shouldUseXPath: function() {
2742 - if (!Prototype.BrowserFeatures.XPath) return false;
2743 -
2744 - var e = this.expression;
2745 -
2746 - // Safari 3 chokes on :*-of-type and :empty
2747 - if (Prototype.Browser.WebKit &&
2748 - (e.include("-of-type") || e.include(":empty")))
2749 - return false;
2750 -
2751 - // XPath can't do namespaced attributes, nor can it read
2752 - // the "checked" property from DOM nodes
2753 - if ((/(\[[\w-]*?:|:checked)/).test(e))
2754 - return false;
2755 -
2756 - return true;
2757 - },
2758 -
2759 - shouldUseSelectorsAPI: function() {
2760 - if (!Prototype.BrowserFeatures.SelectorsAPI) return false;
2761 -
2762 - if (!Selector._div) Selector._div = new Element('div');
2763 -
2764 - // Make sure the browser treats the selector as valid. Test on an
2765 - // isolated element to minimize cost of this check.
2766 - try {
2767 - Selector._div.querySelector(this.expression);
2768 - } catch(e) {
2769 - return false;
2770 - }
2771 -
2772 - return true;
2773 - },
2774 -
2775 - compileMatcher: function() {
2776 - var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
2777 - c = Selector.criteria, le, p, m;
2778 -
2779 - if (Selector._cache[e]) {
2780 - this.matcher = Selector._cache[e];
2781 - return;
2782 - }
2783 -
2784 - this.matcher = ["this.matcher = function(root) {",
2785 - "var r = root, h = Selector.handlers, c = false, n;"];
2786 -
2787 - while (e && le != e && (/\S/).test(e)) {
2788 - le = e;
2789 - for (var i in ps) {
2790 - p = ps[i];
2791 - if (m = e.match(p)) {
2792 - this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :
2793 - new Template(c[i]).evaluate(m));
2794 - e = e.replace(m[0], '');
2795 - break;
2796 - }
2797 - }
2798 - }
2799 -
2800 - this.matcher.push("return h.unique(n);\n}");
2801 - eval(this.matcher.join('\n'));
2802 - Selector._cache[this.expression] = this.matcher;
2803 - },
2804 -
2805 - compileXPathMatcher: function() {
2806 - var e = this.expression, ps = Selector.patterns,
2807 - x = Selector.xpath, le, m;
2808 -
2809 - if (Selector._cache[e]) {
2810 - this.xpath = Selector._cache[e]; return;
2811 - }
2812 -
2813 - this.matcher = ['.//*'];
2814 - while (e && le != e && (/\S/).test(e)) {
2815 - le = e;
2816 - for (var i in ps) {
2817 - if (m = e.match(ps[i])) {
2818 - this.matcher.push(Object.isFunction(x[i]) ? x[i](m) :
2819 - new Template(x[i]).evaluate(m));
2820 - e = e.replace(m[0], '');
2821 - break;
2822 - }
2823 - }
2824 - }
2825 -
2826 - this.xpath = this.matcher.join('');
2827 - Selector._cache[this.expression] = this.xpath;
2828 - },
2829 -
2830 - findElements: function(root) {
2831 - root = root || document;
2832 - var e = this.expression, results;
2833 -
2834 - switch (this.mode) {
2835 - case 'selectorsAPI':
2836 - // querySelectorAll queries document-wide, then filters to descendants
2837 - // of the context element. That's not what we want.
2838 - // Add an explicit context to the selector if necessary.
2839 - if (root !== document) {
2840 - var oldId = root.id, id = $(root).identify();
2841 - e = "#" + id + " " + e;
2842 - }
2843 -
2844 - results = $A(root.querySelectorAll(e)).map(Element.extend);
2845 - root.id = oldId;
2846 -
2847 - return results;
2848 - case 'xpath':
2849 - return document._getElementsByXPath(this.xpath, root);
2850 - default:
2851 - return this.matcher(root);
2852 - }
2853 - },
2854 -
2855 - match: function(element) {
2856 - this.tokens = [];
2857 -
2858 - var e = this.expression, ps = Selector.patterns, as = Selector.assertions;
2859 - var le, p, m;
2860 -
2861 - while (e && le !== e && (/\S/).test(e)) {
2862 - le = e;
2863 - for (var i in ps) {
2864 - p = ps[i];
2865 - if (m = e.match(p)) {
2866 - // use the Selector.assertions methods unless the selector
2867 - // is too complex.
2868 - if (as[i]) {
2869 - this.tokens.push([i, Object.clone(m)]);
2870 - e = e.replace(m[0], '');
2871 - } else {
2872 - // reluctantly do a document-wide search
2873 - // and look for a match in the array
2874 - return this.findElements(document).include(element);
2875 - }
2876 - }
2877 - }
2878 - }
2879 -
2880 - var match = true, name, matches;
2881 - for (var i = 0, token; token = this.tokens[i]; i++) {
2882 - name = token[0], matches = token[1];
2883 - if (!Selector.assertions[name](element, matches)) {
2884 - match = false; break;
2885 - }
2886 - }
2887 -
2888 - return match;
2889 - },
2890 -
2891 - toString: function() {
2892 - return this.expression;
2893 - },
2894 -
2895 - inspect: function() {
2896 - return "#<Selector:" + this.expression.inspect() + ">";
2897 - }
2898 - });
2899 -
2900 - Object.extend(Selector, {
2901 - _cache: { },
2902 -
2903 - xpath: {
2904 - descendant: "//*",
2905 - child: "/*",
2906 - adjacent: "/following-sibling::*[1]",
2907 - laterSibling: '/following-sibling::*',
2908 - tagName: function(m) {
2909 - if (m[1] == '*') return '';
2910 - return "[local-name()='" + m[1].toLowerCase() +
2911 - "' or local-name()='" + m[1].toUpperCase() + "']";
2912 - },
2913 - className: "[contains(concat(' ', @class, ' '), ' #{1} ')]",
2914 - id: "[@id='#{1}']",
2915 - attrPresence: function(m) {
2916 - m[1] = m[1].toLowerCase();
2917 - return new Template("[@#{1}]").evaluate(m);
2918 - },
2919 - attr: function(m) {
2920 - m[1] = m[1].toLowerCase();
2921 - m[3] = m[5] || m[6];
2922 - return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
2923 - },
2924 - pseudo: function(m) {
2925 - var h = Selector.xpath.pseudos[m[1]];
2926 - if (!h) return '';
2927 - if (Object.isFunction(h)) return h(m);
2928 - return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
2929 - },
2930 - operators: {
2931 - '=': "[@#{1}='#{3}']",
2932 - '!=': "[@#{1}!='#{3}']",
2933 - '^=': "[starts-with(@#{1}, '#{3}')]",
2934 - '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
2935 - '*=': "[contains(@#{1}, '#{3}')]",
2936 - '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
2937 - '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
2938 - },
2939 - pseudos: {
2940 - 'first-child': '[not(preceding-sibling::*)]',
2941 - 'last-child': '[not(following-sibling::*)]',
2942 - 'only-child': '[not(preceding-sibling::* or following-sibling::*)]',
2943 - 'empty': "[count(*) = 0 and (count(text()) = 0)]",
2944 - 'checked': "[@checked]",
2945 - 'disabled': "[(@disabled) and (@type!='hidden')]",
2946 - 'enabled': "[not(@disabled) and (@type!='hidden')]",
2947 - 'not': function(m) {
2948 - var e = m[6], p = Selector.patterns,
2949 - x = Selector.xpath, le, v;
2950 -
2951 - var exclusion = [];
2952 - while (e && le != e && (/\S/).test(e)) {
2953 - le = e;
2954 - for (var i in p) {
2955 - if (m = e.match(p[i])) {
2956 - v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m);
2957 - exclusion.push("(" + v.substring(1, v.length - 1) + ")");
2958 - e = e.replace(m[0], '');
2959 - break;
2960 - }
2961 - }
2962 - }
2963 - return "[not(" + exclusion.join(" and ") + ")]";
2964 - },
2965 - 'nth-child': function(m) {
2966 - return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
2967 - },
2968 - 'nth-last-child': function(m) {
2969 - return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
2970 - },
2971 - 'nth-of-type': function(m) {
2972 - return Selector.xpath.pseudos.nth("position() ", m);
2973 - },
2974 - 'nth-last-of-type': function(m) {
2975 - return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
2976 - },
2977 - 'first-of-type': function(m) {
2978 - m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
2979 - },
2980 - 'last-of-type': function(m) {
2981 - m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
2982 - },
2983 - 'only-of-type': function(m) {
2984 - var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
2985 - },
2986 - nth: function(fragment, m) {
2987 - var mm, formula = m[6], predicate;
2988 - if (formula == 'even') formula = '2n+0';
2989 - if (formula == 'odd') formula = '2n+1';
2990 - if (mm = formula.match(/^(\d+)$/)) // digit only
2991 - return '[' + fragment + "= " + mm[1] + ']';
2992 - if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
2993 - if (mm[1] == "-") mm[1] = -1;
2994 - var a = mm[1] ? Number(mm[1]) : 1;
2995 - var b = mm[2] ? Number(mm[2]) : 0;
2996 - predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
2997 - "((#{fragment} - #{b}) div #{a} >= 0)]";
2998 - return new Template(predicate).evaluate({
2999 - fragment: fragment, a: a, b: b });
3000 - }
3001 - }
3002 - }
3003 - },
3004 -
3005 - criteria: {
3006 - tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
3007 - className: 'n = h.className(n, r, "#{1}", c); c = false;',
3008 - id: 'n = h.id(n, r, "#{1}", c); c = false;',
3009 - attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;',
3010 - attr: function(m) {
3011 - m[3] = (m[5] || m[6]);
3012 - return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m);
3013 - },
3014 - pseudo: function(m) {
3015 - if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
3016 - return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
3017 - },
3018 - descendant: 'c = "descendant";',
3019 - child: 'c = "child";',
3020 - adjacent: 'c = "adjacent";',
3021 - laterSibling: 'c = "laterSibling";'
3022 - },
3023 -
3024 - patterns: {
3025 - // combinators must be listed first
3026 - // (and descendant needs to be last combinator)
3027 - laterSibling: /^\s*~\s*/,
3028 - child: /^\s*>\s*/,
3029 - adjacent: /^\s*\+\s*/,
3030 - descendant: /^\s/,
3031 -
3032 - // selectors follow
3033 - tagName: /^\s*(\*|[\w\-]+)(\b|$)?/,
3034 - id: /^#([\w\-\*]+)(\b|$)/,
3035 - className: /^\.([\w\-\*]+)(\b|$)/,
3036 - pseudo:
3037 - /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/,
3038 - attrPresence: /^\[((?:[\w]+:)?[\w]+)\]/,
3039 - attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
3040 - },
3041 -
3042 - // for Selector.match and Element#match
3043 - assertions: {
3044 - tagName: function(element, matches) {
3045 - return matches[1].toUpperCase() == element.tagName.toUpperCase();
3046 - },
3047 -
3048 - className: function(element, matches) {
3049 - return Element.hasClassName(element, matches[1]);
3050 - },
3051 -
3052 - id: function(element, matches) {
3053 - return element.id === matches[1];
3054 - },
3055 -
3056 - attrPresence: function(element, matches) {
3057 - return Element.hasAttribute(element, matches[1]);
3058 - },
3059 -
3060 - attr: function(element, matches) {
3061 - var nodeValue = Element.readAttribute(element, matches[1]);
3062 - return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]);
3063 - }
3064 - },
3065 -
3066 - handlers: {
3067 - // UTILITY FUNCTIONS
3068 - // joins two collections
3069 - concat: function(a, b) {
3070 - for (var i = 0, node; node = b[i]; i++)
3071 - a.push(node);
3072 - return a;
3073 - },
3074 -
3075 - // marks an array of nodes for counting
3076 - mark: function(nodes) {
3077 - var _true = Prototype.emptyFunction;
3078 - for (var i = 0, node; node = nodes[i]; i++)
3079 - node._countedByPrototype = _true;
3080 - return nodes;
3081 - },
3082 -
3083 - unmark: function(nodes) {
3084 - for (var i = 0, node; node = nodes[i]; i++)
3085 - node._countedByPrototype = undefined;
3086 - return nodes;
3087 - },
3088 -
3089 - // mark each child node with its position (for nth calls)
3090 - // "ofType" flag indicates whether we're indexing for nth-of-type
3091 - // rather than nth-child
3092 - index: function(parentNode, reverse, ofType) {
3093 - parentNode._countedByPrototype = Prototype.emptyFunction;
3094 - if (reverse) {
3095 - for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
3096 - var node = nodes[i];
3097 - if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
3098 - }
3099 - } else {
3100 - for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
3101 - if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
3102 - }
3103 - },
3104 -
3105 - // filters out duplicates and extends all nodes
3106 - unique: function(nodes) {
3107 - if (nodes.length == 0) return nodes;
3108 - var results = [], n;
3109 - for (var i = 0, l = nodes.length; i < l; i++)
3110 - if (!(n = nodes[i])._countedByPrototype) {
3111 - n._countedByPrototype = Prototype.emptyFunction;
3112 - results.push(Element.extend(n));
3113 - }
3114 - return Selector.handlers.unmark(results);
3115 - },
3116 -
3117 - // COMBINATOR FUNCTIONS
3118 - descendant: function(nodes) {
3119 - var h = Selector.handlers;
3120 - for (var i = 0, results = [], node; node = nodes[i]; i++)
3121 - h.concat(results, node.getElementsByTagName('*'));
3122 - return results;
3123 - },
3124 -
3125 - child: function(nodes) {
3126 - var h = Selector.handlers;
3127 - for (var i = 0, results = [], node; node = nodes[i]; i++) {
3128 - for (var j = 0, child; child = node.childNodes[j]; j++)
3129 - if (child.nodeType == 1 && child.tagName != '!') results.push(child);
3130 - }
3131 - return results;
3132 - },
3133 -
3134 - adjacent: function(nodes) {
3135 - for (var i = 0, results = [], node; node = nodes[i]; i++) {
3136 - var next = this.nextElementSibling(node);
3137 - if (next) results.push(next);
3138 - }
3139 - return results;
3140 - },
3141 -
3142 - laterSibling: function(nodes) {
3143 - var h = Selector.handlers;
3144 - for (var i = 0, results = [], node; node = nodes[i]; i++)
3145 - h.concat(results, Element.nextSiblings(node));
3146 - return results;
3147 - },
3148 -
3149 - nextElementSibling: function(node) {
3150 - while (node = node.nextSibling)
3151 - if (node.nodeType == 1) return node;
3152 - return null;
3153 - },
3154 -
3155 - previousElementSibling: function(node) {
3156 - while (node = node.previousSibling)
3157 - if (node.nodeType == 1) return node;
3158 - return null;
3159 - },
3160 -
3161 - // TOKEN FUNCTIONS
3162 - tagName: function(nodes, root, tagName, combinator) {
3163 - var uTagName = tagName.toUpperCase();
3164 - var results = [], h = Selector.handlers;
3165 - if (nodes) {
3166 - if (combinator) {
3167 - // fastlane for ordinary descendant combinators
3168 - if (combinator == "descendant") {
3169 - for (var i = 0, node; node = nodes[i]; i++)
3170 - h.concat(results, node.getElementsByTagName(tagName));
3171 - return results;
3172 - } else nodes = this[combinator](nodes);
3173 - if (tagName == "*") return nodes;
3174 - }
3175 - for (var i = 0, node; node = nodes[i]; i++)
3176 - if (node.tagName.toUpperCase() === uTagName) results.push(node);
3177 - return results;
3178 - } else return root.getElementsByTagName(tagName);
3179 - },
3180 -
3181 - id: function(nodes, root, id, combinator) {
3182 - var targetNode = $(id), h = Selector.handlers;
3183 - if (!targetNode) return [];
3184 - if (!nodes && root == document) return [targetNode];
3185 - if (nodes) {
3186 - if (combinator) {
3187 - if (combinator == 'child') {
3188 - for (var i = 0, node; node = nodes[i]; i++)
3189 - if (targetNode.parentNode == node) return [targetNode];
3190 - } else if (combinator == 'descendant') {
3191 - for (var i = 0, node; node = nodes[i]; i++)
3192 - if (Element.descendantOf(targetNode, node)) return [targetNode];
3193 - } else if (combinator == 'adjacent') {
3194 - for (var i = 0, node; node = nodes[i]; i++)
3195 - if (Selector.handlers.previousElementSibling(targetNode) == node)
3196 - return [targetNode];
3197 - } else nodes = h[combinator](nodes);
3198 - }
3199 - for (var i = 0, node; node = nodes[i]; i++)
3200 - if (node == targetNode) return [targetNode];
3201 - return [];
3202 - }
3203 - return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
3204 - },
3205 -
3206 - className: function(nodes, root, className, combinator) {
3207 - if (nodes && combinator) nodes = this[combinator](nodes);
3208 - return Selector.handlers.byClassName(nodes, root, className);
3209 - },
3210 -
3211 - byClassName: function(nodes, root, className) {
3212 - if (!nodes) nodes = Selector.handlers.descendant([root]);
3213 - var needle = ' ' + className + ' ';
3214 - for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
3215 - nodeClassName = node.className;
3216 - if (nodeClassName.length == 0) continue;
3217 - if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
3218 - results.push(node);
3219 - }
3220 - return results;
3221 - },
3222 -
3223 - attrPresence: function(nodes, root, attr, combinator) {
3224 - if (!nodes) nodes = root.getElementsByTagName("*");
3225 - if (nodes && combinator) nodes = this[combinator](nodes);
3226 - var results = [];
3227 - for (var i = 0, node; node = nodes[i]; i++)
3228 - if (Element.hasAttribute(node, attr)) results.push(node);
3229 - return results;
3230 - },
3231 -
3232 - attr: function(nodes, root, attr, value, operator, combinator) {
3233 - if (!nodes) nodes = root.getElementsByTagName("*");
3234 - if (nodes && combinator) nodes = this[combinator](nodes);
3235 - var handler = Selector.operators[operator], results = [];
3236 - for (var i = 0, node; node = nodes[i]; i++) {
3237 - var nodeValue = Element.readAttribute(node, attr);
3238 - if (nodeValue === null) continue;
3239 - if (handler(nodeValue, value)) results.push(node);
3240 - }
3241 - return results;
3242 - },
3243 -
3244 - pseudo: function(nodes, name, value, root, combinator) {
3245 - if (nodes && combinator) nodes = this[combinator](nodes);
3246 - if (!nodes) nodes = root.getElementsByTagName("*");
3247 - return Selector.pseudos[name](nodes, value, root);
3248 - }
3249 - },
3250 -
3251 - pseudos: {
3252 - 'first-child': function(nodes, value, root) {
3253 - for (var i = 0, results = [], node; node = nodes[i]; i++) {
3254 - if (Selector.handlers.previousElementSibling(node)) continue;
3255 - results.push(node);
3256 - }
3257 - return results;
3258 - },
3259 - 'last-child': function(nodes, value, root) {
3260 - for (var i = 0, results = [], node; node = nodes[i]; i++) {
3261 - if (Selector.handlers.nextElementSibling(node)) continue;
3262 - results.push(node);
3263 - }
3264 - return results;
3265 - },
3266 - 'only-child': function(nodes, value, root) {
3267 - var h = Selector.handlers;
3268 - for (var i = 0, results = [], node; node = nodes[i]; i++)
3269 - if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
3270 - results.push(node);
3271 - return results;
3272 - },
3273 - 'nth-child': function(nodes, formula, root) {
3274 - return Selector.pseudos.nth(nodes, formula, root);
3275 - },
3276 - 'nth-last-child': function(nodes, formula, root) {
3277 - return Selector.pseudos.nth(nodes, formula, root, true);
3278 - },
3279 - 'nth-of-type': function(nodes, formula, root) {
3280 - return Selector.pseudos.nth(nodes, formula, root, false, true);
3281 - },
3282 - 'nth-last-of-type': function(nodes, formula, root) {
3283 - return Selector.pseudos.nth(nodes, formula, root, true, true);
3284 - },
3285 - 'first-of-type': function(nodes, formula, root) {
3286 - return Selector.pseudos.nth(nodes, "1", root, false, true);
3287 - },
3288 - 'last-of-type': function(nodes, formula, root) {
3289 - return Selector.pseudos.nth(nodes, "1", root, true, true);
3290 - },
3291 - 'only-of-type': function(nodes, formula, root) {
3292 - var p = Selector.pseudos;
3293 - return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
3294 - },
3295 -
3296 - // handles the an+b logic
3297 - getIndices: function(a, b, total) {
3298 - if (a == 0) return b > 0 ? [b] : [];
3299 - return $R(1, total).inject([], function(memo, i) {
3300 - if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
3301 - return memo;
3302 - });
3303 - },
3304 -
3305 - // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
3306 - nth: function(nodes, formula, root, reverse, ofType) {
3307 - if (nodes.length == 0) return [];
3308 - if (formula == 'even') formula = '2n+0';
3309 - if (formula == 'odd') formula = '2n+1';
3310 - var h = Selector.handlers, results = [], indexed = [], m;
3311 - h.mark(nodes);
3312 - for (var i = 0, node; node = nodes[i]; i++) {
3313 - if (!node.parentNode._countedByPrototype) {
3314 - h.index(node.parentNode, reverse, ofType);
3315 - indexed.push(node.parentNode);
3316 - }
3317 - }
3318 - if (formula.match(/^\d+$/)) { // just a number
3319 - formula = Number(formula);
3320 - for (var i = 0, node; node = nodes[i]; i++)
3321 - if (node.nodeIndex == formula) results.push(node);
3322 - } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
3323 - if (m[1] == "-") m[1] = -1;
3324 - var a = m[1] ? Number(m[1]) : 1;
3325 - var b = m[2] ? Number(m[2]) : 0;
3326 - var indices = Selector.pseudos.getIndices(a, b, nodes.length);
3327 - for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
3328 - for (var j = 0; j < l; j++)
3329 - if (node.nodeIndex == indices[j]) results.push(node);
3330 - }
3331 - }
3332 - h.unmark(nodes);
3333 - h.unmark(indexed);
3334 - return results;
3335 - },
3336 -
3337 - 'empty': function(nodes, value, root) {
3338 - for (var i = 0, results = [], node; node = nodes[i]; i++) {
3339 - // IE treats comments as element nodes
3340 - if (node.tagName == '!' || node.firstChild) continue;
3341 - results.push(node);
3342 - }
3343 - return results;
3344 - },
3345 -
3346 - 'not': function(nodes, selector, root) {
3347 - var h = Selector.handlers, selectorType, m;
3348 - var exclusions = new Selector(selector).findElements(root);
3349 - h.mark(exclusions);
3350 - for (var i = 0, results = [], node; node = nodes[i]; i++)
3351 - if (!node._countedByPrototype) results.push(node);
3352 - h.unmark(exclusions);
3353 - return results;
3354 - },
3355 -
3356 - 'enabled': function(nodes, value, root) {
3357 - for (var i = 0, results = [], node; node = nodes[i]; i++)
3358 - if (!node.disabled && (!node.type || node.type !== 'hidden'))
3359 - results.push(node);
3360 - return results;
3361 - },
3362 -
3363 - 'disabled': function(nodes, value, root) {
3364 - for (var i = 0, results = [], node; node = nodes[i]; i++)
3365 - if (node.disabled) results.push(node);
3366 - return results;
3367 - },
3368 -
3369 - 'checked': function(nodes, value, root) {
3370 - for (var i = 0, results = [], node; node = nodes[i]; i++)
3371 - if (node.checked) results.push(node);
3372 - return results;
3373 - }
3374 - },
3375 -
3376 - operators: {
3377 - '=': function(nv, v) { return nv == v; },
3378 - '!=': function(nv, v) { return nv != v; },
3379 - '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); },
3380 - '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); },
3381 - '*=': function(nv, v) { return nv == v || nv && nv.include(v); },
3382 - '$=': function(nv, v) { return nv.endsWith(v); },
3383 - '*=': function(nv, v) { return nv.include(v); },
3384 - '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
3385 - '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() +
3386 - '-').include('-' + (v || "").toUpperCase() + '-'); }
3387 - },
3388 -
3389 - split: function(expression) {
3390 - var expressions = [];
3391 - expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
3392 - expressions.push(m[1].strip());
3393 - });
3394 - return expressions;
3395 - },
3396 -
3397 - matchElements: function(elements, expression) {
3398 - var matches = $$(expression), h = Selector.handlers;
3399 - h.mark(matches);
3400 - for (var i = 0, results = [], element; element = elements[i]; i++)
3401 - if (element._countedByPrototype) results.push(element);
3402 - h.unmark(matches);
3403 - return results;
3404 - },
3405 -
3406 - findElement: function(elements, expression, index) {
3407 - if (Object.isNumber(expression)) {
3408 - index = expression; expression = false;
3409 - }
3410 - return Selector.matchElements(elements, expression || '*')[index || 0];
3411 - },
3412 -
3413 - findChildElements: function(element, expressions) {
3414 - expressions = Selector.split(expressions.join(','));
3415 - var results = [], h = Selector.handlers;
3416 - for (var i = 0, l = expressions.length, selector; i < l; i++) {
3417 - selector = new Selector(expressions[i].strip());
3418 - h.concat(results, selector.findElements(element));
3419 - }
3420 - return (l > 1) ? h.unique(results) : results;
3421 - }
3422 - });
3423 -
3424 - if (Prototype.Browser.IE) {
3425 - Object.extend(Selector.handlers, {
3426 - // IE returns comment nodes on getElementsByTagName("*").
3427 - // Filter them out.
3428 - concat: function(a, b) {
3429 - for (var i = 0, node; node = b[i]; i++)
3430 - if (node.tagName !== "!") a.push(node);
3431 - return a;
3432 - },
3433 -
3434 - // IE improperly serializes _countedByPrototype in (inner|outer)HTML.
3435 - unmark: function(nodes) {
3436 - for (var i = 0, node; node = nodes[i]; i++)
3437 - node.removeAttribute('_countedByPrototype');
3438 - return nodes;
3439 - }
3440 - });
3441 - }
3442 -
3443 - function $$() {
3444 - return Selector.findChildElements(document, $A(arguments));
3445 - }
3446 - var Form = {
3447 - reset: function(form) {
3448 - $(form).reset();
3449 - return form;
3450 - },
3451 -
3452 - serializeElements: function(elements, options) {
3453 - if (typeof options != 'object') options = { hash: !!options };
3454 - else if (Object.isUndefined(options.hash)) options.hash = true;
3455 - var key, value, submitted = false, submit = options.submit;
3456 -
3457 - var data = elements.inject({ }, function(result, element) {
3458 - if (!element.disabled && element.name) {
3459 - key = element.name; value = $(element).getValue();
3460 - if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&
3461 - submit !== false && (!submit || key == submit) && (submitted = true)))) {
3462 - if (key in result) {
3463 - // a key is already present; construct an array of values
3464 - if (!Object.isArray(result[key])) result[key] = [result[key]];
3465 - result[key].push(value);
3466 - }
3467 - else result[key] = value;
3468 - }
3469 - }
3470 - return result;
3471 - });
3472 -
3473 - return options.hash ? data : Object.toQueryString(data);
3474 - }
3475 - };
3476 -
3477 - Form.Methods = {
3478 - serialize: function(form, options) {
3479 - return Form.serializeElements(Form.getElements(form), options);
3480 - },
3481 -
3482 - getElements: function(form) {
3483 - return $A($(form).getElementsByTagName('*')).inject([],
3484 - function(elements, child) {
3485 - if (Form.Element.Serializers[child.tagName.toLowerCase()])
3486 - elements.push(Element.extend(child));
3487 - return elements;
3488 - }
3489 - );
3490 - },
3491 -
3492 - getInputs: function(form, typeName, name) {
3493 - form = $(form);
3494 - var inputs = form.getElementsByTagName('input');
3495 -
3496 - if (!typeName && !name) return $A(inputs).map(Element.extend);
3497 -
3498 - for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
3499 - var input = inputs[i];
3500 - if ((typeName && input.type != typeName) || (name && input.name != name))
3501 - continue;
3502 - matchingInputs.push(Element.extend(input));
3503 - }
3504 -
3505 - return matchingInputs;
3506 - },
3507 -
3508 - disable: function(form) {
3509 - form = $(form);
3510 - Form.getElements(form).invoke('disable');
3511 - return form;
3512 - },
3513 -
3514 - enable: function(form) {
3515 - form = $(form);
3516 - Form.getElements(form).invoke('enable');
3517 - return form;
3518 - },
3519 -
3520 - findFirstElement: function(form) {
3521 - var elements = $(form).getElements().findAll(function(element) {
3522 - return 'hidden' != element.type && !element.disabled;
3523 - });
3524 - var firstByIndex = elements.findAll(function(element) {
3525 - return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
3526 - }).sortBy(function(element) { return element.tabIndex }).first();
3527 -
3528 - return firstByIndex ? firstByIndex : elements.find(function(element) {
3529 - return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
3530 - });
3531 - },
3532 -
3533 - focusFirstElement: function(form) {
3534 - form = $(form);
3535 - form.findFirstElement().activate();
3536 - return form;
3537 - },
3538 -
3539 - request: function(form, options) {
3540 - form = $(form), options = Object.clone(options || { });
3541 -
3542 - var params = options.parameters, action = form.readAttribute('action') || '';
3543 - if (action.blank()) action = window.location.href;
3544 - options.parameters = form.serialize(true);
3545 -
3546 - if (params) {
3547 - if (Object.isString(params)) params = params.toQueryParams();
3548 - Object.extend(options.parameters, params);
3549 - }
3550 -
3551 - if (form.hasAttribute('method') && !options.method)
3552 - options.method = form.method;
3553 -
3554 - return new Ajax.Request(action, options);
3555 - }
3556 - };
3557 -
3558 - /*--------------------------------------------------------------------------*/
3559 -
3560 - Form.Element = {
3561 - focus: function(element) {
3562 - $(element).focus();
3563 - return element;
3564 - },
3565 -
3566 - select: function(element) {
3567 - $(element).select();
3568 - return element;
3569 - }
3570 - };
3571 -
3572 - Form.Element.Methods = {
3573 - serialize: function(element) {
3574 - element = $(element);
3575 - if (!element.disabled && element.name) {
3576 - var value = element.getValue();
3577 - if (value != undefined) {
3578 - var pair = { };
3579 - pair[element.name] = value;
3580 - return Object.toQueryString(pair);
3581 - }
3582 - }
3583 - return '';
3584 - },
3585 -
3586 - getValue: function(element) {
3587 - element = $(element);
3588 - var method = element.tagName.toLowerCase();
3589 - return Form.Element.Serializers[method](element);
3590 - },
3591 -
3592 - setValue: function(element, value) {
3593 - element = $(element);
3594 - var method = element.tagName.toLowerCase();
3595 - Form.Element.Serializers[method](element, value);
3596 - return element;
3597 - },
3598 -
3599 - clear: function(element) {
3600 - $(element).value = '';
3601 - return element;
3602 - },
3603 -
3604 - present: function(element) {
3605 - return $(element).value != '';
3606 - },
3607 -
3608 - activate: function(element) {
3609 - element = $(element);
3610 - try {
3611 - element.focus();
3612 - if (element.select && (element.tagName.toLowerCase() != 'input' ||
3613 - !['button', 'reset', 'submit'].include(element.type)))
3614 - element.select();
3615 - } catch (e) { }
3616 - return element;
3617 - },
3618 -
3619 - disable: function(element) {
3620 - element = $(element);
3621 - element.disabled = true;
3622 - return element;
3623 - },
3624 -
3625 - enable: function(element) {
3626 - element = $(element);
3627 - element.disabled = false;
3628 - return element;
3629 - }
3630 - };
3631 -
3632 - /*--------------------------------------------------------------------------*/
3633 -
3634 - var Field = Form.Element;
3635 - var $F = Form.Element.Methods.getValue;
3636 -
3637 - /*--------------------------------------------------------------------------*/
3638 -
3639 - Form.Element.Serializers = {
3640 - input: function(element, value) {
3641 - switch (element.type.toLowerCase()) {
3642 - case 'checkbox':
3643 - case 'radio':
3644 - return Form.Element.Serializers.inputSelector(element, value);
3645 - default:
3646 - return Form.Element.Serializers.textarea(element, value);
3647 - }
3648 - },
3649 -
3650 - inputSelector: function(element, value) {
3651 - if (Object.isUndefined(value)) return element.checked ? element.value : null;
3652 - else element.checked = !!value;
3653 - },
3654 -
3655 - textarea: function(element, value) {
3656 - if (Object.isUndefined(value)) return element.value;
3657 - else element.value = value;
3658 - },
3659 -
3660 - select: function(element, value) {
3661 - if (Object.isUndefined(value))
3662 - return this[element.type == 'select-one' ?
3663 - 'selectOne' : 'selectMany'](element);
3664 - else {
3665 - var opt, currentValue, single = !Object.isArray(value);
3666 - for (var i = 0, length = element.length; i < length; i++) {
3667 - opt = element.options[i];
3668 - currentValue = this.optionValue(opt);
3669 - if (single) {
3670 - if (currentValue == value) {
3671 - opt.selected = true;
3672 - return;
3673 - }
3674 - }
3675 - else opt.selected = value.include(currentValue);
3676 - }
3677 - }
3678 - },
3679 -
3680 - selectOne: function(element) {
3681 - var index = element.selectedIndex;
3682 - return index >= 0 ? this.optionValue(element.options[index]) : null;
3683 - },
3684 -
3685 - selectMany: function(element) {
3686 - var values, length = element.length;
3687 - if (!length) return null;
3688 -
3689 - for (var i = 0, values = []; i < length; i++) {
3690 - var opt = element.options[i];
3691 - if (opt.selected) values.push(this.optionValue(opt));
3692 - }
3693 - return values;
3694 - },
3695 -
3696 - optionValue: function(opt) {
3697 - // extend element because hasAttribute may not be native
3698 - return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
3699 - }
3700 - };
3701 -
3702 - /*--------------------------------------------------------------------------*/
3703 -
3704 - Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
3705 - initialize: function($super, element, frequency, callback) {
3706 - $super(callback, frequency);
3707 - this.element = $(element);
3708 - this.lastValue = this.getValue();
3709 - },
3710 -
3711 - execute: function() {
3712 - var value = this.getValue();
3713 - if (Object.isString(this.lastValue) && Object.isString(value) ?
3714 - this.lastValue != value : String(this.lastValue) != String(value)) {
3715 - this.callback(this.element, value);
3716 - this.lastValue = value;
3717 - }
3718 - }
3719 - });
3720 -
3721 - Form.Element.Observer = Class.create(Abstract.TimedObserver, {
3722 - getValue: function() {
3723 - return Form.Element.getValue(this.element);
3724 - }
3725 - });
3726 -
3727 - Form.Observer = Class.create(Abstract.TimedObserver, {
3728 - getValue: function() {
3729 - return Form.serialize(this.element);
3730 - }
3731 - });
3732 -
3733 - /*--------------------------------------------------------------------------*/
3734 -
3735 - Abstract.EventObserver = Class.create({
3736 - initialize: function(element, callback) {
3737 - this.element = $(element);
3738 - this.callback = callback;
3739 -
3740 - this.lastValue = this.getValue();
3741 - if (this.element.tagName.toLowerCase() == 'form')
3742 - this.registerFormCallbacks();
3743 - else
3744 - this.registerCallback(this.element);
3745 - },
3746 -
3747 - onElementEvent: function() {
3748 - var value = this.getValue();
3749 - if (this.lastValue != value) {
3750 - this.callback(this.element, value);
3751 - this.lastValue = value;
3752 - }
3753 - },
3754 -
3755 - registerFormCallbacks: function() {
3756 - Form.getElements(this.element).each(this.registerCallback, this);
3757 - },
3758 -
3759 - registerCallback: function(element) {
3760 - if (element.type) {
3761 - switch (element.type.toLowerCase()) {
3762 - case 'checkbox':
3763 - case 'radio':
3764 - Event.observe(element, 'click', this.onElementEvent.bind(this));
3765 - break;
3766 - default:
3767 - Event.observe(element, 'change', this.onElementEvent.bind(this));
3768 - break;
3769 - }
3770 - }
3771 - }
3772 - });
3773 -
3774 - Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
3775 - getValue: function() {
3776 - return Form.Element.getValue(this.element);
3777 - }
3778 - });
3779 -
3780 - Form.EventObserver = Class.create(Abstract.EventObserver, {
3781 - getValue: function() {
3782 - return Form.serialize(this.element);
3783 - }
3784 - });
3785 - if (!window.Event) var Event = { };
3786 -
3787 - Object.extend(Event, {
3788 - KEY_BACKSPACE: 8,
3789 - KEY_TAB: 9,
3790 - KEY_RETURN: 13,
3791 - KEY_ESC: 27,
3792 - KEY_LEFT: 37,
3793 - KEY_UP: 38,
3794 - KEY_RIGHT: 39,
3795 - KEY_DOWN: 40,
3796 - KEY_DELETE: 46,
3797 - KEY_HOME: 36,
3798 - KEY_END: 35,
3799 - KEY_PAGEUP: 33,
3800 - KEY_PAGEDOWN: 34,
3801 - KEY_INSERT: 45,
3802 -
3803 - cache: { },
3804 -
3805 - relatedTarget: function(event) {
3806 - var element;
3807 - switch(event.type) {
3808 - case 'mouseover': element = event.fromElement; break;
3809 - case 'mouseout': element = event.toElement; break;
3810 - default: return null;
3811 - }
3812 - return Element.extend(element);
3813 - }
3814 - });
3815 -
3816 - Event.Methods = (function() {
3817 - var isButton;
3818 -
3819 - if (Prototype.Browser.IE) {
3820 - var buttonMap = { 0: 1, 1: 4, 2: 2 };
3821 - isButton = function(event, code) {
3822 - return event.button == buttonMap[code];
3823 - };
3824 -
3825 - } else if (Prototype.Browser.WebKit) {
3826 - isButton = function(event, code) {
3827 - switch (code) {
3828 - case 0: return event.which == 1 && !event.metaKey;
3829 - case 1: return event.which == 1 && event.metaKey;
3830 - default: return false;
3831 - }
3832 - };
3833 -
3834 - } else {
3835 - isButton = function(event, code) {
3836 - return event.which ? (event.which === code + 1) : (event.button === code);
3837 - };
3838 - }
3839 -
3840 - return {
3841 - isLeftClick: function(event) { return isButton(event, 0) },
3842 - isMiddleClick: function(event) { return isButton(event, 1) },
3843 - isRightClick: function(event) { return isButton(event, 2) },
3844 -
3845 - element: function(event) {
3846 - event = Event.extend(event);
3847 -
3848 - var node = event.target,
3849 - type = event.type,
3850 - currentTarget = event.currentTarget;
3851 -
3852 - if (currentTarget && currentTarget.tagName) {
3853 - // Firefox screws up the "click" event when moving between radio buttons
3854 - // via arrow keys. It also screws up the "load" and "error" events on images,
3855 - // reporting the document as the target instead of the original image.
3856 - if (type === 'load' || type === 'error' ||
3857 - (type === 'click' && currentTarget.tagName.toLowerCase() === 'input'
3858 - && currentTarget.type === 'radio'))
3859 - node = currentTarget;
3860 - }
3861 - if (node.nodeType == Node.TEXT_NODE) node = node.parentNode;
3862 - return Element.extend(node);
3863 - },
3864 -
3865 - findElement: function(event, expression) {
3866 - var element = Event.element(event);
3867 - if (!expression) return element;
3868 - var elements = [element].concat(element.ancestors());
3869 - return Selector.findElement(elements, expression, 0);
3870 - },
3871 -
3872 - pointer: function(event) {
3873 - var docElement = document.documentElement,
3874 - body = document.body || { scrollLeft: 0, scrollTop: 0 };
3875 - return {
3876 - x: event.pageX || (event.clientX +
3877 - (docElement.scrollLeft || body.scrollLeft) -
3878 - (docElement.clientLeft || 0)),
3879 - y: event.pageY || (event.clientY +
3880 - (docElement.scrollTop || body.scrollTop) -
3881 - (docElement.clientTop || 0))
3882 - };
3883 - },
3884 -
3885 - pointerX: function(event) { return Event.pointer(event).x },
3886 - pointerY: function(event) { return Event.pointer(event).y },
3887 -
3888 - stop: function(event) {
3889 - Event.extend(event);
3890 - event.preventDefault();
3891 - event.stopPropagation();
3892 - event.stopped = true;
3893 - }
3894 - };
3895 - })();
3896 -
3897 - Event.extend = (function() {
3898 - var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
3899 - m[name] = Event.Methods[name].methodize();
3900 - return m;
3901 - });
3902 -
3903 - if (Prototype.Browser.IE) {
3904 - Object.extend(methods, {
3905 - stopPropagation: function() { this.cancelBubble = true },
3906 - preventDefault: function() { this.returnValue = false },
3907 - inspect: function() { return "[object Event]" }
3908 - });
3909 -
3910 - return function(event) {
3911 - if (!event) return false;
3912 - if (event._extendedByPrototype) return event;
3913 -
3914 - event._extendedByPrototype = Prototype.emptyFunction;
3915 - var pointer = Event.pointer(event);
3916 - Object.extend(event, {
3917 - target: event.srcElement,
3918 - relatedTarget: Event.relatedTarget(event),
3919 - pageX: pointer.x,
3920 - pageY: pointer.y
3921 - });
3922 - return Object.extend(event, methods);
3923 - };
3924 -
3925 - } else {
3926 - Event.prototype = Event.prototype || document.createEvent("HTMLEvents")['__proto__'];
3927 - Object.extend(Event.prototype, methods);
3928 - return Prototype.K;
3929 - }
3930 - })();
3931 -
3932 - Object.extend(Event, (function() {
3933 - var cache = Event.cache;
3934 -
3935 - function getEventID(element) {
3936 - if (element._prototypeEventID) return element._prototypeEventID[0];
3937 - arguments.callee.id = arguments.callee.id || 1;
3938 - return element._prototypeEventID = [++arguments.callee.id];
3939 - }
3940 -
3941 - function getDOMEventName(eventName) {
3942 - if (eventName && eventName.include(':')) return "dataavailable";
3943 - return eventName;
3944 - }
3945 -
3946 - function getCacheForID(id) {
3947 - return cache[id] = cache[id] || { };
3948 - }
3949 -
3950 - function getWrappersForEventName(id, eventName) {
3951 - var c = getCacheForID(id);
3952 - return c[eventName] = c[eventName] || [];
3953 - }
3954 -
3955 - function createWrapper(element, eventName, handler) {
3956 - var id = getEventID(element);
3957 - var c = getWrappersForEventName(id, eventName);
3958 - if (c.pluck("handler").include(handler)) return false;
3959 -
3960 - var wrapper = function(event) {
3961 - if (!Event || !Event.extend ||
3962 - (event.eventName && event.eventName != eventName))
3963 - return false;
3964 -
3965 - Event.extend(event);
3966 - handler.call(element, event);
3967 - };
3968 -
3969 - wrapper.handler = handler;
3970 - c.push(wrapper);
3971 - return wrapper;
3972 - }
3973 -
3974 - function findWrapper(id, eventName, handler) {
3975 - var c = getWrappersForEventName(id, eventName);
3976 - return c.find(function(wrapper) { return wrapper.handler == handler });
3977 - }
3978 -
3979 - function destroyWrapper(id, eventName, handler) {
3980 - var c = getCacheForID(id);
3981 - if (!c[eventName]) return false;
3982 - c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));
3983 - }
3984 -
3985 - function destroyCache() {
3986 - for (var id in cache)
3987 - for (var eventName in cache[id])
3988 - cache[id][eventName] = null;
3989 - }
3990 -
3991 -
3992 - // Internet Explorer needs to remove event handlers on page unload
3993 - // in order to avoid memory leaks.
3994 - if (window.attachEvent) {
3995 - window.attachEvent("onunload", destroyCache);
3996 - }
3997 -
3998 - // Safari has a dummy event handler on page unload so that it won't
3999 - // use its bfcache. Safari <= 3.1 has an issue with restoring the "document"
4000 - // object when page is returned to via the back button using its bfcache.
4001 - if (Prototype.Browser.WebKit) {
4002 - window.addEventListener('unload', Prototype.emptyFunction, false);
4003 - }
4004 -
4005 - return {
4006 - observe: function(element, eventName, handler) {
4007 - element = $(element);
4008 - var name = getDOMEventName(eventName);
4009 -
4010 - var wrapper = createWrapper(element, eventName, handler);
4011 - if (!wrapper) return element;
4012 -
4013 - if (element.addEventListener) {
4014 - element.addEventListener(name, wrapper, false);
4015 - } else {
4016 - element.attachEvent("on" + name, wrapper);
4017 - }
4018 -
4019 - return element;
4020 - },
4021 -
4022 - stopObserving: function(element, eventName, handler) {
4023 - element = $(element);
4024 - var id = getEventID(element), name = getDOMEventName(eventName);
4025 -
4026 - if (!handler && eventName) {
4027 - getWrappersForEventName(id, eventName).each(function(wrapper) {
4028 - element.stopObserving(eventName, wrapper.handler);
4029 - });
4030 - return element;
4031 -
4032 - } else if (!eventName) {
4033 - Object.keys(getCacheForID(id)).each(function(eventName) {
4034 - element.stopObserving(eventName);
4035 - });
4036 - return element;
4037 - }
4038 -
4039 - var wrapper = findWrapper(id, eventName, handler);
4040 - if (!wrapper) return element;
4041 -
4042 - if (element.removeEventListener) {
4043 - element.removeEventListener(name, wrapper, false);
4044 - } else {
4045 - element.detachEvent("on" + name, wrapper);
4046 - }
4047 -
4048 - destroyWrapper(id, eventName, handler);
4049 -
4050 - return element;
4051 - },
4052 -
4053 - fire: function(element, eventName, memo) {
4054 - element = $(element);
4055 - if (element == document && document.createEvent && !element.dispatchEvent)
4056 - element = document.documentElement;
4057 -
4058 - var event;
4059 - if (document.createEvent) {
4060 - event = document.createEvent("HTMLEvents");
4061 - event.initEvent("dataavailable", true, true);
4062 - } else {
4063 - event = document.createEventObject();
4064 - event.eventType = "ondataavailable";
4065 - }
4066 -
4067 - event.eventName = eventName;
4068 - event.memo = memo || { };
4069 -
4070 - if (document.createEvent) {
4071 - element.dispatchEvent(event);
4072 - } else {
4073 - element.fireEvent(event.eventType, event);
4074 - }
4075 -
4076 - return Event.extend(event);
4077 - }
4078 - };
4079 - })());
4080 -
4081 - Object.extend(Event, Event.Methods);
4082 -
4083 - Element.addMethods({
4084 - fire: Event.fire,
4085 - observe: Event.observe,
4086 - stopObserving: Event.stopObserving
4087 - });
4088 -
4089 - Object.extend(document, {
4090 - fire: Element.Methods.fire.methodize(),
4091 - observe: Element.Methods.observe.methodize(),
4092 - stopObserving: Element.Methods.stopObserving.methodize(),
4093 - loaded: false
4094 - });
4095 -
4096 - (function() {
4097 - /* Support for the DOMContentLoaded event is based on work by Dan Webb,
4098 - Matthias Miller, Dean Edwards and John Resig. */
4099 -
4100 - var timer;
4101 -
4102 - function fireContentLoadedEvent() {
4103 - if (document.loaded) return;
4104 - if (timer) window.clearInterval(timer);
4105 - document.fire("dom:loaded");
4106 - document.loaded = true;
4107 - }
4108 -
4109 - if (document.addEventListener) {
4110 - if (Prototype.Browser.WebKit) {
4111 - timer = window.setInterval(function() {
4112 - if (/loaded|complete/.test(document.readyState))
4113 - fireContentLoadedEvent();
4114 - }, 0);
4115 -
4116 - Event.observe(window, "load", fireContentLoadedEvent);
4117 -
4118 - } else {
4119 - document.addEventListener("DOMContentLoaded",
4120 - fireContentLoadedEvent, false);
4121 - }
4122 -
4123 - } else {
4124 - document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>");
4125 - $("__onDOMContentLoaded").onreadystatechange = function() {
4126 - if (this.readyState == "complete") {
4127 - this.onreadystatechange = null;
4128 - fireContentLoadedEvent();
4129 - }
4130 - };
4131 - }
4132 - })();
4133 - /*------------------------------- DEPRECATED -------------------------------*/
4134 -
4135 - Hash.toQueryString = Object.toQueryString;
4136 -
4137 - var Toggle = { display: Element.toggle };
4138 -
4139 - Element.Methods.childOf = Element.Methods.descendantOf;
4140 -
4141 - var Insertion = {
4142 - Before: function(element, content) {
4143 - return Element.insert(element, {before:content});
4144 - },
4145 -
4146 - Top: function(element, content) {
4147 - return Element.insert(element, {top:content});
4148 - },
4149 -
4150 - Bottom: function(element, content) {
4151 - return Element.insert(element, {bottom:content});
4152 - },
4153 -
4154 - After: function(element, content) {
4155 - return Element.insert(element, {after:content});
4156 - }
4157 - };
4158 -
4159 - var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
4160 -
4161 - // This should be moved to script.aculo.us; notice the deprecated methods
4162 - // further below, that map to the newer Element methods.
4163 - var Position = {
4164 - // set to true if needed, warning: firefox performance problems
4165 - // NOT neeeded for page scrolling, only if draggable contained in
4166 - // scrollable elements
4167 - includeScrollOffsets: false,
4168 -
4169 - // must be called before calling withinIncludingScrolloffset, every time the
4170 - // page is scrolled
4171 - prepare: function() {
4172 - this.deltaX = window.pageXOffset
4173 - || document.documentElement.scrollLeft
4174 - || document.body.scrollLeft
4175 - || 0;
4176 - this.deltaY = window.pageYOffset
4177 - || document.documentElement.scrollTop
4178 - || document.body.scrollTop
4179 - || 0;
4180 - },
4181 -
4182 - // caches x/y coordinate pair to use with overlap
4183 - within: function(element, x, y) {
4184 - if (this.includeScrollOffsets)
4185 - return this.withinIncludingScrolloffsets(element, x, y);
4186 - this.xcomp = x;
4187 - this.ycomp = y;
4188 - this.offset = Element.cumulativeOffset(element);
4189 -
4190 - return (y >= this.offset[1] &&
4191 - y < this.offset[1] + element.offsetHeight &&
4192 - x >= this.offset[0] &&
4193 - x < this.offset[0] + element.offsetWidth);
4194 - },
4195 -
4196 - withinIncludingScrolloffsets: function(element, x, y) {
4197 - var offsetcache = Element.cumulativeScrollOffset(element);
4198 -
4199 - this.xcomp = x + offsetcache[0] - this.deltaX;
4200 - this.ycomp = y + offsetcache[1] - this.deltaY;
4201 - this.offset = Element.cumulativeOffset(element);
4202 -
4203 - return (this.ycomp >= this.offset[1] &&
4204 - this.ycomp < this.offset[1] + element.offsetHeight &&
4205 - this.xcomp >= this.offset[0] &&
4206 - this.xcomp < this.offset[0] + element.offsetWidth);
4207 - },
4208 -
4209 - // within must be called directly before
4210 - overlap: function(mode, element) {
4211 - if (!mode) return 0;
4212 - if (mode == 'vertical')
4213 - return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
4214 - element.offsetHeight;
4215 - if (mode == 'horizontal')
4216 - return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
4217 - element.offsetWidth;
4218 - },
4219 -
4220 - // Deprecation layer -- use newer Element methods now (1.5.2).
4221 -
4222 - cumulativeOffset: Element.Methods.cumulativeOffset,
4223 -
4224 - positionedOffset: Element.Methods.positionedOffset,
4225 -
4226 - absolutize: function(element) {
4227 - Position.prepare();
4228 - return Element.absolutize(element);
4229 - },
4230 -
4231 - relativize: function(element) {
4232 - Position.prepare();
4233 - return Element.relativize(element);
4234 - },
4235 -
4236 - realOffset: Element.Methods.cumulativeScrollOffset,
4237 -
4238 - offsetParent: Element.Methods.getOffsetParent,
4239 -
4240 - page: Element.Methods.viewportOffset,
4241 -
4242 - clone: function(source, target, options) {
4243 - options = options || { };
4244 - return Element.clonePosition(target, source, options);
4245 - }
4246 - };
4247 -
4248 - /*--------------------------------------------------------------------------*/
4249 -
4250 - if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
4251 - function iter(name) {
4252 - return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
4253 - }
4254 -
4255 - instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
4256 - function(element, className) {
4257 - className = className.toString().strip();
4258 - var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
4259 - return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
4260 - } : function(element, className) {
4261 - className = className.toString().strip();
4262 - var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
4263 - if (!classNames && !className) return elements;
4264 -
4265 - var nodes = $(element).getElementsByTagName('*');
4266 - className = ' ' + className + ' ';
4267 -
4268 - for (var i = 0, child, cn; child = nodes[i]; i++) {
4269 - if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
4270 - (classNames && classNames.all(function(name) {
4271 - return !name.toString().blank() && cn.include(' ' + name + ' ');
4272 - }))))
4273 - elements.push(Element.extend(child));
4274 - }
4275 - return elements;
4276 - };
4277 -
4278 - return function(className, parentElement) {
4279 - return $(parentElement || document.body).getElementsByClassName(className);
4280 - };
4281 - }(Element.Methods);
4282 -
4283 - /*--------------------------------------------------------------------------*/
4284 -
4285 - Element.ClassNames = Class.create();
4286 - Element.ClassNames.prototype = {
4287 - initialize: function(element) {
4288 - this.element = $(element);
4289 - },
4290 -
4291 - _each: function(iterator) {
4292 - this.element.className.split(/\s+/).select(function(name) {
4293 - return name.length > 0;
4294 - })._each(iterator);
4295 - },
4296 -
4297 - set: function(className) {
4298 - this.element.className = className;
4299 - },
4300 -
4301 - add: function(classNameToAdd) {
4302 - if (this.include(classNameToAdd)) return;
4303 - this.set($A(this).concat(classNameToAdd).join(' '));
4304 - },
4305 -
4306 - remove: function(classNameToRemove) {
4307 - if (!this.include(classNameToRemove)) return;
4308 - this.set($A(this).without(classNameToRemove).join(' '));
4309 - },
4310 -
4311 - toString: function() {
4312 - return $A(this).join(' ');
4313 - }
4314 - };
4315 -
4316 - Object.extend(Element.ClassNames.prototype, Enumerable);
4317 -
4318 - /*--------------------------------------------------------------------------*/
4319 -
4320 - Element.addMethods(); No newline at end of file
@@ -1,32 +0,0
1 - function updateSiteList() {
2 - currentCountry = document.getElementById("site_country_id").value;
3 -
4 - sites = siteList[currentCountry];
5 - siteSelect = document.getElementById("login_site_id");
6 - old_len = siteSelect.length;
7 - // clear old box
8 - for(i=0; i<old_len; i++) siteSelect.remove(0);
9 -
10 - if(currentCountry==0) {
11 - for(i=0; i<allSiteList.length; i++) {
12 - if(allSiteList[i]!=null) {
13 - try {
14 - siteSelect.add(new Option(allSiteList[i],""+i,false,false),null);
15 - } catch(ex) {
16 - siteSelect.add(new Option(allSiteList[i],""+i,false,false));
17 - }
18 - }
19 - }
20 - } else {
21 - for(i=0; i<sites.length; i++) {
22 - if(sites[i]!=null) {
23 - try {
24 - siteSelect.add(new Option(sites[i],""+i,false,false),null);
25 - } catch(ex) {
26 - siteSelect.add(new Option(sites[i],""+i,false,false));
27 - }
28 - }
29 - }
30 - }
31 - }
32 - No newline at end of file
You need to be logged in to leave comments. Login now