bivouac 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/README +6 -7
  2. data/bin/bivouac +1 -1
  3. data/doc/rdoc/classes/BivouacHelpers/BaseView.html +178 -0
  4. data/doc/rdoc/classes/BivouacHelpers/FormView.html +398 -0
  5. data/doc/rdoc/classes/BivouacHelpers/HtmlView.html +305 -0
  6. data/doc/rdoc/classes/BivouacHelpers/JavaScriptView.html +573 -0
  7. data/doc/rdoc/classes/BivouacHelpers/ScriptAculoUsView.html +258 -0
  8. data/doc/rdoc/classes/BivouacHelpers/TooltipView.html +158 -0
  9. data/doc/rdoc/classes/BivouacHelpers.html +117 -0
  10. data/doc/rdoc/classes/JavaScriptGenerator.html +564 -0
  11. data/doc/rdoc/created.rid +1 -0
  12. data/doc/rdoc/files/AUTHORS.html +109 -0
  13. data/doc/rdoc/files/COPYING.html +533 -0
  14. data/doc/rdoc/files/README.html +427 -0
  15. data/doc/rdoc/files/lib/bivouac/helpers/view/goh/base_rb.html +109 -0
  16. data/doc/rdoc/files/lib/bivouac/helpers/view/goh/form_rb.html +109 -0
  17. data/doc/rdoc/files/lib/bivouac/helpers/view/goh/html_rb.html +109 -0
  18. data/doc/rdoc/files/lib/bivouac/helpers/view/goh/javascript_rb.html +113 -0
  19. data/doc/rdoc/files/lib/bivouac/helpers/view/goh/scriptaculous_rb.html +113 -0
  20. data/doc/rdoc/files/lib/bivouac/helpers/view/goh/tooltip_rb.html +109 -0
  21. data/doc/rdoc/index.html +10 -0
  22. data/doc/rdoc/permalink.gif +0 -0
  23. data/doc/rdoc/rdoc-style.css +106 -0
  24. data/doc/rdoc/rubyfr.png +0 -0
  25. data/examples/bivouac_sample/Rakefile +48 -0
  26. data/examples/bivouac_sample/app/bivouac_sample.rb +15 -7
  27. data/examples/bivouac_sample/app/controllers/index.rb +2 -2
  28. data/examples/bivouac_sample/app/controllers/sound.rb +10 -0
  29. data/examples/bivouac_sample/app/helpers/_helpers.rb +6 -3
  30. data/examples/bivouac_sample/app/views/sound.rb +16 -0
  31. data/examples/bivouac_sample/config/environment.rb +5 -2
  32. data/examples/bivouac_sample/config/postamble.rb +89 -18
  33. data/examples/bivouac_sample/public/javascripts/builder.js +12 -7
  34. data/examples/bivouac_sample/public/javascripts/controls.js +485 -355
  35. data/examples/bivouac_sample/public/javascripts/dragdrop.js +82 -52
  36. data/examples/bivouac_sample/public/javascripts/effects.js +361 -329
  37. data/examples/bivouac_sample/public/javascripts/prototype.js +2826 -1120
  38. data/examples/bivouac_sample/public/javascripts/scriptaculous.js +15 -8
  39. data/examples/bivouac_sample/public/javascripts/slider.js +40 -43
  40. data/examples/bivouac_sample/public/javascripts/sound.js +55 -0
  41. data/examples/bivouac_sample/public/javascripts/unittest.js +16 -12
  42. data/examples/bivouac_sample/public/sound/sword.mp3 +0 -0
  43. data/examples/bivouac_sample/script/console +6 -0
  44. data/examples/bivouac_sample/script/plugin +3 -0
  45. data/examples/bivouac_sample/script/server +2 -1
  46. data/examples/bivouac_sample/test/test_sound.rb +15 -0
  47. data/lib/bivouac/helpers/view/goh/sound.rb +38 -0
  48. data/lib/bivouac/template/application/helpers_goh.rb +2 -0
  49. data/lib/bivouac/template/static/builder.js +12 -7
  50. data/lib/bivouac/template/static/controls.js +485 -355
  51. data/lib/bivouac/template/static/dragdrop.js +82 -52
  52. data/lib/bivouac/template/static/effects.js +361 -329
  53. data/lib/bivouac/template/static/prototype.js +2826 -1120
  54. data/lib/bivouac/template/static/scriptaculous.js +15 -8
  55. data/lib/bivouac/template/static/slider.js +40 -43
  56. data/lib/bivouac/template/static/sound.js +55 -0
  57. data/lib/bivouac/template/static/unittest.js +16 -12
  58. metadata +45 -2
@@ -1,6 +1,6 @@
1
- // script.aculo.us effects.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
1
+ // script.aculo.us effects.js v1.8.1, Thu Jan 03 22:07:12 -0500 2008
2
2
 
3
- // Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
3
+ // Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
4
4
  // Contributors:
5
5
  // Justin Palmer (http://encytemedia.com/)
6
6
  // Mark Pilgrim (http://diveintomark.org/)
@@ -13,17 +13,17 @@
13
13
  // returns self (or first argument) if not convertable
14
14
  String.prototype.parseColor = function() {
15
15
  var color = '#';
16
- if(this.slice(0,4) == 'rgb(') {
16
+ if (this.slice(0,4) == 'rgb(') {
17
17
  var cols = this.slice(4,this.length-1).split(',');
18
18
  var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
19
19
  } else {
20
- if(this.slice(0,1) == '#') {
21
- if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
22
- if(this.length==7) color = this.toLowerCase();
20
+ if (this.slice(0,1) == '#') {
21
+ if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
22
+ if (this.length==7) color = this.toLowerCase();
23
23
  }
24
24
  }
25
- return(color.length==7 ? color : (arguments[0] || this));
26
- }
25
+ return (color.length==7 ? color : (arguments[0] || this));
26
+ };
27
27
 
28
28
  /*--------------------------------------------------------------------------*/
29
29
 
@@ -32,7 +32,7 @@ Element.collectTextNodes = function(element) {
32
32
  return (node.nodeType==3 ? node.nodeValue :
33
33
  (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
34
34
  }).flatten().join('');
35
- }
35
+ };
36
36
 
37
37
  Element.collectTextNodesIgnoreClass = function(element, className) {
38
38
  return $A($(element).childNodes).collect( function(node) {
@@ -40,26 +40,18 @@ Element.collectTextNodesIgnoreClass = function(element, className) {
40
40
  ((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
41
41
  Element.collectTextNodesIgnoreClass(node, className) : ''));
42
42
  }).flatten().join('');
43
- }
43
+ };
44
44
 
45
45
  Element.setContentZoom = function(element, percent) {
46
46
  element = $(element);
47
47
  element.setStyle({fontSize: (percent/100) + 'em'});
48
- if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
48
+ if (Prototype.Browser.WebKit) window.scrollBy(0,0);
49
49
  return element;
50
- }
51
-
52
- Element.getOpacity = function(element){
53
- return $(element).getStyle('opacity');
54
- }
55
-
56
- Element.setOpacity = function(element, value){
57
- return $(element).setStyle({opacity:value});
58
- }
50
+ };
59
51
 
60
52
  Element.getInlineOpacity = function(element){
61
53
  return $(element).style.opacity || '';
62
- }
54
+ };
63
55
 
64
56
  Element.forceRerendering = function(element) {
65
57
  try {
@@ -72,31 +64,63 @@ Element.forceRerendering = function(element) {
72
64
 
73
65
  /*--------------------------------------------------------------------------*/
74
66
 
75
- Array.prototype.call = function() {
76
- var args = arguments;
77
- this.each(function(f){ f.apply(this, args) });
78
- }
79
-
80
- /*--------------------------------------------------------------------------*/
81
-
82
67
  var Effect = {
83
68
  _elementDoesNotExistError: {
84
69
  name: 'ElementDoesNotExistError',
85
70
  message: 'The specified DOM element does not exist, but is required for this effect to operate'
86
71
  },
72
+ Transitions: {
73
+ linear: Prototype.K,
74
+ sinoidal: function(pos) {
75
+ return (-Math.cos(pos*Math.PI)/2) + 0.5;
76
+ },
77
+ reverse: function(pos) {
78
+ return 1-pos;
79
+ },
80
+ flicker: function(pos) {
81
+ var pos = ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
82
+ return pos > 1 ? 1 : pos;
83
+ },
84
+ wobble: function(pos) {
85
+ return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
86
+ },
87
+ pulse: function(pos, pulses) {
88
+ pulses = pulses || 5;
89
+ return (
90
+ ((pos % (1/pulses)) * pulses).round() == 0 ?
91
+ ((pos * pulses * 2) - (pos * pulses * 2).floor()) :
92
+ 1 - ((pos * pulses * 2) - (pos * pulses * 2).floor())
93
+ );
94
+ },
95
+ spring: function(pos) {
96
+ return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
97
+ },
98
+ none: function(pos) {
99
+ return 0;
100
+ },
101
+ full: function(pos) {
102
+ return 1;
103
+ }
104
+ },
105
+ DefaultOptions: {
106
+ duration: 1.0, // seconds
107
+ fps: 100, // 100= assume 66fps max.
108
+ sync: false, // true for combining
109
+ from: 0.0,
110
+ to: 1.0,
111
+ delay: 0.0,
112
+ queue: 'parallel'
113
+ },
87
114
  tagifyText: function(element) {
88
- if(typeof Builder == 'undefined')
89
- throw("Effect.tagifyText requires including script.aculo.us' builder.js library");
90
-
91
115
  var tagifyStyle = 'position:relative';
92
- if(/MSIE/.test(navigator.userAgent) && !window.opera) tagifyStyle += ';zoom:1';
116
+ if (Prototype.Browser.IE) tagifyStyle += ';zoom:1';
93
117
 
94
118
  element = $(element);
95
119
  $A(element.childNodes).each( function(child) {
96
- if(child.nodeType==3) {
120
+ if (child.nodeType==3) {
97
121
  child.nodeValue.toArray().each( function(character) {
98
122
  element.insertBefore(
99
- Builder.node('span',{style: tagifyStyle},
123
+ new Element('span', {style: tagifyStyle}).update(
100
124
  character == ' ' ? String.fromCharCode(160) : character),
101
125
  child);
102
126
  });
@@ -106,8 +130,8 @@ var Effect = {
106
130
  },
107
131
  multiple: function(element, effect) {
108
132
  var elements;
109
- if(((typeof element == 'object') ||
110
- (typeof element == 'function')) &&
133
+ if (((typeof element == 'object') ||
134
+ Object.isFunction(element)) &&
111
135
  (element.length))
112
136
  elements = element;
113
137
  else
@@ -116,7 +140,7 @@ var Effect = {
116
140
  var options = Object.extend({
117
141
  speed: 0.1,
118
142
  delay: 0.0
119
- }, arguments[2] || {});
143
+ }, arguments[2] || { });
120
144
  var masterDelay = options.delay;
121
145
 
122
146
  $A(elements).each( function(element, index) {
@@ -133,53 +157,20 @@ var Effect = {
133
157
  effect = (effect || 'appear').toLowerCase();
134
158
  var options = Object.extend({
135
159
  queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
136
- }, arguments[2] || {});
160
+ }, arguments[2] || { });
137
161
  Effect[element.visible() ?
138
162
  Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
139
163
  }
140
164
  };
141
165
 
142
- var Effect2 = Effect; // deprecated
143
-
144
- /* ------------- transitions ------------- */
145
-
146
- Effect.Transitions = {
147
- linear: Prototype.K,
148
- sinoidal: function(pos) {
149
- return (-Math.cos(pos*Math.PI)/2) + 0.5;
150
- },
151
- reverse: function(pos) {
152
- return 1-pos;
153
- },
154
- flicker: function(pos) {
155
- return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
156
- },
157
- wobble: function(pos) {
158
- return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
159
- },
160
- pulse: function(pos, pulses) {
161
- pulses = pulses || 5;
162
- return (
163
- Math.round((pos % (1/pulses)) * pulses) == 0 ?
164
- ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) :
165
- 1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2))
166
- );
167
- },
168
- none: function(pos) {
169
- return 0;
170
- },
171
- full: function(pos) {
172
- return 1;
173
- }
174
- };
166
+ Effect.DefaultOptions.transition = Effect.Transitions.sinoidal;
175
167
 
176
168
  /* ------------- core effects ------------- */
177
169
 
178
- Effect.ScopedQueue = Class.create();
179
- Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
170
+ Effect.ScopedQueue = Class.create(Enumerable, {
180
171
  initialize: function() {
181
172
  this.effects = [];
182
- this.interval = null;
173
+ this.interval = null;
183
174
  },
184
175
  _each: function(iterator) {
185
176
  this.effects._each(iterator);
@@ -187,7 +178,7 @@ Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
187
178
  add: function(effect) {
188
179
  var timestamp = new Date().getTime();
189
180
 
190
- var position = (typeof effect.options.queue == 'string') ?
181
+ var position = Object.isString(effect.options.queue) ?
191
182
  effect.options.queue : effect.options.queue.position;
192
183
 
193
184
  switch(position) {
@@ -210,15 +201,15 @@ Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
210
201
  effect.startOn += timestamp;
211
202
  effect.finishOn += timestamp;
212
203
 
213
- if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
204
+ if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
214
205
  this.effects.push(effect);
215
206
 
216
- if(!this.interval)
207
+ if (!this.interval)
217
208
  this.interval = setInterval(this.loop.bind(this), 15);
218
209
  },
219
210
  remove: function(effect) {
220
211
  this.effects = this.effects.reject(function(e) { return e==effect });
221
- if(this.effects.length == 0) {
212
+ if (this.effects.length == 0) {
222
213
  clearInterval(this.interval);
223
214
  this.interval = null;
224
215
  }
@@ -226,103 +217,95 @@ Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
226
217
  loop: function() {
227
218
  var timePos = new Date().getTime();
228
219
  for(var i=0, len=this.effects.length;i<len;i++)
229
- if(this.effects[i]) this.effects[i].loop(timePos);
220
+ this.effects[i] && this.effects[i].loop(timePos);
230
221
  }
231
222
  });
232
223
 
233
224
  Effect.Queues = {
234
225
  instances: $H(),
235
226
  get: function(queueName) {
236
- if(typeof queueName != 'string') return queueName;
227
+ if (!Object.isString(queueName)) return queueName;
237
228
 
238
- if(!this.instances[queueName])
239
- this.instances[queueName] = new Effect.ScopedQueue();
240
-
241
- return this.instances[queueName];
229
+ return this.instances.get(queueName) ||
230
+ this.instances.set(queueName, new Effect.ScopedQueue());
242
231
  }
243
- }
232
+ };
244
233
  Effect.Queue = Effect.Queues.get('global');
245
234
 
246
- Effect.DefaultOptions = {
247
- transition: Effect.Transitions.sinoidal,
248
- duration: 1.0, // seconds
249
- fps: 60.0, // max. 60fps due to Effect.Queue implementation
250
- sync: false, // true for combining
251
- from: 0.0,
252
- to: 1.0,
253
- delay: 0.0,
254
- queue: 'parallel'
255
- }
256
-
257
- Effect.Base = function() {};
258
- Effect.Base.prototype = {
235
+ Effect.Base = Class.create({
259
236
  position: null,
260
237
  start: function(options) {
261
- this.options = Object.extend(Object.extend({},Effect.DefaultOptions), options || {});
238
+ function codeForEvent(options,eventName){
239
+ return (
240
+ (options[eventName+'Internal'] ? 'this.options.'+eventName+'Internal(this);' : '') +
241
+ (options[eventName] ? 'this.options.'+eventName+'(this);' : '')
242
+ );
243
+ }
244
+ if (options && options.transition === false) options.transition = Effect.Transitions.linear;
245
+ this.options = Object.extend(Object.extend({ },Effect.DefaultOptions), options || { });
262
246
  this.currentFrame = 0;
263
247
  this.state = 'idle';
264
248
  this.startOn = this.options.delay*1000;
265
- this.finishOn = this.startOn + (this.options.duration*1000);
249
+ this.finishOn = this.startOn+(this.options.duration*1000);
250
+ this.fromToDelta = this.options.to-this.options.from;
251
+ this.totalTime = this.finishOn-this.startOn;
252
+ this.totalFrames = this.options.fps*this.options.duration;
253
+
254
+ eval('this.render = function(pos){ '+
255
+ 'if (this.state=="idle"){this.state="running";'+
256
+ codeForEvent(this.options,'beforeSetup')+
257
+ (this.setup ? 'this.setup();':'')+
258
+ codeForEvent(this.options,'afterSetup')+
259
+ '};if (this.state=="running"){'+
260
+ 'pos=this.options.transition(pos)*'+this.fromToDelta+'+'+this.options.from+';'+
261
+ 'this.position=pos;'+
262
+ codeForEvent(this.options,'beforeUpdate')+
263
+ (this.update ? 'this.update(pos);':'')+
264
+ codeForEvent(this.options,'afterUpdate')+
265
+ '}}');
266
+
266
267
  this.event('beforeStart');
267
- if(!this.options.sync)
268
- Effect.Queues.get(typeof this.options.queue == 'string' ?
268
+ if (!this.options.sync)
269
+ Effect.Queues.get(Object.isString(this.options.queue) ?
269
270
  'global' : this.options.queue.scope).add(this);
270
271
  },
271
272
  loop: function(timePos) {
272
- if(timePos >= this.startOn) {
273
- if(timePos >= this.finishOn) {
273
+ if (timePos >= this.startOn) {
274
+ if (timePos >= this.finishOn) {
274
275
  this.render(1.0);
275
276
  this.cancel();
276
277
  this.event('beforeFinish');
277
- if(this.finish) this.finish();
278
+ if (this.finish) this.finish();
278
279
  this.event('afterFinish');
279
280
  return;
280
281
  }
281
- var pos = (timePos - this.startOn) / (this.finishOn - this.startOn);
282
- var frame = Math.round(pos * this.options.fps * this.options.duration);
283
- if(frame > this.currentFrame) {
282
+ var pos = (timePos - this.startOn) / this.totalTime,
283
+ frame = (pos * this.totalFrames).round();
284
+ if (frame > this.currentFrame) {
284
285
  this.render(pos);
285
286
  this.currentFrame = frame;
286
287
  }
287
288
  }
288
289
  },
289
- render: function(pos) {
290
- if(this.state == 'idle') {
291
- this.state = 'running';
292
- this.event('beforeSetup');
293
- if(this.setup) this.setup();
294
- this.event('afterSetup');
295
- }
296
- if(this.state == 'running') {
297
- if(this.options.transition) pos = this.options.transition(pos);
298
- pos *= (this.options.to-this.options.from);
299
- pos += this.options.from;
300
- this.position = pos;
301
- this.event('beforeUpdate');
302
- if(this.update) this.update(pos);
303
- this.event('afterUpdate');
304
- }
305
- },
306
290
  cancel: function() {
307
- if(!this.options.sync)
308
- Effect.Queues.get(typeof this.options.queue == 'string' ?
291
+ if (!this.options.sync)
292
+ Effect.Queues.get(Object.isString(this.options.queue) ?
309
293
  'global' : this.options.queue.scope).remove(this);
310
294
  this.state = 'finished';
311
295
  },
312
296
  event: function(eventName) {
313
- if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
314
- if(this.options[eventName]) this.options[eventName](this);
297
+ if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
298
+ if (this.options[eventName]) this.options[eventName](this);
315
299
  },
316
300
  inspect: function() {
317
301
  var data = $H();
318
302
  for(property in this)
319
- if(typeof this[property] != 'function') data[property] = this[property];
303
+ if (!Object.isFunction(this[property])) data.set(property, this[property]);
320
304
  return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
321
305
  }
322
- }
306
+ });
323
307
 
324
- Effect.Parallel = Class.create();
325
- Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
308
+ Effect.Parallel = Class.create(Effect.Base, {
326
309
  initialize: function(effects) {
327
310
  this.effects = effects || [];
328
311
  this.start(arguments[1]);
@@ -335,35 +318,45 @@ Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
335
318
  effect.render(1.0);
336
319
  effect.cancel();
337
320
  effect.event('beforeFinish');
338
- if(effect.finish) effect.finish(position);
321
+ if (effect.finish) effect.finish(position);
339
322
  effect.event('afterFinish');
340
323
  });
341
324
  }
342
325
  });
343
326
 
344
- Effect.Event = Class.create();
345
- Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), {
327
+ Effect.Tween = Class.create(Effect.Base, {
328
+ initialize: function(object, from, to) {
329
+ object = Object.isString(object) ? $(object) : object;
330
+ var args = $A(arguments), method = args.last(),
331
+ options = args.length == 5 ? args[3] : null;
332
+ this.method = Object.isFunction(method) ? method.bind(object) :
333
+ Object.isFunction(object[method]) ? object[method].bind(object) :
334
+ function(value) { object[method] = value };
335
+ this.start(Object.extend({ from: from, to: to }, options || { }));
336
+ },
337
+ update: function(position) {
338
+ this.method(position);
339
+ }
340
+ });
341
+
342
+ Effect.Event = Class.create(Effect.Base, {
346
343
  initialize: function() {
347
- var options = Object.extend({
348
- duration: 0
349
- }, arguments[0] || {});
350
- this.start(options);
344
+ this.start(Object.extend({ duration: 0 }, arguments[0] || { }));
351
345
  },
352
346
  update: Prototype.emptyFunction
353
347
  });
354
348
 
355
- Effect.Opacity = Class.create();
356
- Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
349
+ Effect.Opacity = Class.create(Effect.Base, {
357
350
  initialize: function(element) {
358
351
  this.element = $(element);
359
- if(!this.element) throw(Effect._elementDoesNotExistError);
352
+ if (!this.element) throw(Effect._elementDoesNotExistError);
360
353
  // make this work on IE on elements without 'layout'
361
- if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout))
354
+ if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
362
355
  this.element.setStyle({zoom: 1});
363
356
  var options = Object.extend({
364
357
  from: this.element.getOpacity() || 0.0,
365
358
  to: 1.0
366
- }, arguments[1] || {});
359
+ }, arguments[1] || { });
367
360
  this.start(options);
368
361
  },
369
362
  update: function(position) {
@@ -371,36 +364,30 @@ Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
371
364
  }
372
365
  });
373
366
 
374
- Effect.Move = Class.create();
375
- Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
367
+ Effect.Move = Class.create(Effect.Base, {
376
368
  initialize: function(element) {
377
369
  this.element = $(element);
378
- if(!this.element) throw(Effect._elementDoesNotExistError);
370
+ if (!this.element) throw(Effect._elementDoesNotExistError);
379
371
  var options = Object.extend({
380
372
  x: 0,
381
373
  y: 0,
382
374
  mode: 'relative'
383
- }, arguments[1] || {});
375
+ }, arguments[1] || { });
384
376
  this.start(options);
385
377
  },
386
378
  setup: function() {
387
- // Bug in Opera: Opera returns the "real" position of a static element or
388
- // relative element that does not have top/left explicitly set.
389
- // ==> Always set top and left for position relative elements in your stylesheets
390
- // (to 0 if you do not need them)
391
379
  this.element.makePositioned();
392
380
  this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
393
381
  this.originalTop = parseFloat(this.element.getStyle('top') || '0');
394
- if(this.options.mode == 'absolute') {
395
- // absolute movement, so we need to calc deltaX and deltaY
382
+ if (this.options.mode == 'absolute') {
396
383
  this.options.x = this.options.x - this.originalLeft;
397
384
  this.options.y = this.options.y - this.originalTop;
398
385
  }
399
386
  },
400
387
  update: function(position) {
401
388
  this.element.setStyle({
402
- left: Math.round(this.options.x * position + this.originalLeft) + 'px',
403
- top: Math.round(this.options.y * position + this.originalTop) + 'px'
389
+ left: (this.options.x * position + this.originalLeft).round() + 'px',
390
+ top: (this.options.y * position + this.originalTop).round() + 'px'
404
391
  });
405
392
  }
406
393
  });
@@ -408,30 +395,29 @@ Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
408
395
  // for backwards compatibility
409
396
  Effect.MoveBy = function(element, toTop, toLeft) {
410
397
  return new Effect.Move(element,
411
- Object.extend({ x: toLeft, y: toTop }, arguments[3] || {}));
398
+ Object.extend({ x: toLeft, y: toTop }, arguments[3] || { }));
412
399
  };
413
400
 
414
- Effect.Scale = Class.create();
415
- Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
401
+ Effect.Scale = Class.create(Effect.Base, {
416
402
  initialize: function(element, percent) {
417
403
  this.element = $(element);
418
- if(!this.element) throw(Effect._elementDoesNotExistError);
404
+ if (!this.element) throw(Effect._elementDoesNotExistError);
419
405
  var options = Object.extend({
420
406
  scaleX: true,
421
407
  scaleY: true,
422
408
  scaleContent: true,
423
409
  scaleFromCenter: false,
424
- scaleMode: 'box', // 'box' or 'contents' or {} with provided values
410
+ scaleMode: 'box', // 'box' or 'contents' or { } with provided values
425
411
  scaleFrom: 100.0,
426
412
  scaleTo: percent
427
- }, arguments[2] || {});
413
+ }, arguments[2] || { });
428
414
  this.start(options);
429
415
  },
430
416
  setup: function() {
431
417
  this.restoreAfterFinish = this.options.restoreAfterFinish || false;
432
418
  this.elementPositioning = this.element.getStyle('position');
433
419
 
434
- this.originalStyle = {};
420
+ this.originalStyle = { };
435
421
  ['top','left','width','height','fontSize'].each( function(k) {
436
422
  this.originalStyle[k] = this.element.style[k];
437
423
  }.bind(this));
@@ -441,7 +427,7 @@ Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
441
427
 
442
428
  var fontSize = this.element.getStyle('font-size') || '100%';
443
429
  ['em','px','%','pt'].each( function(fontSizeType) {
444
- if(fontSize.indexOf(fontSizeType)>0) {
430
+ if (fontSize.indexOf(fontSizeType)>0) {
445
431
  this.fontSize = parseFloat(fontSize);
446
432
  this.fontSizeType = fontSizeType;
447
433
  }
@@ -450,62 +436,61 @@ Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
450
436
  this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
451
437
 
452
438
  this.dims = null;
453
- if(this.options.scaleMode=='box')
439
+ if (this.options.scaleMode=='box')
454
440
  this.dims = [this.element.offsetHeight, this.element.offsetWidth];
455
- if(/^content/.test(this.options.scaleMode))
441
+ if (/^content/.test(this.options.scaleMode))
456
442
  this.dims = [this.element.scrollHeight, this.element.scrollWidth];
457
- if(!this.dims)
443
+ if (!this.dims)
458
444
  this.dims = [this.options.scaleMode.originalHeight,
459
445
  this.options.scaleMode.originalWidth];
460
446
  },
461
447
  update: function(position) {
462
448
  var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
463
- if(this.options.scaleContent && this.fontSize)
449
+ if (this.options.scaleContent && this.fontSize)
464
450
  this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
465
451
  this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
466
452
  },
467
453
  finish: function(position) {
468
- if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
454
+ if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
469
455
  },
470
456
  setDimensions: function(height, width) {
471
- var d = {};
472
- if(this.options.scaleX) d.width = Math.round(width) + 'px';
473
- if(this.options.scaleY) d.height = Math.round(height) + 'px';
474
- if(this.options.scaleFromCenter) {
457
+ var d = { };
458
+ if (this.options.scaleX) d.width = width.round() + 'px';
459
+ if (this.options.scaleY) d.height = height.round() + 'px';
460
+ if (this.options.scaleFromCenter) {
475
461
  var topd = (height - this.dims[0])/2;
476
462
  var leftd = (width - this.dims[1])/2;
477
- if(this.elementPositioning == 'absolute') {
478
- if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
479
- if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
463
+ if (this.elementPositioning == 'absolute') {
464
+ if (this.options.scaleY) d.top = this.originalTop-topd + 'px';
465
+ if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
480
466
  } else {
481
- if(this.options.scaleY) d.top = -topd + 'px';
482
- if(this.options.scaleX) d.left = -leftd + 'px';
467
+ if (this.options.scaleY) d.top = -topd + 'px';
468
+ if (this.options.scaleX) d.left = -leftd + 'px';
483
469
  }
484
470
  }
485
471
  this.element.setStyle(d);
486
472
  }
487
473
  });
488
474
 
489
- Effect.Highlight = Class.create();
490
- Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
475
+ Effect.Highlight = Class.create(Effect.Base, {
491
476
  initialize: function(element) {
492
477
  this.element = $(element);
493
- if(!this.element) throw(Effect._elementDoesNotExistError);
494
- var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
478
+ if (!this.element) throw(Effect._elementDoesNotExistError);
479
+ var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { });
495
480
  this.start(options);
496
481
  },
497
482
  setup: function() {
498
483
  // Prevent executing on elements not in the layout flow
499
- if(this.element.getStyle('display')=='none') { this.cancel(); return; }
484
+ if (this.element.getStyle('display')=='none') { this.cancel(); return; }
500
485
  // Disable background image during the effect
501
- this.oldStyle = {};
486
+ this.oldStyle = { };
502
487
  if (!this.options.keepBackgroundImage) {
503
488
  this.oldStyle.backgroundImage = this.element.getStyle('background-image');
504
489
  this.element.setStyle({backgroundImage: 'none'});
505
490
  }
506
- if(!this.options.endcolor)
491
+ if (!this.options.endcolor)
507
492
  this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
508
- if(!this.options.restorecolor)
493
+ if (!this.options.restorecolor)
509
494
  this.options.restorecolor = this.element.getStyle('background-color');
510
495
  // init color calculations
511
496
  this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
@@ -513,7 +498,7 @@ Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype),
513
498
  },
514
499
  update: function(position) {
515
500
  this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
516
- return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) });
501
+ return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) });
517
502
  },
518
503
  finish: function() {
519
504
  this.element.setStyle(Object.extend(this.oldStyle, {
@@ -522,30 +507,21 @@ Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype),
522
507
  }
523
508
  });
524
509
 
525
- Effect.ScrollTo = Class.create();
526
- Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
527
- initialize: function(element) {
528
- this.element = $(element);
529
- this.start(arguments[1] || {});
530
- },
531
- setup: function() {
532
- Position.prepare();
533
- var offsets = Position.cumulativeOffset(this.element);
534
- if(this.options.offset) offsets[1] += this.options.offset;
535
- var max = window.innerHeight ?
536
- window.height - window.innerHeight :
537
- document.body.scrollHeight -
538
- (document.documentElement.clientHeight ?
539
- document.documentElement.clientHeight : document.body.clientHeight);
540
- this.scrollStart = Position.deltaY;
541
- this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart;
542
- },
543
- update: function(position) {
544
- Position.prepare();
545
- window.scrollTo(Position.deltaX,
546
- this.scrollStart + (position*this.delta));
547
- }
548
- });
510
+ Effect.ScrollTo = function(element) {
511
+ var options = arguments[1] || { },
512
+ scrollOffsets = document.viewport.getScrollOffsets(),
513
+ elementOffsets = $(element).cumulativeOffset(),
514
+ max = (window.height || document.body.scrollHeight) - document.viewport.getHeight();
515
+
516
+ if (options.offset) elementOffsets[1] += options.offset;
517
+
518
+ return new Effect.Tween(null,
519
+ scrollOffsets.top,
520
+ elementOffsets[1] > max ? max : elementOffsets[1],
521
+ options,
522
+ function(p){ scrollTo(scrollOffsets.left, p.round()) }
523
+ );
524
+ };
549
525
 
550
526
  /* ------------- combination effects ------------- */
551
527
 
@@ -553,14 +529,15 @@ Effect.Fade = function(element) {
553
529
  element = $(element);
554
530
  var oldOpacity = element.getInlineOpacity();
555
531
  var options = Object.extend({
556
- from: element.getOpacity() || 1.0,
557
- to: 0.0,
558
- afterFinishInternal: function(effect) {
559
- if(effect.options.to!=0) return;
560
- effect.element.hide().setStyle({opacity: oldOpacity});
561
- }}, arguments[1] || {});
532
+ from: element.getOpacity() || 1.0,
533
+ to: 0.0,
534
+ afterFinishInternal: function(effect) {
535
+ if (effect.options.to!=0) return;
536
+ effect.element.hide().setStyle({opacity: oldOpacity});
537
+ }
538
+ }, arguments[1] || { });
562
539
  return new Effect.Opacity(element,options);
563
- }
540
+ };
564
541
 
565
542
  Effect.Appear = function(element) {
566
543
  element = $(element);
@@ -573,9 +550,9 @@ Effect.Appear = function(element) {
573
550
  },
574
551
  beforeSetup: function(effect) {
575
552
  effect.element.setOpacity(effect.options.from).show();
576
- }}, arguments[1] || {});
553
+ }}, arguments[1] || { });
577
554
  return new Effect.Opacity(element,options);
578
- }
555
+ };
579
556
 
580
557
  Effect.Puff = function(element) {
581
558
  element = $(element);
@@ -597,9 +574,9 @@ Effect.Puff = function(element) {
597
574
  },
598
575
  afterFinishInternal: function(effect) {
599
576
  effect.effects[0].element.hide().setStyle(oldStyle); }
600
- }, arguments[1] || {})
577
+ }, arguments[1] || { })
601
578
  );
602
- }
579
+ };
603
580
 
604
581
  Effect.BlindUp = function(element) {
605
582
  element = $(element);
@@ -611,9 +588,9 @@ Effect.BlindUp = function(element) {
611
588
  afterFinishInternal: function(effect) {
612
589
  effect.element.hide().undoClipping();
613
590
  }
614
- }, arguments[1] || {})
591
+ }, arguments[1] || { })
615
592
  );
616
- }
593
+ };
617
594
 
618
595
  Effect.BlindDown = function(element) {
619
596
  element = $(element);
@@ -630,8 +607,8 @@ Effect.BlindDown = function(element) {
630
607
  afterFinishInternal: function(effect) {
631
608
  effect.element.undoClipping();
632
609
  }
633
- }, arguments[1] || {}));
634
- }
610
+ }, arguments[1] || { }));
611
+ };
635
612
 
636
613
  Effect.SwitchOff = function(element) {
637
614
  element = $(element);
@@ -652,8 +629,8 @@ Effect.SwitchOff = function(element) {
652
629
  }
653
630
  })
654
631
  }
655
- }, arguments[1] || {}));
656
- }
632
+ }, arguments[1] || { }));
633
+ };
657
634
 
658
635
  Effect.DropOut = function(element) {
659
636
  element = $(element);
@@ -672,29 +649,35 @@ Effect.DropOut = function(element) {
672
649
  afterFinishInternal: function(effect) {
673
650
  effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
674
651
  }
675
- }, arguments[1] || {}));
676
- }
652
+ }, arguments[1] || { }));
653
+ };
677
654
 
678
655
  Effect.Shake = function(element) {
679
656
  element = $(element);
657
+ var options = Object.extend({
658
+ distance: 20,
659
+ duration: 0.5
660
+ }, arguments[1] || {});
661
+ var distance = parseFloat(options.distance);
662
+ var split = parseFloat(options.duration) / 10.0;
680
663
  var oldStyle = {
681
664
  top: element.getStyle('top'),
682
665
  left: element.getStyle('left') };
683
- return new Effect.Move(element,
684
- { x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
666
+ return new Effect.Move(element,
667
+ { x: distance, y: 0, duration: split, afterFinishInternal: function(effect) {
685
668
  new Effect.Move(effect.element,
686
- { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
669
+ { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
687
670
  new Effect.Move(effect.element,
688
- { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
671
+ { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
689
672
  new Effect.Move(effect.element,
690
- { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
673
+ { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
691
674
  new Effect.Move(effect.element,
692
- { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
675
+ { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
693
676
  new Effect.Move(effect.element,
694
- { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
677
+ { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) {
695
678
  effect.element.undoPositioned().setStyle(oldStyle);
696
679
  }}) }}) }}) }}) }}) }});
697
- }
680
+ };
698
681
 
699
682
  Effect.SlideDown = function(element) {
700
683
  element = $(element).cleanWhitespace();
@@ -710,7 +693,7 @@ Effect.SlideDown = function(element) {
710
693
  afterSetup: function(effect) {
711
694
  effect.element.makePositioned();
712
695
  effect.element.down().makePositioned();
713
- if(window.opera) effect.element.setStyle({top: ''});
696
+ if (window.opera) effect.element.setStyle({top: ''});
714
697
  effect.element.makeClipping().setStyle({height: '0px'}).show();
715
698
  },
716
699
  afterUpdateInternal: function(effect) {
@@ -720,23 +703,25 @@ Effect.SlideDown = function(element) {
720
703
  afterFinishInternal: function(effect) {
721
704
  effect.element.undoClipping().undoPositioned();
722
705
  effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
723
- }, arguments[1] || {})
706
+ }, arguments[1] || { })
724
707
  );
725
- }
708
+ };
726
709
 
727
710
  Effect.SlideUp = function(element) {
728
711
  element = $(element).cleanWhitespace();
729
712
  var oldInnerBottom = element.down().getStyle('bottom');
713
+ var elementDimensions = element.getDimensions();
730
714
  return new Effect.Scale(element, window.opera ? 0 : 1,
731
715
  Object.extend({ scaleContent: false,
732
716
  scaleX: false,
733
717
  scaleMode: 'box',
734
718
  scaleFrom: 100,
719
+ scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
735
720
  restoreAfterFinish: true,
736
- beforeStartInternal: function(effect) {
721
+ afterSetup: function(effect) {
737
722
  effect.element.makePositioned();
738
723
  effect.element.down().makePositioned();
739
- if(window.opera) effect.element.setStyle({top: ''});
724
+ if (window.opera) effect.element.setStyle({top: ''});
740
725
  effect.element.makeClipping().show();
741
726
  },
742
727
  afterUpdateInternal: function(effect) {
@@ -744,12 +729,12 @@ Effect.SlideUp = function(element) {
744
729
  (effect.dims[0] - effect.element.clientHeight) + 'px' });
745
730
  },
746
731
  afterFinishInternal: function(effect) {
747
- effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom});
748
- effect.element.down().undoPositioned();
732
+ effect.element.hide().undoClipping().undoPositioned();
733
+ effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom});
749
734
  }
750
- }, arguments[1] || {})
735
+ }, arguments[1] || { })
751
736
  );
752
- }
737
+ };
753
738
 
754
739
  // Bug in opera makes the TD containing this element expand for a instance after finish
755
740
  Effect.Squish = function(element) {
@@ -762,7 +747,7 @@ Effect.Squish = function(element) {
762
747
  effect.element.hide().undoClipping();
763
748
  }
764
749
  });
765
- }
750
+ };
766
751
 
767
752
  Effect.Grow = function(element) {
768
753
  element = $(element);
@@ -771,7 +756,7 @@ Effect.Grow = function(element) {
771
756
  moveTransition: Effect.Transitions.sinoidal,
772
757
  scaleTransition: Effect.Transitions.sinoidal,
773
758
  opacityTransition: Effect.Transitions.full
774
- }, arguments[1] || {});
759
+ }, arguments[1] || { });
775
760
  var oldStyle = {
776
761
  top: element.style.top,
777
762
  left: element.style.left,
@@ -836,7 +821,7 @@ Effect.Grow = function(element) {
836
821
  )
837
822
  }
838
823
  });
839
- }
824
+ };
840
825
 
841
826
  Effect.Shrink = function(element) {
842
827
  element = $(element);
@@ -845,7 +830,7 @@ Effect.Shrink = function(element) {
845
830
  moveTransition: Effect.Transitions.sinoidal,
846
831
  scaleTransition: Effect.Transitions.sinoidal,
847
832
  opacityTransition: Effect.Transitions.none
848
- }, arguments[1] || {});
833
+ }, arguments[1] || { });
849
834
  var oldStyle = {
850
835
  top: element.style.top,
851
836
  left: element.style.left,
@@ -890,11 +875,11 @@ Effect.Shrink = function(element) {
890
875
  effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
891
876
  }, options)
892
877
  );
893
- }
878
+ };
894
879
 
895
880
  Effect.Pulsate = function(element) {
896
881
  element = $(element);
897
- var options = arguments[1] || {};
882
+ var options = arguments[1] || { };
898
883
  var oldOpacity = element.getInlineOpacity();
899
884
  var transition = options.transition || Effect.Transitions.sinoidal;
900
885
  var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) };
@@ -903,7 +888,7 @@ Effect.Pulsate = function(element) {
903
888
  Object.extend(Object.extend({ duration: 2.0, from: 0,
904
889
  afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
905
890
  }, options), {transition: reverser}));
906
- }
891
+ };
907
892
 
908
893
  Effect.Fold = function(element) {
909
894
  element = $(element);
@@ -923,72 +908,71 @@ Effect.Fold = function(element) {
923
908
  afterFinishInternal: function(effect) {
924
909
  effect.element.hide().undoClipping().setStyle(oldStyle);
925
910
  } });
926
- }}, arguments[1] || {}));
911
+ }}, arguments[1] || { }));
927
912
  };
928
913
 
929
- Effect.Morph = Class.create();
930
- Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), {
914
+ Effect.Morph = Class.create(Effect.Base, {
931
915
  initialize: function(element) {
932
916
  this.element = $(element);
933
- if(!this.element) throw(Effect._elementDoesNotExistError);
917
+ if (!this.element) throw(Effect._elementDoesNotExistError);
934
918
  var options = Object.extend({
935
- style: {}
936
- }, arguments[1] || {});
937
- if (typeof options.style == 'string') {
938
- if(options.style.indexOf(':') == -1) {
939
- var cssText = '', selector = '.' + options.style;
940
- $A(document.styleSheets).reverse().each(function(styleSheet) {
941
- if (styleSheet.cssRules) cssRules = styleSheet.cssRules;
942
- else if (styleSheet.rules) cssRules = styleSheet.rules;
943
- $A(cssRules).reverse().each(function(rule) {
944
- if (selector == rule.selectorText) {
945
- cssText = rule.style.cssText;
946
- throw $break;
947
- }
948
- });
949
- if (cssText) throw $break;
919
+ style: { }
920
+ }, arguments[1] || { });
921
+
922
+ if (!Object.isString(options.style)) this.style = $H(options.style);
923
+ else {
924
+ if (options.style.include(':'))
925
+ this.style = options.style.parseStyle();
926
+ else {
927
+ this.element.addClassName(options.style);
928
+ this.style = $H(this.element.getStyles());
929
+ this.element.removeClassName(options.style);
930
+ var css = this.element.getStyles();
931
+ this.style = this.style.reject(function(style) {
932
+ return style.value == css[style.key];
950
933
  });
951
- this.style = cssText.parseStyle();
952
- options.afterFinishInternal = function(effect){
934
+ options.afterFinishInternal = function(effect) {
953
935
  effect.element.addClassName(effect.options.style);
954
936
  effect.transforms.each(function(transform) {
955
- if(transform.style != 'opacity')
956
- effect.element.style[transform.style.camelize()] = '';
937
+ effect.element.style[transform.style] = '';
957
938
  });
958
939
  }
959
- } else this.style = options.style.parseStyle();
960
- } else this.style = $H(options.style)
940
+ }
941
+ }
961
942
  this.start(options);
962
943
  },
944
+
963
945
  setup: function(){
964
946
  function parseColor(color){
965
- if(!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
947
+ if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
966
948
  color = color.parseColor();
967
949
  return $R(0,2).map(function(i){
968
950
  return parseInt( color.slice(i*2+1,i*2+3), 16 )
969
951
  });
970
952
  }
971
953
  this.transforms = this.style.map(function(pair){
972
- var property = pair[0].underscore().dasherize(), value = pair[1], unit = null;
954
+ var property = pair[0], value = pair[1], unit = null;
973
955
 
974
- if(value.parseColor('#zzzzzz') != '#zzzzzz') {
956
+ if (value.parseColor('#zzzzzz') != '#zzzzzz') {
975
957
  value = value.parseColor();
976
958
  unit = 'color';
977
- } else if(property == 'opacity') {
959
+ } else if (property == 'opacity') {
978
960
  value = parseFloat(value);
979
- if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout))
961
+ if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
980
962
  this.element.setStyle({zoom: 1});
981
- } else if(Element.CSS_LENGTH.test(value))
982
- var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/),
983
- value = parseFloat(components[1]), unit = (components.length == 3) ? components[2] : null;
963
+ } else if (Element.CSS_LENGTH.test(value)) {
964
+ var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
965
+ value = parseFloat(components[1]);
966
+ unit = (components.length == 3) ? components[2] : null;
967
+ }
984
968
 
985
969
  var originalValue = this.element.getStyle(property);
986
- return $H({
987
- style: property,
970
+ return {
971
+ style: property.camelize(),
988
972
  originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0),
989
973
  targetValue: unit=='color' ? parseColor(value) : value,
990
974
  unit: unit
991
- });
975
+ };
992
976
  }.bind(this)).reject(function(transform){
993
977
  return (
994
978
  (transform.originalValue == transform.targetValue) ||
@@ -1000,32 +984,35 @@ Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), {
1000
984
  });
1001
985
  },
1002
986
  update: function(position) {
1003
- var style = $H(), value = null;
1004
- this.transforms.each(function(transform){
1005
- value = transform.unit=='color' ?
1006
- $R(0,2).inject('#',function(m,v,i){
1007
- return m+(Math.round(transform.originalValue[i]+
1008
- (transform.targetValue[i] - transform.originalValue[i])*position)).toColorPart() }) :
1009
- transform.originalValue + Math.round(
1010
- ((transform.targetValue - transform.originalValue) * position) * 1000)/1000 + transform.unit;
1011
- style[transform.style] = value;
1012
- });
1013
- this.element.setStyle(style);
987
+ var style = { }, transform, i = this.transforms.length;
988
+ while(i--)
989
+ style[(transform = this.transforms[i]).style] =
990
+ transform.unit=='color' ? '#'+
991
+ (Math.round(transform.originalValue[0]+
992
+ (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
993
+ (Math.round(transform.originalValue[1]+
994
+ (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +
995
+ (Math.round(transform.originalValue[2]+
996
+ (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
997
+ (transform.originalValue +
998
+ (transform.targetValue - transform.originalValue) * position).toFixed(3) +
999
+ (transform.unit === null ? '' : transform.unit);
1000
+ this.element.setStyle(style, true);
1014
1001
  }
1015
1002
  });
1016
1003
 
1017
- Effect.Transform = Class.create();
1018
- Object.extend(Effect.Transform.prototype, {
1004
+ Effect.Transform = Class.create({
1019
1005
  initialize: function(tracks){
1020
1006
  this.tracks = [];
1021
- this.options = arguments[1] || {};
1007
+ this.options = arguments[1] || { };
1022
1008
  this.addTracks(tracks);
1023
1009
  },
1024
1010
  addTracks: function(tracks){
1025
1011
  tracks.each(function(track){
1026
- var data = $H(track).values().first();
1012
+ track = $H(track);
1013
+ var data = track.values().first();
1027
1014
  this.tracks.push($H({
1028
- ids: $H(track).keys().first(),
1015
+ ids: track.keys().first(),
1029
1016
  effect: Effect.Morph,
1030
1017
  options: { style: data }
1031
1018
  }));
@@ -1035,8 +1022,9 @@ Object.extend(Effect.Transform.prototype, {
1035
1022
  play: function(){
1036
1023
  return new Effect.Parallel(
1037
1024
  this.tracks.map(function(track){
1038
- var elements = [$(track.ids) || $$(track.ids)].flatten();
1039
- return elements.map(function(e){ return new track.effect(e, Object.extend({ sync:true }, track.options)) });
1025
+ var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options');
1026
+ var elements = [$(ids) || $$(ids)].flatten();
1027
+ return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) });
1040
1028
  }).flatten(),
1041
1029
  this.options
1042
1030
  );
@@ -1056,35 +1044,79 @@ Element.CSS_PROPERTIES = $w(
1056
1044
 
1057
1045
  Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
1058
1046
 
1047
+ String.__parseStyleElement = document.createElement('div');
1059
1048
  String.prototype.parseStyle = function(){
1060
- var element = Element.extend(document.createElement('div'));
1061
- element.innerHTML = '<div style="' + this + '"></div>';
1062
- var style = element.down().style, styleRules = $H();
1049
+ var style, styleRules = $H();
1050
+ if (Prototype.Browser.WebKit)
1051
+ style = new Element('div',{style:this}).style;
1052
+ else {
1053
+ String.__parseStyleElement.innerHTML = '<div style="' + this + '"></div>';
1054
+ style = String.__parseStyleElement.childNodes[0].style;
1055
+ }
1063
1056
 
1064
1057
  Element.CSS_PROPERTIES.each(function(property){
1065
- if(style[property]) styleRules[property] = style[property];
1058
+ if (style[property]) styleRules.set(property, style[property]);
1066
1059
  });
1067
- if(/MSIE/.test(navigator.userAgent) && !window.opera && this.indexOf('opacity') > -1) {
1068
- styleRules.opacity = this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1];
1069
- }
1060
+
1061
+ if (Prototype.Browser.IE && this.include('opacity'))
1062
+ styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]);
1063
+
1070
1064
  return styleRules;
1071
1065
  };
1072
1066
 
1073
- Element.morph = function(element, style) {
1074
- new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {}));
1075
- return element;
1067
+ if (document.defaultView && document.defaultView.getComputedStyle) {
1068
+ Element.getStyles = function(element) {
1069
+ var css = document.defaultView.getComputedStyle($(element), null);
1070
+ return Element.CSS_PROPERTIES.inject({ }, function(styles, property) {
1071
+ styles[property] = css[property];
1072
+ return styles;
1073
+ });
1074
+ };
1075
+ } else {
1076
+ Element.getStyles = function(element) {
1077
+ element = $(element);
1078
+ var css = element.currentStyle, styles;
1079
+ styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) {
1080
+ results[property] = css[property];
1081
+ return results;
1082
+ });
1083
+ if (!styles.opacity) styles.opacity = element.getOpacity();
1084
+ return styles;
1085
+ };
1086
+ };
1087
+
1088
+ Effect.Methods = {
1089
+ morph: function(element, style) {
1090
+ element = $(element);
1091
+ new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { }));
1092
+ return element;
1093
+ },
1094
+ visualEffect: function(element, effect, options) {
1095
+ element = $(element)
1096
+ var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1);
1097
+ new Effect[klass](element, options);
1098
+ return element;
1099
+ },
1100
+ highlight: function(element, options) {
1101
+ element = $(element);
1102
+ new Effect.Highlight(element, options);
1103
+ return element;
1104
+ }
1076
1105
  };
1077
1106
 
1078
- ['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom',
1079
- 'collectTextNodes','collectTextNodesIgnoreClass','morph'].each(
1080
- function(f) { Element.Methods[f] = Element[f]; }
1107
+ $w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+
1108
+ 'pulsate shake puff squish switchOff dropOut').each(
1109
+ function(effect) {
1110
+ Effect.Methods[effect] = function(element, options){
1111
+ element = $(element);
1112
+ Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options);
1113
+ return element;
1114
+ }
1115
+ }
1081
1116
  );
1082
1117
 
1083
- Element.Methods.visualEffect = function(element, effect, options) {
1084
- s = effect.gsub(/_/, '-').camelize();
1085
- effect_class = s.charAt(0).toUpperCase() + s.substring(1);
1086
- new Effect[effect_class](element, options);
1087
- return $(element);
1088
- };
1118
+ $w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each(
1119
+ function(f) { Effect.Methods[f] = Element[f]; }
1120
+ );
1089
1121
 
1090
- Element.addMethods();
1122
+ Element.addMethods(Effect.Methods);