Changesets can be listed by changeset number.
The Git repository is here.
- Revision:
- 193
- Log:
First stage commit of Typo 4.1, modified for the ROOL site.
Includes all local modifications but a final pass needs to be
made to delete any files left over from earlier Typo versions
that shouldn't be here anymore. See the 'tags' section of the
repository for a clean Typo 4.1 tree.Note that symlinks to shared files in the RISC OS Open theme
directory have been deliberately included this time around; I
decided that on balance it was better to leave them in as
placeholders, since unlike symlinks in app/views/shared, the
Typo theme structure is not a standard Rails concept.
- Author:
- rool
- Date:
- Wed Apr 04 18:51:02 +0100 2007
- Size:
- 38200 Bytes
1 | // Copyright (c) 2005, 2006 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(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); |
47 | return element; |
48 | } |
49 | |
50 | Element.getOpacity = function(element){ |
51 | element = $(element); |
52 | var opacity; |
53 | if (opacity = element.getStyle('opacity')) |
54 | return parseFloat(opacity); |
55 | if (opacity = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) |
56 | if(opacity[1]) return parseFloat(opacity[1]) / 100; |
57 | return 1.0; |
58 | } |
59 | |
60 | Element.setOpacity = function(element, value){ |
61 | element= $(element); |
62 | if (value == 1){ |
63 | element.setStyle({ opacity: |
64 | (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? |
65 | 0.999999 : 1.0 }); |
66 | if(/MSIE/.test(navigator.userAgent) && !window.opera) |
67 | element.setStyle({filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')}); |
68 | } else { |
69 | if(value < 0.00001) value = 0; |
70 | element.setStyle({opacity: value}); |
71 | if(/MSIE/.test(navigator.userAgent) && !window.opera) |
72 | element.setStyle( |
73 | { filter: element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') + |
74 | 'alpha(opacity='+value*100+')' }); |
75 | } |
76 | return element; |
77 | } |
78 | |
79 | Element.getInlineOpacity = function(element){ |
80 | return $(element).style.opacity || ''; |
81 | } |
82 | |
83 | Element.forceRerendering = function(element) { |
84 | try { |
85 | element = $(element); |
86 | var n = document.createTextNode(' '); |
87 | element.appendChild(n); |
88 | element.removeChild(n); |
89 | } catch(e) { } |
90 | }; |
91 | |
92 | /*--------------------------------------------------------------------------*/ |
93 | |
94 | Array.prototype.call = function() { |
95 | var args = arguments; |
96 | this.each(function(f){ f.apply(this, args) }); |
97 | } |
98 | |
99 | /*--------------------------------------------------------------------------*/ |
100 | |
101 | var Effect = { |
102 | _elementDoesNotExistError: { |
103 | name: 'ElementDoesNotExistError', |
104 | message: 'The specified DOM element does not exist, but is required for this effect to operate' |
105 | }, |
106 | tagifyText: function(element) { |
107 | if(typeof Builder == 'undefined') |
108 | throw("Effect.tagifyText requires including script.aculo.us' builder.js library"); |
109 | |
110 | var tagifyStyle = 'position:relative'; |
111 | if(/MSIE/.test(navigator.userAgent) && !window.opera) tagifyStyle += ';zoom:1'; |
112 | |
113 | element = $(element); |
114 | $A(element.childNodes).each( function(child) { |
115 | if(child.nodeType==3) { |
116 | child.nodeValue.toArray().each( function(character) { |
117 | element.insertBefore( |
118 | Builder.node('span',{style: tagifyStyle}, |
119 | character == ' ' ? String.fromCharCode(160) : character), |
120 | child); |
121 | }); |
122 | Element.remove(child); |
123 | } |
124 | }); |
125 | }, |
126 | multiple: function(element, effect) { |
127 | var elements; |
128 | if(((typeof element == 'object') || |
129 | (typeof element == 'function')) && |
130 | (element.length)) |
131 | elements = element; |
132 | else |
133 | elements = $(element).childNodes; |
134 | |
135 | var options = Object.extend({ |
136 | speed: 0.1, |
137 | delay: 0.0 |
138 | }, arguments[2] || {}); |
139 | var masterDelay = options.delay; |
140 | |
141 | $A(elements).each( function(element, index) { |
142 | new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay })); |
143 | }); |
144 | }, |
145 | PAIRS: { |
146 | 'slide': ['SlideDown','SlideUp'], |
147 | 'blind': ['BlindDown','BlindUp'], |
148 | 'appear': ['Appear','Fade'] |
149 | }, |
150 | toggle: function(element, effect) { |
151 | element = $(element); |
152 | effect = (effect || 'appear').toLowerCase(); |
153 | var options = Object.extend({ |
154 | queue: { position:'end', scope:(element.id || 'global'), limit: 1 } |
155 | }, arguments[2] || {}); |
156 | Effect[element.visible() ? |
157 | Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options); |
158 | } |
159 | }; |
160 | |
161 | var Effect2 = Effect; // deprecated |
162 | |
163 | /* ------------- transitions ------------- */ |
164 | |
165 | Effect.Transitions = { |
166 | linear: Prototype.K, |
167 | sinoidal: function(pos) { |
168 | return (-Math.cos(pos*Math.PI)/2) + 0.5; |
169 | }, |
170 | reverse: function(pos) { |
171 | return 1-pos; |
172 | }, |
173 | flicker: function(pos) { |
174 | return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4; |
175 | }, |
176 | wobble: function(pos) { |
177 | return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5; |
178 | }, |
179 | pulse: function(pos, pulses) { |
180 | pulses = pulses || 5; |
181 | return ( |
182 | Math.round((pos % (1/pulses)) * pulses) == 0 ? |
183 | ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) : |
184 | 1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) |
185 | ); |
186 | }, |
187 | none: function(pos) { |
188 | return 0; |
189 | }, |
190 | full: function(pos) { |
191 | return 1; |
192 | } |
193 | }; |
194 | |
195 | /* ------------- core effects ------------- */ |
196 | |
197 | Effect.ScopedQueue = Class.create(); |
198 | Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), { |
199 | initialize: function() { |
200 | this.effects = []; |
201 | this.interval = null; |
202 | }, |
203 | _each: function(iterator) { |
204 | this.effects._each(iterator); |
205 | }, |
206 | add: function(effect) { |
207 | var timestamp = new Date().getTime(); |
208 | |
209 | var position = (typeof effect.options.queue == 'string') ? |
210 | effect.options.queue : effect.options.queue.position; |
211 | |
212 | switch(position) { |
213 | case 'front': |
214 | // move unstarted effects after this effect |
215 | this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) { |
216 | e.startOn += effect.finishOn; |
217 | e.finishOn += effect.finishOn; |
218 | }); |
219 | break; |
220 | case 'with-last': |
221 | timestamp = this.effects.pluck('startOn').max() || timestamp; |
222 | break; |
223 | case 'end': |
224 | // start effect after last queued effect has finished |
225 | timestamp = this.effects.pluck('finishOn').max() || timestamp; |
226 | break; |
227 | } |
228 | |
229 | effect.startOn += timestamp; |
230 | effect.finishOn += timestamp; |
231 | |
232 | if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit)) |
233 | this.effects.push(effect); |
234 | |
235 | if(!this.interval) |
236 | this.interval = setInterval(this.loop.bind(this), 40); |
237 | }, |
238 | remove: function(effect) { |
239 | this.effects = this.effects.reject(function(e) { return e==effect }); |
240 | if(this.effects.length == 0) { |
241 | clearInterval(this.interval); |
242 | this.interval = null; |
243 | } |
244 | }, |
245 | loop: function() { |
246 | var timePos = new Date().getTime(); |
247 | this.effects.invoke('loop', timePos); |
248 | } |
249 | }); |
250 | |
251 | Effect.Queues = { |
252 | instances: $H(), |
253 | get: function(queueName) { |
254 | if(typeof queueName != 'string') return queueName; |
255 | |
256 | if(!this.instances[queueName]) |
257 | this.instances[queueName] = new Effect.ScopedQueue(); |
258 | |
259 | return this.instances[queueName]; |
260 | } |
261 | } |
262 | Effect.Queue = Effect.Queues.get('global'); |
263 | |
264 | Effect.DefaultOptions = { |
265 | transition: Effect.Transitions.sinoidal, |
266 | duration: 1.0, // seconds |
267 | fps: 25.0, // max. 25fps due to Effect.Queue implementation |
268 | sync: false, // true for combining |
269 | from: 0.0, |
270 | to: 1.0, |
271 | delay: 0.0, |
272 | queue: 'parallel' |
273 | } |
274 | |
275 | Effect.Base = function() {}; |
276 | Effect.Base.prototype = { |
277 | position: null, |
278 | start: function(options) { |
279 | this.options = Object.extend(Object.extend({},Effect.DefaultOptions), options || {}); |
280 | this.currentFrame = 0; |
281 | this.state = 'idle'; |
282 | this.startOn = this.options.delay*1000; |
283 | this.finishOn = this.startOn + (this.options.duration*1000); |
284 | this.event('beforeStart'); |
285 | if(!this.options.sync) |
286 | Effect.Queues.get(typeof this.options.queue == 'string' ? |
287 | 'global' : this.options.queue.scope).add(this); |
288 | }, |
289 | loop: function(timePos) { |
290 | if(timePos >= this.startOn) { |
291 | if(timePos >= this.finishOn) { |
292 | this.render(1.0); |
293 | this.cancel(); |
294 | this.event('beforeFinish'); |
295 | if(this.finish) this.finish(); |
296 | this.event('afterFinish'); |
297 | return; |
298 | } |
299 | var pos = (timePos - this.startOn) / (this.finishOn - this.startOn); |
300 | var frame = Math.round(pos * this.options.fps * this.options.duration); |
301 | if(frame > this.currentFrame) { |
302 | this.render(pos); |
303 | this.currentFrame = frame; |
304 | } |
305 | } |
306 | }, |
307 | render: function(pos) { |
308 | if(this.state == 'idle') { |
309 | this.state = 'running'; |
310 | this.event('beforeSetup'); |
311 | if(this.setup) this.setup(); |
312 | this.event('afterSetup'); |
313 | } |
314 | if(this.state == 'running') { |
315 | if(this.options.transition) pos = this.options.transition(pos); |
316 | pos *= (this.options.to-this.options.from); |
317 | pos += this.options.from; |
318 | this.position = pos; |
319 | this.event('beforeUpdate'); |
320 | if(this.update) this.update(pos); |
321 | this.event('afterUpdate'); |
322 | } |
323 | }, |
324 | cancel: function() { |
325 | if(!this.options.sync) |
326 | Effect.Queues.get(typeof this.options.queue == 'string' ? |
327 | 'global' : this.options.queue.scope).remove(this); |
328 | this.state = 'finished'; |
329 | }, |
330 | event: function(eventName) { |
331 | if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this); |
332 | if(this.options[eventName]) this.options[eventName](this); |
333 | }, |
334 | inspect: function() { |
335 | return '#<Effect:' + $H(this).inspect() + ',options:' + $H(this.options).inspect() + '>'; |
336 | } |
337 | } |
338 | |
339 | Effect.Parallel = Class.create(); |
340 | Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), { |
341 | initialize: function(effects) { |
342 | this.effects = effects || []; |
343 | this.start(arguments[1]); |
344 | }, |
345 | update: function(position) { |
346 | this.effects.invoke('render', position); |
347 | }, |
348 | finish: function(position) { |
349 | this.effects.each( function(effect) { |
350 | effect.render(1.0); |
351 | effect.cancel(); |
352 | effect.event('beforeFinish'); |
353 | if(effect.finish) effect.finish(position); |
354 | effect.event('afterFinish'); |
355 | }); |
356 | } |
357 | }); |
358 | |
359 | Effect.Event = Class.create(); |
360 | Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), { |
361 | initialize: function() { |
362 | var options = Object.extend({ |
363 | duration: 0 |
364 | }, arguments[0] || {}); |
365 | this.start(options); |
366 | }, |
367 | update: Prototype.emptyFunction |
368 | }); |
369 | |
370 | Effect.Opacity = Class.create(); |
371 | Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), { |
372 | initialize: function(element) { |
373 | this.element = $(element); |
374 | if(!this.element) throw(Effect._elementDoesNotExistError); |
375 | // make this work on IE on elements without 'layout' |
376 | if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout)) |
377 | this.element.setStyle({zoom: 1}); |
378 | var options = Object.extend({ |
379 | from: this.element.getOpacity() || 0.0, |
380 | to: 1.0 |
381 | }, arguments[1] || {}); |
382 | this.start(options); |
383 | }, |
384 | update: function(position) { |
385 | this.element.setOpacity(position); |
386 | } |
387 | }); |
388 | |
389 | Effect.Move = Class.create(); |
390 | Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), { |
391 | initialize: function(element) { |
392 | this.element = $(element); |
393 | if(!this.element) throw(Effect._elementDoesNotExistError); |
394 | var options = Object.extend({ |
395 | x: 0, |
396 | y: 0, |
397 | mode: 'relative' |
398 | }, arguments[1] || {}); |
399 | this.start(options); |
400 | }, |
401 | setup: function() { |
402 | // Bug in Opera: Opera returns the "real" position of a static element or |
403 | // relative element that does not have top/left explicitly set. |
404 | // ==> Always set top and left for position relative elements in your stylesheets |
405 | // (to 0 if you do not need them) |
406 | this.element.makePositioned(); |
407 | this.originalLeft = parseFloat(this.element.getStyle('left') || '0'); |
408 | this.originalTop = parseFloat(this.element.getStyle('top') || '0'); |
409 | if(this.options.mode == 'absolute') { |
410 | // absolute movement, so we need to calc deltaX and deltaY |
411 | this.options.x = this.options.x - this.originalLeft; |
412 | this.options.y = this.options.y - this.originalTop; |
413 | } |
414 | }, |
415 | update: function(position) { |
416 | this.element.setStyle({ |
417 | left: Math.round(this.options.x * position + this.originalLeft) + 'px', |
418 | top: Math.round(this.options.y * position + this.originalTop) + 'px' |
419 | }); |
420 | } |
421 | }); |
422 | |
423 | // for backwards compatibility |
424 | Effect.MoveBy = function(element, toTop, toLeft) { |
425 | return new Effect.Move(element, |
426 | Object.extend({ x: toLeft, y: toTop }, arguments[3] || {})); |
427 | }; |
428 | |
429 | Effect.Scale = Class.create(); |
430 | Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), { |
431 | initialize: function(element, percent) { |
432 | this.element = $(element); |
433 | if(!this.element) throw(Effect._elementDoesNotExistError); |
434 | var options = Object.extend({ |
435 | scaleX: true, |
436 | scaleY: true, |
437 | scaleContent: true, |
438 | scaleFromCenter: false, |
439 | scaleMode: 'box', // 'box' or 'contents' or {} with provided values |
440 | scaleFrom: 100.0, |
441 | scaleTo: percent |
442 | }, arguments[2] || {}); |
443 | this.start(options); |
444 | }, |
445 | setup: function() { |
446 | this.restoreAfterFinish = this.options.restoreAfterFinish || false; |
447 | this.elementPositioning = this.element.getStyle('position'); |
448 | |
449 | this.originalStyle = {}; |
450 | ['top','left','width','height','fontSize'].each( function(k) { |
451 | this.originalStyle[k] = this.element.style[k]; |
452 | }.bind(this)); |
453 | |
454 | this.originalTop = this.element.offsetTop; |
455 | this.originalLeft = this.element.offsetLeft; |
456 | |
457 | var fontSize = this.element.getStyle('font-size') || '100%'; |
458 | ['em','px','%','pt'].each( function(fontSizeType) { |
459 | if(fontSize.indexOf(fontSizeType)>0) { |
460 | this.fontSize = parseFloat(fontSize); |
461 | this.fontSizeType = fontSizeType; |
462 | } |
463 | }.bind(this)); |
464 | |
465 | this.factor = (this.options.scaleTo - this.options.scaleFrom)/100; |
466 | |
467 | this.dims = null; |
468 | if(this.options.scaleMode=='box') |
469 | this.dims = [this.element.offsetHeight, this.element.offsetWidth]; |
470 | if(/^content/.test(this.options.scaleMode)) |
471 | this.dims = [this.element.scrollHeight, this.element.scrollWidth]; |
472 | if(!this.dims) |
473 | this.dims = [this.options.scaleMode.originalHeight, |
474 | this.options.scaleMode.originalWidth]; |
475 | }, |
476 | update: function(position) { |
477 | var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position); |
478 | if(this.options.scaleContent && this.fontSize) |
479 | this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType }); |
480 | this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale); |
481 | }, |
482 | finish: function(position) { |
483 | if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle); |
484 | }, |
485 | setDimensions: function(height, width) { |
486 | var d = {}; |
487 | if(this.options.scaleX) d.width = Math.round(width) + 'px'; |
488 | if(this.options.scaleY) d.height = Math.round(height) + 'px'; |
489 | if(this.options.scaleFromCenter) { |
490 | var topd = (height - this.dims[0])/2; |
491 | var leftd = (width - this.dims[1])/2; |
492 | if(this.elementPositioning == 'absolute') { |
493 | if(this.options.scaleY) d.top = this.originalTop-topd + 'px'; |
494 | if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px'; |
495 | } else { |
496 | if(this.options.scaleY) d.top = -topd + 'px'; |
497 | if(this.options.scaleX) d.left = -leftd + 'px'; |
498 | } |
499 | } |
500 | this.element.setStyle(d); |
501 | } |
502 | }); |
503 | |
504 | Effect.Highlight = Class.create(); |
505 | Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), { |
506 | initialize: function(element) { |
507 | this.element = $(element); |
508 | if(!this.element) throw(Effect._elementDoesNotExistError); |
509 | var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {}); |
510 | this.start(options); |
511 | }, |
512 | setup: function() { |
513 | // Prevent executing on elements not in the layout flow |
514 | if(this.element.getStyle('display')=='none') { this.cancel(); return; } |
515 | // Disable background image during the effect |
516 | this.oldStyle = { |
517 | backgroundImage: this.element.getStyle('background-image') }; |
518 | this.element.setStyle({backgroundImage: 'none'}); |
519 | if(!this.options.endcolor) |
520 | this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff'); |
521 | if(!this.options.restorecolor) |
522 | this.options.restorecolor = this.element.getStyle('background-color'); |
523 | // init color calculations |
524 | this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this)); |
525 | 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)); |
526 | }, |
527 | update: function(position) { |
528 | this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){ |
529 | return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) }); |
530 | }, |
531 | finish: function() { |
532 | this.element.setStyle(Object.extend(this.oldStyle, { |
533 | backgroundColor: this.options.restorecolor |
534 | })); |
535 | } |
536 | }); |
537 | |
538 | Effect.ScrollTo = Class.create(); |
539 | Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), { |
540 | initialize: function(element) { |
541 | this.element = $(element); |
542 | this.start(arguments[1] || {}); |
543 | }, |
544 | setup: function() { |
545 | Position.prepare(); |
546 | var offsets = Position.cumulativeOffset(this.element); |
547 | if(this.options.offset) offsets[1] += this.options.offset; |
548 | var max = window.innerHeight ? |
549 | window.height - window.innerHeight : |
550 | document.body.scrollHeight - |
551 | (document.documentElement.clientHeight ? |
552 | document.documentElement.clientHeight : document.body.clientHeight); |
553 | this.scrollStart = Position.deltaY; |
554 | this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart; |
555 | }, |
556 | update: function(position) { |
557 | Position.prepare(); |
558 | window.scrollTo(Position.deltaX, |
559 | this.scrollStart + (position*this.delta)); |
560 | } |
561 | }); |
562 | |
563 | /* ------------- combination effects ------------- */ |
564 | |
565 | Effect.Fade = function(element) { |
566 | element = $(element); |
567 | var oldOpacity = element.getInlineOpacity(); |
568 | var options = Object.extend({ |
569 | from: element.getOpacity() || 1.0, |
570 | to: 0.0, |
571 | afterFinishInternal: function(effect) { |
572 | if(effect.options.to!=0) return; |
573 | effect.element.hide().setStyle({opacity: oldOpacity}); |
574 | }}, arguments[1] || {}); |
575 | return new Effect.Opacity(element,options); |
576 | } |
577 | |
578 | Effect.Appear = function(element) { |
579 | element = $(element); |
580 | var options = Object.extend({ |
581 | from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0), |
582 | to: 1.0, |
583 | // force Safari to render floated elements properly |
584 | afterFinishInternal: function(effect) { |
585 | effect.element.forceRerendering(); |
586 | }, |
587 | beforeSetup: function(effect) { |
588 | effect.element.setOpacity(effect.options.from).show(); |
589 | }}, arguments[1] || {}); |
590 | return new Effect.Opacity(element,options); |
591 | } |
592 | |
593 | Effect.Puff = function(element) { |
594 | element = $(element); |
595 | var oldStyle = { |
596 | opacity: element.getInlineOpacity(), |
597 | position: element.getStyle('position'), |
598 | top: element.style.top, |
599 | left: element.style.left, |
600 | width: element.style.width, |
601 | height: element.style.height |
602 | }; |
603 | return new Effect.Parallel( |
604 | [ new Effect.Scale(element, 200, |
605 | { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), |
606 | new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], |
607 | Object.extend({ duration: 1.0, |
608 | beforeSetupInternal: function(effect) { |
609 | Position.absolutize(effect.effects[0].element) |
610 | }, |
611 | afterFinishInternal: function(effect) { |
612 | effect.effects[0].element.hide().setStyle(oldStyle); } |
613 | }, arguments[1] || {}) |
614 | ); |
615 | } |
616 | |
617 | Effect.BlindUp = function(element) { |
618 | element = $(element); |
619 | element.makeClipping(); |
620 | return new Effect.Scale(element, 0, |
621 | Object.extend({ scaleContent: false, |
622 | scaleX: false, |
623 | restoreAfterFinish: true, |
624 | afterFinishInternal: function(effect) { |
625 | effect.element.hide().undoClipping(); |
626 | } |
627 | }, arguments[1] || {}) |
628 | ); |
629 | } |
630 | |
631 | Effect.BlindDown = function(element) { |
632 | element = $(element); |
633 | var elementDimensions = element.getDimensions(); |
634 | return new Effect.Scale(element, 100, Object.extend({ |
635 | scaleContent: false, |
636 | scaleX: false, |
637 | scaleFrom: 0, |
638 | scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, |
639 | restoreAfterFinish: true, |
640 | afterSetup: function(effect) { |
641 | effect.element.makeClipping().setStyle({height: '0px'}).show(); |
642 | }, |
643 | afterFinishInternal: function(effect) { |
644 | effect.element.undoClipping(); |
645 | } |
646 | }, arguments[1] || {})); |
647 | } |
648 | |
649 | Effect.SwitchOff = function(element) { |
650 | element = $(element); |
651 | var oldOpacity = element.getInlineOpacity(); |
652 | return new Effect.Appear(element, Object.extend({ |
653 | duration: 0.4, |
654 | from: 0, |
655 | transition: Effect.Transitions.flicker, |
656 | afterFinishInternal: function(effect) { |
657 | new Effect.Scale(effect.element, 1, { |
658 | duration: 0.3, scaleFromCenter: true, |
659 | scaleX: false, scaleContent: false, restoreAfterFinish: true, |
660 | beforeSetup: function(effect) { |
661 | effect.element.makePositioned().makeClipping(); |
662 | }, |
663 | afterFinishInternal: function(effect) { |
664 | effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity}); |
665 | } |
666 | }) |
667 | } |
668 | }, arguments[1] || {})); |
669 | } |
670 | |
671 | Effect.DropOut = function(element) { |
672 | element = $(element); |
673 | var oldStyle = { |
674 | top: element.getStyle('top'), |
675 | left: element.getStyle('left'), |
676 | opacity: element.getInlineOpacity() }; |
677 | return new Effect.Parallel( |
678 | [ new Effect.Move(element, {x: 0, y: 100, sync: true }), |
679 | new Effect.Opacity(element, { sync: true, to: 0.0 }) ], |
680 | Object.extend( |
681 | { duration: 0.5, |
682 | beforeSetup: function(effect) { |
683 | effect.effects[0].element.makePositioned(); |
684 | }, |
685 | afterFinishInternal: function(effect) { |
686 | effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle); |
687 | } |
688 | }, arguments[1] || {})); |
689 | } |
690 | |
691 | Effect.Shake = function(element) { |
692 | element = $(element); |
693 | var oldStyle = { |
694 | top: element.getStyle('top'), |
695 | left: element.getStyle('left') }; |
696 | return new Effect.Move(element, |
697 | { x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { |
698 | new Effect.Move(effect.element, |
699 | { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { |
700 | new Effect.Move(effect.element, |
701 | { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { |
702 | new Effect.Move(effect.element, |
703 | { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { |
704 | new Effect.Move(effect.element, |
705 | { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { |
706 | new Effect.Move(effect.element, |
707 | { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { |
708 | effect.element.undoPositioned().setStyle(oldStyle); |
709 | }}) }}) }}) }}) }}) }}); |
710 | } |
711 | |
712 | Effect.SlideDown = function(element) { |
713 | element = $(element).cleanWhitespace(); |
714 | // SlideDown need to have the content of the element wrapped in a container element with fixed height! |
715 | var oldInnerBottom = element.down().getStyle('bottom'); |
716 | var elementDimensions = element.getDimensions(); |
717 | return new Effect.Scale(element, 100, Object.extend({ |
718 | scaleContent: false, |
719 | scaleX: false, |
720 | scaleFrom: window.opera ? 0 : 1, |
721 | scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, |
722 | restoreAfterFinish: true, |
723 | afterSetup: function(effect) { |
724 | effect.element.makePositioned(); |
725 | effect.element.down().makePositioned(); |
726 | if(window.opera) effect.element.setStyle({top: ''}); |
727 | effect.element.makeClipping().setStyle({height: '0px'}).show(); |
728 | }, |
729 | afterUpdateInternal: function(effect) { |
730 | effect.element.down().setStyle({bottom: |
731 | (effect.dims[0] - effect.element.clientHeight) + 'px' }); |
732 | }, |
733 | afterFinishInternal: function(effect) { |
734 | effect.element.undoClipping().undoPositioned(); |
735 | effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); } |
736 | }, arguments[1] || {}) |
737 | ); |
738 | } |
739 | |
740 | Effect.SlideUp = function(element) { |
741 | element = $(element).cleanWhitespace(); |
742 | var oldInnerBottom = element.down().getStyle('bottom'); |
743 | return new Effect.Scale(element, window.opera ? 0 : 1, |
744 | Object.extend({ scaleContent: false, |
745 | scaleX: false, |
746 | scaleMode: 'box', |
747 | scaleFrom: 100, |
748 | restoreAfterFinish: true, |
749 | beforeStartInternal: function(effect) { |
750 | effect.element.makePositioned(); |
751 | effect.element.down().makePositioned(); |
752 | if(window.opera) effect.element.setStyle({top: ''}); |
753 | effect.element.makeClipping().show(); |
754 | }, |
755 | afterUpdateInternal: function(effect) { |
756 | effect.element.down().setStyle({bottom: |
757 | (effect.dims[0] - effect.element.clientHeight) + 'px' }); |
758 | }, |
759 | afterFinishInternal: function(effect) { |
760 | effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom}); |
761 | effect.element.down().undoPositioned(); |
762 | } |
763 | }, arguments[1] || {}) |
764 | ); |
765 | } |
766 | |
767 | // Bug in opera makes the TD containing this element expand for a instance after finish |
768 | Effect.Squish = function(element) { |
769 | return new Effect.Scale(element, window.opera ? 1 : 0, { |
770 | restoreAfterFinish: true, |
771 | beforeSetup: function(effect) { |
772 | effect.element.makeClipping(); |
773 | }, |
774 | afterFinishInternal: function(effect) { |
775 | effect.element.hide().undoClipping(); |
776 | } |
777 | }); |
778 | } |
779 | |
780 | Effect.Grow = function(element) { |
781 | element = $(element); |
782 | var options = Object.extend({ |
783 | direction: 'center', |
784 | moveTransition: Effect.Transitions.sinoidal, |
785 | scaleTransition: Effect.Transitions.sinoidal, |
786 | opacityTransition: Effect.Transitions.full |
787 | }, arguments[1] || {}); |
788 | var oldStyle = { |
789 | top: element.style.top, |
790 | left: element.style.left, |
791 | height: element.style.height, |
792 | width: element.style.width, |
793 | opacity: element.getInlineOpacity() }; |
794 | |
795 | var dims = element.getDimensions(); |
796 | var initialMoveX, initialMoveY; |
797 | var moveX, moveY; |
798 | |
799 | switch (options.direction) { |
800 | case 'top-left': |
801 | initialMoveX = initialMoveY = moveX = moveY = 0; |
802 | break; |
803 | case 'top-right': |
804 | initialMoveX = dims.width; |
805 | initialMoveY = moveY = 0; |
806 | moveX = -dims.width; |
807 | break; |
808 | case 'bottom-left': |
809 | initialMoveX = moveX = 0; |
810 | initialMoveY = dims.height; |
811 | moveY = -dims.height; |
812 | break; |
813 | case 'bottom-right': |
814 | initialMoveX = dims.width; |
815 | initialMoveY = dims.height; |
816 | moveX = -dims.width; |
817 | moveY = -dims.height; |
818 | break; |
819 | case 'center': |
820 | initialMoveX = dims.width / 2; |
821 | initialMoveY = dims.height / 2; |
822 | moveX = -dims.width / 2; |
823 | moveY = -dims.height / 2; |
824 | break; |
825 | } |
826 | |
827 | return new Effect.Move(element, { |
828 | x: initialMoveX, |
829 | y: initialMoveY, |
830 | duration: 0.01, |
831 | beforeSetup: function(effect) { |
832 | effect.element.hide().makeClipping().makePositioned(); |
833 | }, |
834 | afterFinishInternal: function(effect) { |
835 | new Effect.Parallel( |
836 | [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }), |
837 | new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }), |
838 | new Effect.Scale(effect.element, 100, { |
839 | scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, |
840 | sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true}) |
841 | ], Object.extend({ |
842 | beforeSetup: function(effect) { |
843 | effect.effects[0].element.setStyle({height: '0px'}).show(); |
844 | }, |
845 | afterFinishInternal: function(effect) { |
846 | effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); |
847 | } |
848 | }, options) |
849 | ) |
850 | } |
851 | }); |
852 | } |
853 | |
854 | Effect.Shrink = function(element) { |
855 | element = $(element); |
856 | var options = Object.extend({ |
857 | direction: 'center', |
858 | moveTransition: Effect.Transitions.sinoidal, |
859 | scaleTransition: Effect.Transitions.sinoidal, |
860 | opacityTransition: Effect.Transitions.none |
861 | }, arguments[1] || {}); |
862 | var oldStyle = { |
863 | top: element.style.top, |
864 | left: element.style.left, |
865 | height: element.style.height, |
866 | width: element.style.width, |
867 | opacity: element.getInlineOpacity() }; |
868 | |
869 | var dims = element.getDimensions(); |
870 | var moveX, moveY; |
871 | |
872 | switch (options.direction) { |
873 | case 'top-left': |
874 | moveX = moveY = 0; |
875 | break; |
876 | case 'top-right': |
877 | moveX = dims.width; |
878 | moveY = 0; |
879 | break; |
880 | case 'bottom-left': |
881 | moveX = 0; |
882 | moveY = dims.height; |
883 | break; |
884 | case 'bottom-right': |
885 | moveX = dims.width; |
886 | moveY = dims.height; |
887 | break; |
888 | case 'center': |
889 | moveX = dims.width / 2; |
890 | moveY = dims.height / 2; |
891 | break; |
892 | } |
893 | |
894 | return new Effect.Parallel( |
895 | [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }), |
896 | new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}), |
897 | new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }) |
898 | ], Object.extend({ |
899 | beforeStartInternal: function(effect) { |
900 | effect.effects[0].element.makePositioned().makeClipping(); |
901 | }, |
902 | afterFinishInternal: function(effect) { |
903 | effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); } |
904 | }, options) |
905 | ); |
906 | } |
907 | |
908 | Effect.Pulsate = function(element) { |
909 | element = $(element); |
910 | var options = arguments[1] || {}; |
911 | var oldOpacity = element.getInlineOpacity(); |
912 | var transition = options.transition || Effect.Transitions.sinoidal; |
913 | var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) }; |
914 | reverser.bind(transition); |
915 | return new Effect.Opacity(element, |
916 | Object.extend(Object.extend({ duration: 2.0, from: 0, |
917 | afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); } |
918 | }, options), {transition: reverser})); |
919 | } |
920 | |
921 | Effect.Fold = function(element) { |
922 | element = $(element); |
923 | var oldStyle = { |
924 | top: element.style.top, |
925 | left: element.style.left, |
926 | width: element.style.width, |
927 | height: element.style.height }; |
928 | element.makeClipping(); |
929 | return new Effect.Scale(element, 5, Object.extend({ |
930 | scaleContent: false, |
931 | scaleX: false, |
932 | afterFinishInternal: function(effect) { |
933 | new Effect.Scale(element, 1, { |
934 | scaleContent: false, |
935 | scaleY: false, |
936 | afterFinishInternal: function(effect) { |
937 | effect.element.hide().undoClipping().setStyle(oldStyle); |
938 | } }); |
939 | }}, arguments[1] || {})); |
940 | }; |
941 | |
942 | Effect.Morph = Class.create(); |
943 | Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), { |
944 | initialize: function(element) { |
945 | this.element = $(element); |
946 | if(!this.element) throw(Effect._elementDoesNotExistError); |
947 | var options = Object.extend({ |
948 | style: '' |
949 | }, arguments[1] || {}); |
950 | this.start(options); |
951 | }, |
952 | setup: function(){ |
953 | function parseColor(color){ |
954 | if(!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff'; |
955 | color = color.parseColor(); |
956 | return $R(0,2).map(function(i){ |
957 | return parseInt( color.slice(i*2+1,i*2+3), 16 ) |
958 | }); |
959 | } |
960 | this.transforms = this.options.style.parseStyle().map(function(property){ |
961 | var originalValue = this.element.getStyle(property[0]); |
962 | return $H({ |
963 | style: property[0], |
964 | originalValue: property[1].unit=='color' ? |
965 | parseColor(originalValue) : parseFloat(originalValue || 0), |
966 | targetValue: property[1].unit=='color' ? |
967 | parseColor(property[1].value) : property[1].value, |
968 | unit: property[1].unit |
969 | }); |
970 | }.bind(this)).reject(function(transform){ |
971 | return ( |
972 | (transform.originalValue == transform.targetValue) || |
973 | ( |
974 | transform.unit != 'color' && |
975 | (isNaN(transform.originalValue) || isNaN(transform.targetValue)) |
976 | ) |
977 | ) |
978 | }); |
979 | }, |
980 | update: function(position) { |
981 | var style = $H(), value = null; |
982 | this.transforms.each(function(transform){ |
983 | value = transform.unit=='color' ? |
984 | $R(0,2).inject('#',function(m,v,i){ |
985 | return m+(Math.round(transform.originalValue[i]+ |
986 | (transform.targetValue[i] - transform.originalValue[i])*position)).toColorPart() }) : |
987 | transform.originalValue + Math.round( |
988 | ((transform.targetValue - transform.originalValue) * position) * 1000)/1000 + transform.unit; |
989 | style[transform.style] = value; |
990 | }); |
991 | this.element.setStyle(style); |
992 | } |
993 | }); |
994 | |
995 | Effect.Transform = Class.create(); |
996 | Object.extend(Effect.Transform.prototype, { |
997 | initialize: function(tracks){ |
998 | this.tracks = []; |
999 | this.options = arguments[1] || {}; |
1000 | this.addTracks(tracks); |
1001 | }, |
1002 | addTracks: function(tracks){ |
1003 | tracks.each(function(track){ |
1004 | var data = $H(track).values().first(); |
1005 | this.tracks.push($H({ |
1006 | ids: $H(track).keys().first(), |
1007 | effect: Effect.Morph, |
1008 | options: { style: data } |
1009 | })); |
1010 | }.bind(this)); |
1011 | return this; |
1012 | }, |
1013 | play: function(){ |
1014 | return new Effect.Parallel( |
1015 | this.tracks.map(function(track){ |
1016 | var elements = [$(track.ids) || $$(track.ids)].flatten(); |
1017 | return elements.map(function(e){ return new track.effect(e, Object.extend({ sync:true }, track.options)) }); |
1018 | }).flatten(), |
1019 | this.options |
1020 | ); |
1021 | } |
1022 | }); |
1023 | |
1024 | Element.CSS_PROPERTIES = ['azimuth', 'backgroundAttachment', 'backgroundColor', 'backgroundImage', |
1025 | 'backgroundPosition', 'backgroundRepeat', 'borderBottomColor', 'borderBottomStyle', |
1026 | 'borderBottomWidth', 'borderCollapse', 'borderLeftColor', 'borderLeftStyle', 'borderLeftWidth', |
1027 | 'borderRightColor', 'borderRightStyle', 'borderRightWidth', 'borderSpacing', 'borderTopColor', |
1028 | 'borderTopStyle', 'borderTopWidth', 'bottom', 'captionSide', 'clear', 'clip', 'color', 'content', |
1029 | 'counterIncrement', 'counterReset', 'cssFloat', 'cueAfter', 'cueBefore', 'cursor', 'direction', |
1030 | 'display', 'elevation', 'emptyCells', 'fontFamily', 'fontSize', 'fontSizeAdjust', 'fontStretch', |
1031 | 'fontStyle', 'fontVariant', 'fontWeight', 'height', 'left', 'letterSpacing', 'lineHeight', |
1032 | 'listStyleImage', 'listStylePosition', 'listStyleType', 'marginBottom', 'marginLeft', 'marginRight', |
1033 | 'marginTop', 'markerOffset', 'marks', 'maxHeight', 'maxWidth', 'minHeight', 'minWidth', 'opacity', |
1034 | 'orphans', 'outlineColor', 'outlineOffset', 'outlineStyle', 'outlineWidth', 'overflowX', 'overflowY', |
1035 | 'paddingBottom', 'paddingLeft', 'paddingRight', 'paddingTop', 'page', 'pageBreakAfter', 'pageBreakBefore', |
1036 | 'pageBreakInside', 'pauseAfter', 'pauseBefore', 'pitch', 'pitchRange', 'position', 'quotes', |
1037 | 'richness', 'right', 'size', 'speakHeader', 'speakNumeral', 'speakPunctuation', 'speechRate', 'stress', |
1038 | 'tableLayout', 'textAlign', 'textDecoration', 'textIndent', 'textShadow', 'textTransform', 'top', |
1039 | 'unicodeBidi', 'verticalAlign', 'visibility', 'voiceFamily', 'volume', 'whiteSpace', 'widows', |
1040 | 'width', 'wordSpacing', 'zIndex']; |
1041 | |
1042 | Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/; |
1043 | |
1044 | String.prototype.parseStyle = function(){ |
1045 | var element = Element.extend(document.createElement('div')); |
1046 | element.innerHTML = '<div style="' + this + '"></div>'; |
1047 | var style = element.down().style, styleRules = $H(); |
1048 | |
1049 | Element.CSS_PROPERTIES.each(function(property){ |
1050 | if(style[property]) styleRules[property] = style[property]; |
1051 | }); |
1052 | |
1053 | var result = $H(); |
1054 | |
1055 | styleRules.each(function(pair){ |
1056 | var property = pair[0], value = pair[1], unit = null; |
1057 | |
1058 | if(value.parseColor('#zzzzzz') != '#zzzzzz') { |
1059 | value = value.parseColor(); |
1060 | unit = 'color'; |
1061 | } else if(Element.CSS_LENGTH.test(value)) |
1062 | var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/), |
1063 | value = parseFloat(components[1]), unit = (components.length == 3) ? components[2] : null; |
1064 | |
1065 | result[property.underscore().dasherize()] = $H({ value:value, unit:unit }); |
1066 | }.bind(this)); |
1067 | |
1068 | return result; |
1069 | }; |
1070 | |
1071 | Element.morph = function(element, style) { |
1072 | new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {})); |
1073 | return element; |
1074 | }; |
1075 | |
1076 | ['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom', |
1077 | 'collectTextNodes','collectTextNodesIgnoreClass','morph'].each( |
1078 | function(f) { Element.Methods[f] = Element[f]; } |
1079 | ); |
1080 | |
1081 | Element.Methods.visualEffect = function(element, effect, options) { |
1082 | s = effect.gsub(/_/, '-').camelize(); |
1083 | effect_class = s.charAt(0).toUpperCase() + s.substring(1); |
1084 | new Effect[effect_class](element, options); |
1085 | return $(element); |
1086 | }; |
1087 | |
1088 | Element.addMethods(); |