gluttonberg-core 2.5.7 → 2.5.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. data/app/assets/images/gb_360-button-pause-light.gif +0 -0
  2. data/app/assets/images/gb_360-button-pause-light.png +0 -0
  3. data/app/assets/images/gb_360-button-pause.gif +0 -0
  4. data/app/assets/images/gb_360-button-pause.png +0 -0
  5. data/app/assets/images/gb_360-button-play-light.gif +0 -0
  6. data/app/assets/images/gb_360-button-play-light.png +0 -0
  7. data/app/assets/images/gb_360-button-play.gif +0 -0
  8. data/app/assets/images/gb_360-button-play.png +0 -0
  9. data/app/assets/images/gb_360-button-vis-pause-light.gif +0 -0
  10. data/app/assets/images/gb_360-button-vis-pause-light.png +0 -0
  11. data/app/assets/images/gb_360-button-vis-pause.gif +0 -0
  12. data/app/assets/images/gb_360-button-vis-pause.png +0 -0
  13. data/app/assets/images/gb_360-button-vis-play-light.gif +0 -0
  14. data/app/assets/images/gb_360-button-vis-play-light.png +0 -0
  15. data/app/assets/images/gb_360-button-vis-play.gif +0 -0
  16. data/app/assets/images/gb_360-button-vis-play.png +0 -0
  17. data/app/assets/javascripts/gb_360player.js +1396 -0
  18. data/app/assets/javascripts/gb_application.js +49 -4
  19. data/app/assets/javascripts/gb_berniecode-animator.js +674 -0
  20. data/app/assets/javascripts/gb_soundmanager2-jsmin.js +106 -0
  21. data/app/assets/stylesheets/gb_360player.css +271 -0
  22. data/app/assets/stylesheets/gb_admin-override.sass +6 -0
  23. data/app/helpers/gluttonberg/asset_library.rb +5 -1
  24. data/app/views/gluttonberg/admin/asset_library/assets/show.html.haml +7 -1
  25. data/app/views/gluttonberg/admin/asset_library/shared/_asset_panels.html.haml +9 -3
  26. data/app/views/gluttonberg/admin/shared/_asset_panel.html.haml +12 -6
  27. data/app/views/layouts/gluttonberg.html.haml +4 -1
  28. data/lib/gluttonberg/version.rb +1 -1
  29. metadata +38 -18
@@ -0,0 +1,674 @@
1
+ /** @license
2
+ Animator.js 1.1.9
3
+
4
+ This library is released under the BSD license:
5
+
6
+ Copyright (c) 2006, Bernard Sumption. All rights reserved.
7
+
8
+ Redistribution and use in source and binary forms, with or without
9
+ modification, are permitted provided that the following conditions are met:
10
+
11
+ Redistributions of source code must retain the above copyright notice, this
12
+ list of conditions and the following disclaimer. Redistributions in binary
13
+ form must reproduce the above copyright notice, this list of conditions and
14
+ the following disclaimer in the documentation and/or other materials
15
+ provided with the distribution. Neither the name BernieCode nor
16
+ the names of its contributors may be used to endorse or promote products
17
+ derived from this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
23
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
29
+ DAMAGE.
30
+
31
+ */
32
+
33
+ // http://www.berniecode.com/writing/animator.html
34
+
35
+ // Applies a sequence of numbers between 0 and 1 to a number of subjects
36
+ // construct - see setOptions for parameters
37
+ function Animator(options) {
38
+ this.setOptions(options);
39
+ var _this = this;
40
+ this.timerDelegate = function(){_this.onTimerEvent()};
41
+ this.subjects = [];
42
+ this.subjectScopes = [];
43
+ this.target = 0;
44
+ this.state = 0;
45
+ this.lastTime = null;
46
+ };
47
+ Animator.prototype = {
48
+ // apply defaults
49
+ setOptions: function(options) {
50
+ this.options = Animator.applyDefaults({
51
+ interval: 20, // time between animation frames
52
+ duration: 400, // length of animation
53
+ onComplete: function(){},
54
+ onStep: function(){},
55
+ transition: Animator.tx.easeInOut
56
+ }, options);
57
+ },
58
+ // animate from the current state to provided value
59
+ seekTo: function(to) {
60
+ this.seekFromTo(this.state, to);
61
+ },
62
+ // animate from the current state to provided value
63
+ seekFromTo: function(from, to) {
64
+ this.target = Math.max(0, Math.min(1, to));
65
+ this.state = Math.max(0, Math.min(1, from));
66
+ this.lastTime = new Date().getTime();
67
+ if (!this.intervalId) {
68
+ this.intervalId = window.setInterval(this.timerDelegate, this.options.interval);
69
+ }
70
+ },
71
+ // animate from the current state to provided value
72
+ jumpTo: function(to) {
73
+ this.target = this.state = Math.max(0, Math.min(1, to));
74
+ this.propagate();
75
+ },
76
+ // seek to the opposite of the current target
77
+ toggle: function() {
78
+ this.seekTo(1 - this.target);
79
+ },
80
+ // add a function or an object with a method setState(state) that will be called with a number
81
+ // between 0 and 1 on each frame of the animation
82
+ addSubject: function(subject,scope) {
83
+ this.subjects[this.subjects.length] = subject;
84
+ this.subjectScopes[this.subjectScopes.length] = scope;
85
+ return this;
86
+ },
87
+ // remove all subjects
88
+ clearSubjects: function() {
89
+ this.subjects = [];
90
+ this.subjectScopes = [];
91
+ },
92
+ // forward the current state to the animation subjects
93
+ propagate: function() {
94
+ var value = this.options.transition(this.state);
95
+ for (var i=0; i<this.subjects.length; i++) {
96
+ if (this.subjects[i].setState) {
97
+ this.subjects[i].setState(value);
98
+ } else {
99
+ this.subjects[i].apply(this.subjectScopes[i],[value]);
100
+ }
101
+ }
102
+ },
103
+ // called once per frame to update the current state
104
+ onTimerEvent: function() {
105
+ var now = new Date().getTime();
106
+ var timePassed = now - this.lastTime;
107
+ this.lastTime = now;
108
+ var movement = (timePassed / this.options.duration) * (this.state < this.target ? 1 : -1);
109
+ if (Math.abs(movement) >= Math.abs(this.state - this.target)) {
110
+ this.state = this.target;
111
+ } else {
112
+ this.state += movement;
113
+ }
114
+
115
+ try {
116
+ this.propagate();
117
+ } finally {
118
+ this.options.onStep.call(this);
119
+ if (this.target == this.state) {
120
+ window.clearInterval(this.intervalId);
121
+ this.intervalId = null;
122
+ this.options.onComplete.call(this);
123
+ }
124
+ }
125
+ },
126
+ // shortcuts
127
+ play: function() {this.seekFromTo(0, 1)},
128
+ reverse: function() {this.seekFromTo(1, 0)},
129
+ // return a string describing this Animator, for debugging
130
+ inspect: function() {
131
+ var str = "#<Animator:\n";
132
+ for (var i=0; i<this.subjects.length; i++) {
133
+ str += this.subjects[i].inspect();
134
+ }
135
+ str += ">";
136
+ return str;
137
+ }
138
+ }
139
+ // merge the properties of two objects
140
+ Animator.applyDefaults = function(defaults, prefs) {
141
+ prefs = prefs || {};
142
+ var prop, result = {};
143
+ for (prop in defaults) result[prop] = prefs[prop] !== undefined ? prefs[prop] : defaults[prop];
144
+ return result;
145
+ }
146
+ // make an array from any object
147
+ Animator.makeArray = function(o) {
148
+ if (o == null) return [];
149
+ if (!o.length) return [o];
150
+ var result = [];
151
+ for (var i=0; i<o.length; i++) result[i] = o[i];
152
+ return result;
153
+ }
154
+ // convert a dash-delimited-property to a camelCaseProperty (c/o Prototype, thanks Sam!)
155
+ Animator.camelize = function(string) {
156
+ var oStringList = string.split('-');
157
+ if (oStringList.length == 1) return oStringList[0];
158
+
159
+ var camelizedString = string.indexOf('-') == 0
160
+ ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
161
+ : oStringList[0];
162
+
163
+ for (var i = 1, len = oStringList.length; i < len; i++) {
164
+ var s = oStringList[i];
165
+ camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
166
+ }
167
+ return camelizedString;
168
+ }
169
+ // syntactic sugar for creating CSSStyleSubjects
170
+ Animator.apply = function(el, style, options) {
171
+ if (style instanceof Array) {
172
+ return new Animator(options).addSubject(new CSSStyleSubject(el, style[0], style[1]));
173
+ }
174
+ return new Animator(options).addSubject(new CSSStyleSubject(el, style));
175
+ }
176
+ // make a transition function that gradually accelerates. pass a=1 for smooth
177
+ // gravitational acceleration, higher values for an exaggerated effect
178
+ Animator.makeEaseIn = function(a) {
179
+ return function(state) {
180
+ return Math.pow(state, a*2);
181
+ }
182
+ }
183
+ // as makeEaseIn but for deceleration
184
+ Animator.makeEaseOut = function(a) {
185
+ return function(state) {
186
+ return 1 - Math.pow(1 - state, a*2);
187
+ }
188
+ }
189
+ // make a transition function that, like an object with momentum being attracted to a point,
190
+ // goes past the target then returns
191
+ Animator.makeElastic = function(bounces) {
192
+ return function(state) {
193
+ state = Animator.tx.easeInOut(state);
194
+ return ((1-Math.cos(state * Math.PI * bounces)) * (1 - state)) + state;
195
+ }
196
+ }
197
+ // make an Attack Decay Sustain Release envelope that starts and finishes on the same level
198
+ //
199
+ Animator.makeADSR = function(attackEnd, decayEnd, sustainEnd, sustainLevel) {
200
+ if (sustainLevel == null) sustainLevel = 0.5;
201
+ return function(state) {
202
+ if (state < attackEnd) {
203
+ return state / attackEnd;
204
+ }
205
+ if (state < decayEnd) {
206
+ return 1 - ((state - attackEnd) / (decayEnd - attackEnd) * (1 - sustainLevel));
207
+ }
208
+ if (state < sustainEnd) {
209
+ return sustainLevel;
210
+ }
211
+ return sustainLevel * (1 - ((state - sustainEnd) / (1 - sustainEnd)));
212
+ }
213
+ }
214
+ // make a transition function that, like a ball falling to floor, reaches the target and/
215
+ // bounces back again
216
+ Animator.makeBounce = function(bounces) {
217
+ var fn = Animator.makeElastic(bounces);
218
+ return function(state) {
219
+ state = fn(state);
220
+ return state <= 1 ? state : 2-state;
221
+ }
222
+ }
223
+
224
+ // pre-made transition functions to use with the 'transition' option
225
+ Animator.tx = {
226
+ easeInOut: function(pos){
227
+ return ((-Math.cos(pos*Math.PI)/2) + 0.5);
228
+ },
229
+ linear: function(x) {
230
+ return x;
231
+ },
232
+ easeIn: Animator.makeEaseIn(1.5),
233
+ easeOut: Animator.makeEaseOut(1.5),
234
+ strongEaseIn: Animator.makeEaseIn(2.5),
235
+ strongEaseOut: Animator.makeEaseOut(2.5),
236
+ elastic: Animator.makeElastic(1),
237
+ veryElastic: Animator.makeElastic(3),
238
+ bouncy: Animator.makeBounce(1),
239
+ veryBouncy: Animator.makeBounce(3)
240
+ }
241
+
242
+ // animates a pixel-based style property between two integer values
243
+ function NumericalStyleSubject(els, property, from, to, units) {
244
+ this.els = Animator.makeArray(els);
245
+ if (property == 'opacity' && window.ActiveXObject) {
246
+ this.property = 'filter';
247
+ } else {
248
+ this.property = Animator.camelize(property);
249
+ }
250
+ this.from = parseFloat(from);
251
+ this.to = parseFloat(to);
252
+ this.units = units != null ? units : 'px';
253
+ }
254
+ NumericalStyleSubject.prototype = {
255
+ setState: function(state) {
256
+ var style = this.getStyle(state);
257
+ var visibility = (this.property == 'opacity' && state == 0) ? 'hidden' : '';
258
+ var j=0;
259
+ for (var i=0; i<this.els.length; i++) {
260
+ try {
261
+ this.els[i].style[this.property] = style;
262
+ } catch (e) {
263
+ // ignore fontWeight - intermediate numerical values cause exeptions in firefox
264
+ if (this.property != 'fontWeight') throw e;
265
+ }
266
+ if (j++ > 20) return;
267
+ }
268
+ },
269
+ getStyle: function(state) {
270
+ state = this.from + ((this.to - this.from) * state);
271
+ if (this.property == 'filter') return "alpha(opacity=" + Math.round(state*100) + ")";
272
+ if (this.property == 'opacity') return state;
273
+ return Math.round(state) + this.units;
274
+ },
275
+ inspect: function() {
276
+ return "\t" + this.property + "(" + this.from + this.units + " to " + this.to + this.units + ")\n";
277
+ }
278
+ }
279
+
280
+ // animates a colour based style property between two hex values
281
+ function ColorStyleSubject(els, property, from, to) {
282
+ this.els = Animator.makeArray(els);
283
+ this.property = Animator.camelize(property);
284
+ this.to = this.expandColor(to);
285
+ this.from = this.expandColor(from);
286
+ this.origFrom = from;
287
+ this.origTo = to;
288
+ }
289
+
290
+ ColorStyleSubject.prototype = {
291
+ // parse "#FFFF00" to [256, 256, 0]
292
+ expandColor: function(color) {
293
+ var hexColor, red, green, blue;
294
+ hexColor = ColorStyleSubject.parseColor(color);
295
+ if (hexColor) {
296
+ red = parseInt(hexColor.slice(1, 3), 16);
297
+ green = parseInt(hexColor.slice(3, 5), 16);
298
+ blue = parseInt(hexColor.slice(5, 7), 16);
299
+ return [red,green,blue]
300
+ }
301
+ if (window.DEBUG) {
302
+ alert("Invalid colour: '" + color + "'");
303
+ }
304
+ },
305
+ getValueForState: function(color, state) {
306
+ return Math.round(this.from[color] + ((this.to[color] - this.from[color]) * state));
307
+ },
308
+ setState: function(state) {
309
+ var color = '#'
310
+ + ColorStyleSubject.toColorPart(this.getValueForState(0, state))
311
+ + ColorStyleSubject.toColorPart(this.getValueForState(1, state))
312
+ + ColorStyleSubject.toColorPart(this.getValueForState(2, state));
313
+ for (var i=0; i<this.els.length; i++) {
314
+ this.els[i].style[this.property] = color;
315
+ }
316
+ },
317
+ inspect: function() {
318
+ return "\t" + this.property + "(" + this.origFrom + " to " + this.origTo + ")\n";
319
+ }
320
+ }
321
+
322
+ // return a properly formatted 6-digit hex colour spec, or false
323
+ ColorStyleSubject.parseColor = function(string) {
324
+ var color = '#', match;
325
+ if(match = ColorStyleSubject.parseColor.rgbRe.exec(string)) {
326
+ var part;
327
+ for (var i=1; i<=3; i++) {
328
+ part = Math.max(0, Math.min(255, parseInt(match[i])));
329
+ color += ColorStyleSubject.toColorPart(part);
330
+ }
331
+ return color;
332
+ }
333
+ if (match = ColorStyleSubject.parseColor.hexRe.exec(string)) {
334
+ if(match[1].length == 3) {
335
+ for (var i=0; i<3; i++) {
336
+ color += match[1].charAt(i) + match[1].charAt(i);
337
+ }
338
+ return color;
339
+ }
340
+ return '#' + match[1];
341
+ }
342
+ return false;
343
+ }
344
+ // convert a number to a 2 digit hex string
345
+ ColorStyleSubject.toColorPart = function(number) {
346
+ if (number > 255) number = 255;
347
+ var digits = number.toString(16);
348
+ if (number < 16) return '0' + digits;
349
+ return digits;
350
+ }
351
+ ColorStyleSubject.parseColor.rgbRe = /^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i;
352
+ ColorStyleSubject.parseColor.hexRe = /^\#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
353
+
354
+ // Animates discrete styles, i.e. ones that do not scale but have discrete values
355
+ // that can't be interpolated
356
+ function DiscreteStyleSubject(els, property, from, to, threshold) {
357
+ this.els = Animator.makeArray(els);
358
+ this.property = Animator.camelize(property);
359
+ this.from = from;
360
+ this.to = to;
361
+ this.threshold = threshold || 0.5;
362
+ }
363
+
364
+ DiscreteStyleSubject.prototype = {
365
+ setState: function(state) {
366
+ var j=0;
367
+ for (var i=0; i<this.els.length; i++) {
368
+ this.els[i].style[this.property] = state <= this.threshold ? this.from : this.to;
369
+ }
370
+ },
371
+ inspect: function() {
372
+ return "\t" + this.property + "(" + this.from + " to " + this.to + " @ " + this.threshold + ")\n";
373
+ }
374
+ }
375
+
376
+ // animates between two styles defined using CSS.
377
+ // if style1 and style2 are present, animate between them, if only style1
378
+ // is present, animate between the element's current style and style1
379
+ function CSSStyleSubject(els, style1, style2) {
380
+ els = Animator.makeArray(els);
381
+ this.subjects = [];
382
+ if (els.length == 0) return;
383
+ var prop, toStyle, fromStyle;
384
+ if (style2) {
385
+ fromStyle = this.parseStyle(style1, els[0]);
386
+ toStyle = this.parseStyle(style2, els[0]);
387
+ } else {
388
+ toStyle = this.parseStyle(style1, els[0]);
389
+ fromStyle = {};
390
+ for (prop in toStyle) {
391
+ fromStyle[prop] = CSSStyleSubject.getStyle(els[0], prop);
392
+ }
393
+ }
394
+ // remove unchanging properties
395
+ var prop;
396
+ for (prop in fromStyle) {
397
+ if (fromStyle[prop] == toStyle[prop]) {
398
+ delete fromStyle[prop];
399
+ delete toStyle[prop];
400
+ }
401
+ }
402
+ // discover the type (numerical or colour) of each style
403
+ var prop, units, match, type, from, to;
404
+ for (prop in fromStyle) {
405
+ var fromProp = String(fromStyle[prop]);
406
+ var toProp = String(toStyle[prop]);
407
+ if (toStyle[prop] == null) {
408
+ if (window.DEBUG) alert("No to style provided for '" + prop + '"');
409
+ continue;
410
+ }
411
+
412
+ if (from = ColorStyleSubject.parseColor(fromProp)) {
413
+ to = ColorStyleSubject.parseColor(toProp);
414
+ type = ColorStyleSubject;
415
+ } else if (fromProp.match(CSSStyleSubject.numericalRe)
416
+ && toProp.match(CSSStyleSubject.numericalRe)) {
417
+ from = parseFloat(fromProp);
418
+ to = parseFloat(toProp);
419
+ type = NumericalStyleSubject;
420
+ match = CSSStyleSubject.numericalRe.exec(fromProp);
421
+ var reResult = CSSStyleSubject.numericalRe.exec(toProp);
422
+ if (match[1] != null) {
423
+ units = match[1];
424
+ } else if (reResult[1] != null) {
425
+ units = reResult[1];
426
+ } else {
427
+ units = reResult;
428
+ }
429
+ } else if (fromProp.match(CSSStyleSubject.discreteRe)
430
+ && toProp.match(CSSStyleSubject.discreteRe)) {
431
+ from = fromProp;
432
+ to = toProp;
433
+ type = DiscreteStyleSubject;
434
+ units = 0; // hack - how to get an animator option down to here
435
+ } else {
436
+ if (window.DEBUG) {
437
+ alert("Unrecognised format for value of "
438
+ + prop + ": '" + fromStyle[prop] + "'");
439
+ }
440
+ continue;
441
+ }
442
+ this.subjects[this.subjects.length] = new type(els, prop, from, to, units);
443
+ }
444
+ }
445
+
446
+ CSSStyleSubject.prototype = {
447
+ // parses "width: 400px; color: #FFBB2E" to {width: "400px", color: "#FFBB2E"}
448
+ parseStyle: function(style, el) {
449
+ var rtn = {};
450
+ // if style is a rule set
451
+ if (style.indexOf(":") != -1) {
452
+ var styles = style.split(";");
453
+ for (var i=0; i<styles.length; i++) {
454
+ var parts = CSSStyleSubject.ruleRe.exec(styles[i]);
455
+ if (parts) {
456
+ rtn[parts[1]] = parts[2];
457
+ }
458
+ }
459
+ }
460
+ // else assume style is a class name
461
+ else {
462
+ var prop, value, oldClass;
463
+ oldClass = el.className;
464
+ el.className = style;
465
+ for (var i=0; i<CSSStyleSubject.cssProperties.length; i++) {
466
+ prop = CSSStyleSubject.cssProperties[i];
467
+ value = CSSStyleSubject.getStyle(el, prop);
468
+ if (value != null) {
469
+ rtn[prop] = value;
470
+ }
471
+ }
472
+ el.className = oldClass;
473
+ }
474
+ return rtn;
475
+
476
+ },
477
+ setState: function(state) {
478
+ for (var i=0; i<this.subjects.length; i++) {
479
+ this.subjects[i].setState(state);
480
+ }
481
+ },
482
+ inspect: function() {
483
+ var str = "";
484
+ for (var i=0; i<this.subjects.length; i++) {
485
+ str += this.subjects[i].inspect();
486
+ }
487
+ return str;
488
+ }
489
+ }
490
+ // get the current value of a css property,
491
+ CSSStyleSubject.getStyle = function(el, property){
492
+ var style;
493
+ if(document.defaultView && document.defaultView.getComputedStyle){
494
+ style = document.defaultView.getComputedStyle(el, "").getPropertyValue(property);
495
+ if (style) {
496
+ return style;
497
+ }
498
+ }
499
+ property = Animator.camelize(property);
500
+ if(el.currentStyle){
501
+ style = el.currentStyle[property];
502
+ }
503
+ return style || el.style[property]
504
+ }
505
+
506
+
507
+ CSSStyleSubject.ruleRe = /^\s*([a-zA-Z\-]+)\s*:\s*(\S(.+\S)?)\s*$/;
508
+ CSSStyleSubject.numericalRe = /^-?\d+(?:\.\d+)?(%|[a-zA-Z]{2})?$/;
509
+ CSSStyleSubject.discreteRe = /^\w+$/;
510
+
511
+ // required because the style object of elements isn't enumerable in Safari
512
+ /*
513
+ CSSStyleSubject.cssProperties = ['background-color','border','border-color','border-spacing',
514
+ 'border-style','border-top','border-right','border-bottom','border-left','border-top-color',
515
+ 'border-right-color','border-bottom-color','border-left-color','border-top-width','border-right-width',
516
+ 'border-bottom-width','border-left-width','border-width','bottom','color','font-size','font-size-adjust',
517
+ 'font-stretch','font-style','height','left','letter-spacing','line-height','margin','margin-top',
518
+ 'margin-right','margin-bottom','margin-left','marker-offset','max-height','max-width','min-height',
519
+ 'min-width','orphans','outline','outline-color','outline-style','outline-width','overflow','padding',
520
+ 'padding-top','padding-right','padding-bottom','padding-left','quotes','right','size','text-indent',
521
+ 'top','width','word-spacing','z-index','opacity','outline-offset'];*/
522
+
523
+
524
+ CSSStyleSubject.cssProperties = ['azimuth','background','background-attachment','background-color','background-image','background-position','background-repeat','border-collapse','border-color','border-spacing','border-style','border-top','border-top-color','border-right-color','border-bottom-color','border-left-color','border-top-style','border-right-style','border-bottom-style','border-left-style','border-top-width','border-right-width','border-bottom-width','border-left-width','border-width','bottom','clear','clip','color','content','cursor','direction','display','elevation','empty-cells','css-float','font','font-family','font-size','font-size-adjust','font-stretch','font-style','font-variant','font-weight','height','left','letter-spacing','line-height','list-style','list-style-image','list-style-position','list-style-type','margin','margin-top','margin-right','margin-bottom','margin-left','max-height','max-width','min-height','min-width','orphans','outline','outline-color','outline-style','outline-width','overflow','padding','padding-top','padding-right','padding-bottom','padding-left','pause','position','right','size','table-layout','text-align','text-decoration','text-indent','text-shadow','text-transform','top','vertical-align','visibility','white-space','width','word-spacing','z-index','opacity','outline-offset','overflow-x','overflow-y'];
525
+
526
+
527
+ // chains several Animator objects together
528
+ function AnimatorChain(animators, options) {
529
+ this.animators = animators;
530
+ this.setOptions(options);
531
+ for (var i=0; i<this.animators.length; i++) {
532
+ this.listenTo(this.animators[i]);
533
+ }
534
+ this.forwards = false;
535
+ this.current = 0;
536
+ }
537
+
538
+ AnimatorChain.prototype = {
539
+ // apply defaults
540
+ setOptions: function(options) {
541
+ this.options = Animator.applyDefaults({
542
+ // by default, each call to AnimatorChain.play() calls jumpTo(0) of each animator
543
+ // before playing, which can cause flickering if you have multiple animators all
544
+ // targeting the same element. Set this to false to avoid this.
545
+ resetOnPlay: true
546
+ }, options);
547
+ },
548
+ // play each animator in turn
549
+ play: function() {
550
+ this.forwards = true;
551
+ this.current = -1;
552
+ if (this.options.resetOnPlay) {
553
+ for (var i=0; i<this.animators.length; i++) {
554
+ this.animators[i].jumpTo(0);
555
+ }
556
+ }
557
+ this.advance();
558
+ },
559
+ // play all animators backwards
560
+ reverse: function() {
561
+ this.forwards = false;
562
+ this.current = this.animators.length;
563
+ if (this.options.resetOnPlay) {
564
+ for (var i=0; i<this.animators.length; i++) {
565
+ this.animators[i].jumpTo(1);
566
+ }
567
+ }
568
+ this.advance();
569
+ },
570
+ // if we have just play()'d, then call reverse(), and vice versa
571
+ toggle: function() {
572
+ if (this.forwards) {
573
+ this.seekTo(0);
574
+ } else {
575
+ this.seekTo(1);
576
+ }
577
+ },
578
+ // internal: install an event listener on an animator's onComplete option
579
+ // to trigger the next animator
580
+ listenTo: function(animator) {
581
+ var oldOnComplete = animator.options.onComplete;
582
+ var _this = this;
583
+ animator.options.onComplete = function() {
584
+ if (oldOnComplete) oldOnComplete.call(animator);
585
+ _this.advance();
586
+ }
587
+ },
588
+ // play the next animator
589
+ advance: function() {
590
+ if (this.forwards) {
591
+ if (this.animators[this.current + 1] == null) return;
592
+ this.current++;
593
+ this.animators[this.current].play();
594
+ } else {
595
+ if (this.animators[this.current - 1] == null) return;
596
+ this.current--;
597
+ this.animators[this.current].reverse();
598
+ }
599
+ },
600
+ // this function is provided for drop-in compatibility with Animator objects,
601
+ // but only accepts 0 and 1 as target values
602
+ seekTo: function(target) {
603
+ if (target <= 0) {
604
+ this.forwards = false;
605
+ this.animators[this.current].seekTo(0);
606
+ } else {
607
+ this.forwards = true;
608
+ this.animators[this.current].seekTo(1);
609
+ }
610
+ }
611
+ }
612
+
613
+ // an Accordion is a class that creates and controls a number of Animators. An array of elements is passed in,
614
+ // and for each element an Animator and a activator button is created. When an Animator's activator button is
615
+ // clicked, the Animator and all before it seek to 0, and all Animators after it seek to 1. This can be used to
616
+ // create the classic Accordion effect, hence the name.
617
+ // see setOptions for arguments
618
+ function Accordion(options) {
619
+ this.setOptions(options);
620
+ var selected = this.options.initialSection, current;
621
+ if (this.options.rememberance) {
622
+ current = document.location.hash.substring(1);
623
+ }
624
+ this.rememberanceTexts = [];
625
+ this.ans = [];
626
+ var _this = this;
627
+ for (var i=0; i<this.options.sections.length; i++) {
628
+ var el = this.options.sections[i];
629
+ var an = new Animator(this.options.animatorOptions);
630
+ var from = this.options.from + (this.options.shift * i);
631
+ var to = this.options.to + (this.options.shift * i);
632
+ an.addSubject(new NumericalStyleSubject(el, this.options.property, from, to, this.options.units));
633
+ an.jumpTo(0);
634
+ var activator = this.options.getActivator(el);
635
+ activator.index = i;
636
+ activator.onclick = function(){_this.show(this.index)};
637
+ this.ans[this.ans.length] = an;
638
+ this.rememberanceTexts[i] = activator.innerHTML.replace(/\s/g, "");
639
+ if (this.rememberanceTexts[i] === current) {
640
+ selected = i;
641
+ }
642
+ }
643
+ this.show(selected);
644
+ }
645
+
646
+ Accordion.prototype = {
647
+ // apply defaults
648
+ setOptions: function(options) {
649
+ this.options = Object.extend({
650
+ // REQUIRED: an array of elements to use as the accordion sections
651
+ sections: null,
652
+ // a function that locates an activator button element given a section element.
653
+ // by default it takes a button id from the section's "activator" attibute
654
+ getActivator: function(el) {return document.getElementById(el.getAttribute("activator"))},
655
+ // shifts each animator's range, for example with options {from:0,to:100,shift:20}
656
+ // the animators' ranges will be 0-100, 20-120, 40-140 etc.
657
+ shift: 0,
658
+ // the first page to show
659
+ initialSection: 0,
660
+ // if set to true, document.location.hash will be used to preserve the open section across page reloads
661
+ rememberance: true,
662
+ // constructor arguments to the Animator objects
663
+ animatorOptions: {}
664
+ }, options || {});
665
+ },
666
+ show: function(section) {
667
+ for (var i=0; i<this.ans.length; i++) {
668
+ this.ans[i].seekTo(i > section ? 1 : 0);
669
+ }
670
+ if (this.options.rememberance) {
671
+ document.location.hash = this.rememberanceTexts[section];
672
+ }
673
+ }
674
+ }