adhearsion 0.7.6 → 0.7.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/.version +1 -1
  2. data/CHANGELOG +43 -25
  3. data/Rakefile +0 -5
  4. data/TODO +51 -2
  5. data/ahn +2 -1
  6. data/apps/default/Rakefile +16 -7
  7. data/apps/default/config/adhearsion.yml +22 -1
  8. data/apps/default/config/helpers/manager_proxy.yml +1 -0
  9. data/apps/default/config/helpers/micromenus/images/arrow-off.gif +0 -0
  10. data/apps/default/config/helpers/micromenus/images/arrow-on.gif +0 -0
  11. data/apps/default/config/helpers/micromenus/images/error.gif +0 -0
  12. data/apps/default/config/helpers/micromenus/images/folder-off.gif +0 -0
  13. data/apps/default/config/helpers/micromenus/images/folder-on.gif +0 -0
  14. data/apps/default/config/helpers/micromenus/images/folder.png +0 -0
  15. data/apps/default/config/helpers/micromenus/images/ggbridge.jpg +0 -0
  16. data/apps/default/config/helpers/micromenus/images/green.png +0 -0
  17. data/apps/default/config/helpers/micromenus/images/microbrowser.bg.gif +0 -0
  18. data/apps/default/config/helpers/micromenus/images/red.png +0 -0
  19. data/apps/default/config/helpers/micromenus/images/url-off.gif +0 -0
  20. data/apps/default/config/helpers/micromenus/images/url-on.gif +0 -0
  21. data/apps/default/config/helpers/micromenus/images/yellow.png +0 -0
  22. data/apps/default/config/helpers/micromenus/javascripts/animation.js +1341 -0
  23. data/apps/default/config/helpers/micromenus/javascripts/carousel.js +1238 -0
  24. data/apps/default/config/helpers/micromenus/javascripts/columnav.js +306 -0
  25. data/apps/default/config/helpers/micromenus/javascripts/connection.js +965 -0
  26. data/apps/default/config/helpers/micromenus/javascripts/container.js +4727 -0
  27. data/apps/default/config/helpers/micromenus/javascripts/container_core.js +2915 -0
  28. data/apps/default/config/helpers/micromenus/javascripts/dom.js +892 -0
  29. data/apps/default/config/helpers/micromenus/javascripts/dragdrop.js +2921 -907
  30. data/apps/default/config/helpers/micromenus/javascripts/event.js +1771 -0
  31. data/apps/default/config/helpers/micromenus/javascripts/yahoo.js +433 -0
  32. data/apps/default/config/helpers/micromenus/stylesheets/carousel.css +78 -0
  33. data/apps/default/config/helpers/micromenus/stylesheets/columnav.css +135 -0
  34. data/apps/default/config/helpers/micromenus/stylesheets/microbrowsers.css +42 -0
  35. data/apps/default/config/helpers/multi_messenger.yml +5 -1
  36. data/apps/default/config/migration.rb +10 -0
  37. data/apps/default/extensions.rb +1 -1
  38. data/apps/default/helpers/factorial.alien.c +3 -3
  39. data/apps/default/helpers/lookup.rb +2 -1
  40. data/apps/default/helpers/manager_proxy.rb +67 -15
  41. data/apps/default/helpers/micromenus.rb +173 -31
  42. data/apps/default/helpers/multi_messenger.rb +20 -3
  43. data/lib/adhearsion.rb +218 -88
  44. data/lib/constants.rb +1 -0
  45. data/lib/core_extensions.rb +15 -9
  46. data/lib/phone_number.rb +85 -0
  47. data/lib/rami.rb +3 -2
  48. data/lib/servlet_container.rb +47 -24
  49. data/lib/sexy_migrations.rb +70 -0
  50. data/test/asterisk_module_test.rb +9 -9
  51. data/test/specs/numerical_string_spec.rb +53 -0
  52. metadata +31 -11
  53. data/apps/default/config/helpers/micromenus/javascripts/builder.js +0 -131
  54. data/apps/default/config/helpers/micromenus/javascripts/controls.js +0 -834
  55. data/apps/default/config/helpers/micromenus/javascripts/effects.js +0 -956
  56. data/apps/default/config/helpers/micromenus/javascripts/prototype.js +0 -2319
  57. data/apps/default/config/helpers/micromenus/javascripts/scriptaculous.js +0 -51
  58. data/apps/default/config/helpers/micromenus/javascripts/slider.js +0 -278
  59. data/apps/default/config/helpers/micromenus/javascripts/unittest.js +0 -557
  60. data/apps/default/config/helpers/micromenus/stylesheets/firefox.css +0 -10
  61. data/apps/default/config/helpers/micromenus/stylesheets/firefox.xul.css +0 -44
data/.version CHANGED
@@ -1 +1 @@
1
- 0.7.6
1
+ 0.7.7
data/CHANGELOG CHANGED
@@ -1,25 +1,43 @@
1
- Adhearsion should now run fine in later versions of Ruby (1.8.5 and 1.8.6).
2
-
3
- Changed Adhearsion's license to LGPL from GPL.
4
-
5
- Dial plan caching! Awesome performance improvement!
6
-
7
- Adhearsion now daemonizes properly! Use "ahn start daemon /path/to/app"
8
-
9
- The input() method now returns the "*" key properly.
10
-
11
- Can now read any leading zeros in "extension" by using "str_extension" instead. This is a temporary patch until the replacement solution is complete.
12
-
13
- Big improvements to the record() method.
14
-
15
- AMI originations are a little cleaner now.
16
-
17
- Improved error reporting.
18
-
19
- Fixed bug in Micromenus that prevented the requester's IP address from being parsed properly.
20
-
21
- Fixed bug in the overloading of the IAX, IAX2, Zap and ZAP constants' division operator.
22
-
23
- TODO lists now exist in the trunk.
24
-
25
- Many other miscellaneous improvements.
1
+ --- ADDED ---
2
+ The "extension" dialplan variable is now handled with a special PhoneNumber class that resolves issues with extensions beginning with a zero.
3
+ Added PBX.introduce which much more conveniently connects two endpoints.
4
+ Can now use Asterisk dialplan methods like _('2XZNX32Z')
5
+ Merged in the improved Micromenu GUI branch for modern browsers.
6
+ Can now play() currency values. e.g.: play "$12.50"
7
+ Did some preliminary work on Snom/Cisco support in Micromenus with a Snom employee at AstriDevCon.
8
+ Broke up PhoneNumber into PhoneNumber and NumericalString. Wrote an RSpec for their functionality.
9
+ Added the PBX.call_and_exec() method. Preliminary work on PBX.overhear()
10
+ Implemented the redirection (~) unary operation to dialplan contexts. For example +just_dial in a dialplan executes the "just_dial" context and continues in the originating context. Doing ~just_dial executes "just_dial" and does not return to the originating context. What's more, the originating context is removed from the eval() context stack which could lead to some heavy memory use when used intensely.
11
+ Added a super-simple dialplan method segment() which wraps code in a block so redo keywords can work for targeted dialplan segment.
12
+ Added a patch by Bruce Williams of Five Runs who contributed some great code for generating Asterisk dialplan technology classes (i.e. IAX2/123 or SCCP/123123)
13
+ The lookup() helper now also makes available a :name property
14
+ Added default value of hangup_after_error to the config file.
15
+ Adding file for making Adhearsion migrations much nicer
16
+ Minor changes to speak()
17
+ Minor improvement to the default migration to help people get up and running (and create new content at the end of a migration)
18
+ Minor enhancement which makes dial() a little more intuitive when setting the :callerid hash key argument
19
+ Other numerical variables received from Asterisk over AGI now use NumericalString instead of blowing up their thread.
20
+ Added a SIP_URI constant regexp
21
+ Can now give a Time object to play()
22
+ Jabber events can now be handled much easier in the multi_messenger.rb helper
23
+ Can now call detach!() in a dialplan to let Asterisk's extensions.conf continue executing.
24
+ Can now call size() and length() on a Fixnum. Works just like num.to_s.size. Useful when working with numerical extensions.
25
+ Can now give a Symbol to play(). Example -- play:beep
26
+ Can now specify whether events should be captured by Adhearsion's AMI client.
27
+ Can now specify whether incoming subscription requests should be automatically accepted
28
+ Can now specify whether the Adhearsion AMI client should receive events or not by putting events: true or events:false in adhearsion.yml
29
+ Added several new technology classes (SCCP, Local)
30
+ Can now use sugary syntaxes like IAX/:foo/12
31
+
32
+ --- FIXED ---
33
+ Fixed wait_for_digit timeout
34
+ Fixed the speak() method. Now works with Festival (which comes by default with AsteriskNOW)
35
+ Fixed a variable name that blew up the interpreter
36
+ Fixed a comment suggestion
37
+ Fixed a small syntactical error that prevented a helper from running.
38
+ Fixed syntactical issues in the test file
39
+ The factorial method had a mathematical error in it.
40
+ Asterisk-played error messages are more verbose
41
+ Fixed the wait_for_digit bug reported by ernieboy
42
+ Fixed method_missing notifier method in PBX
43
+ I no longer live in Dallas so I'm changing the startup message. :)
data/Rakefile CHANGED
@@ -93,11 +93,6 @@ end
93
93
  desc "Simply prints the Adhearsion version."
94
94
  task :version do puts ADHEARSION_VERSION end
95
95
 
96
- desc 'Generate sample databases'
97
- task :migrate do
98
- # Coming soon
99
- end
100
-
101
96
  desc 'Reinstall the gem'
102
97
  task :update => [:repackage] do
103
98
  if `whoami`.chomp != 'root'
data/TODO CHANGED
@@ -1,22 +1,71 @@
1
1
  Port Jason's T2S work into trunk when stable. Jason?
2
2
 
3
+ Allow setting of CallerID names in dial(). This is seemingly Asterisk version dependent. :(
4
+
3
5
  Port in new Micromenus browser GUI
4
6
 
5
7
  Support ITAD routing using ENUM lookups.
8
+
6
9
  Major file structure refactoring!
7
10
 
8
11
  Port in RAI's AMI work.
9
12
 
13
+ Support a way of playing digits
14
+
15
+ Implement the notifications DSL using OpenWFEru as a base.
16
+
17
+ Add the ability to auto-require gems when Adhearsion boots by specifying them in adhearsion.yml.
18
+
19
+ Implement PBX[] access to the Asterisk database. In an AGI session this should use DATABASE PUT/GET while elsewhere it should use AMI if a connection exists. Here are some examples:
20
+ - PBX['SIP']['Registry'].each { |user| p user }
21
+ - PBX['foo'] = Time.now # => Should use Marshal.dump
22
+ - PBX['foo'].delete!
23
+
24
+ Implement an AMI client in Erlang that Ruby can talk to and dispatch/queue events.
25
+
26
+ Allow setting autohangups after a certain duration (SET AUTOHANGUP seconds)
27
+
28
+ Create more framework hooks! Need some especially for after_helpers_load()
29
+
30
+ Support logging to the Asterisk console with the use of the VERBOSE AGI command.
31
+
32
+ Support calling normal Asterisk AGI scripts from Adhearsion.
33
+
34
+ Create a CommandFactory module which takes the same arguments as all dialplan methods, but returns the String that should be sent to Asterisk. This would be really helpful for compiling commands for use elsewhere. This would greatly clean up the Asterisk module.
35
+
10
36
  Port in RAI's Rails app initialization and routing integration.
11
37
 
12
38
  Develop a reasonable RSpec testing framework for Adhearsion.
13
39
 
14
- Have AGI server optionally powered by mongrel
40
+ Have AGI server optionally powered by Mongrel's C-based TCP server.
15
41
 
16
42
  Port Micromenus server over to Camping
17
43
 
44
+ Port the Perl Least Cost Routing Engine (Asterisk::LCR) to Adhearsion. http://search.cpan.org/~jhiver/Asterisk-LCR-0.08/lib/Asterisk/LCR.pm
45
+
46
+ Make ActiveRecord::Migration's create_table() syntax sexier by wrapping a method_missing around calls to TableDefinition#column. See http://errtheblog.com/post/2381. Below is an example:
47
+ create table :users do
48
+ foreign_key :group
49
+ string :name
50
+ timestamps!
51
+ end
52
+
53
+ Support storing call caches with memcached if available.
54
+
55
+ Have Adhearsion's migrations use a version system. Instead of having just one migration.rb file, migrations should be kept with different versions and a schema which specifies the version.
56
+
18
57
  Adhearsion CLI. Should use the 'breakpoint' library's DRb extension to run an irb session in an external Ruby interpreter (Adhearsion's)
19
58
 
59
+ Allow config files to use ERb
60
+
20
61
  Let record() take a block of functionality to record. This feature will probably only be available when an AMI connection is present.
21
62
 
22
- Build in hunt-group support into dial()
63
+ Build in hunt-group support into dial(). Basically, traverse a list of people to dial and checking for timeouts. When a timeout occurs, try the next person. Can optionally loop.
64
+
65
+ Allow the multi_messenger.rb helper's event handlers to be declared somewhere other than the file itself (e.g. config/helpers/ directory)
66
+
67
+ Package standard ActiveRecord with KirbyBase for extremely portable development databases.
68
+
69
+ Use Piston with svn:externals to keep third-party libraries up to date in the repository
70
+
71
+ When "ahn" is ran, it should check for whether the current directory is actually an Adhearsion app before trying to intialize. At the moment it says it can't find the adhearsion.log file. This is probably pretty strange when first encountered. If no Adhearsion app is found, it should simply print out the usage information.
data/ahn CHANGED
@@ -18,6 +18,7 @@
18
18
  # You should have received a copy of the GNU Lesser General Public
19
19
  # License along with this library; if not, write to the Free Software
20
20
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
+
21
22
  require 'rubygems'
22
23
 
23
24
  usage = "Usage:
@@ -215,7 +216,7 @@ when 'start'
215
216
  sc = ServletContainer.new((CONFIG['port'] || 4573), (CONFIG['host'] || '0.0.0.0'))
216
217
  $HUTDOWN.hook { sc.shutdown }
217
218
 
218
- log "Dallas, we have liftoff!"
219
+ log "Adhearsion Started"
219
220
  sc.server.join
220
221
 
221
222
  else puts "Unrecognized command!", usage
@@ -2,8 +2,7 @@ require 'rubygems'
2
2
  require 'rake/testtask'
3
3
  require 'rake/rdoctask'
4
4
 
5
- Summary = 'Adhearsion is a professional integration system for
6
- integrating anything and everything.'
5
+ Summary = 'Adhearsion is a professional integration system for integrating anything and everything.'
7
6
 
8
7
  desc "Generate RDoc documentation for Adhearsion"
9
8
  Rake::RDocTask.new do |rdoc|
@@ -46,11 +45,21 @@ task :prepare_release do
46
45
  puts "WARNING: These files are not under version control:\n#{unversioned_files}" unless unversioned_files.empty?
47
46
  end
48
47
 
49
- desc 'Create sample databases per the config/migration.rb and database.yml files.'
50
- task :migrate do
48
+ desc 'Initialize the environment for an ActiveRecord::Migration'
49
+ task :init_migrations do
50
+ require 'active_record'
51
+ # This won't work until the Adhearsion codebase is refactored.
52
+ require 'lib/sexy_migrations'
53
+
54
+ ActiveRecord::ConnectionAdapters::TableDefinition.send :include, SexyMigrations::Table
55
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.send :include, SexyMigrations::Schema
56
+
51
57
  require 'config/migration'
52
- Module.constants.each do |c|
53
- c = Module.const_get(c)
54
- c.up if c.respond_to?(:superclass) && c.superclass == ActiveRecord::Migration
58
+ end
59
+
60
+ desc 'Create sample databases per the config/migration.rb and database.yml files.'
61
+ task :migrate => [:init_migrations] do
62
+ ObjectSpace.each_object(Class) do |c|
63
+ c.up if c.superclass == ActiveRecord::Migration
55
64
  end
56
65
  end
@@ -1,6 +1,22 @@
1
+ # HEY! FILL IN A CONTEXT! This should be a context in
2
+ # your extensions.conf that points entirely to Adhearsion.
3
+ # For example, this may be the context you include
4
+ # the "exten => _X.,1,AGI(agi://192.168.1.3)" line in.
5
+ context:
6
+ # context: internal # Example
7
+
8
+ # Since you probably want to handle your dialplans without
9
+ # remembering to answer() and hangup() the call, Adhearsion
10
+ # will automatically do this for you if you specify it here.
1
11
  answer_before_call: true
2
12
  hangup_after_call: true
13
+ hangup_after_error: true
14
+
15
+ # Do you want to use database.rb in your app? Enable this.
3
16
  enable_database: false
17
+
18
+ # This is the host and port on which Adhearsion's AGI server
19
+ # listens for incoming dial plan processing requests.
4
20
  host: 0.0.0.0
5
21
  port: 4573
6
22
 
@@ -38,6 +54,12 @@ drb:
38
54
  - 127.0.0.1
39
55
  - 192.168.1.*
40
56
 
57
+ manager:
58
+ host: 192.168.48.129
59
+ username: jicksta
60
+ password: pass
61
+ events: false
62
+
41
63
  # Set your access control permissions above.
42
64
  # Values for deny and allow can be several
43
65
  # things:
@@ -71,4 +93,3 @@ drb:
71
93
  # - 192.168.1.123
72
94
  # - 192.168.1.99
73
95
  # - 66.199.34.44
74
-
@@ -2,6 +2,7 @@ enabled: false
2
2
  host: 192.168.1.2
3
3
  username: jicksta
4
4
  secret: jicksta
5
+ events: false
5
6
  #port: 5038
6
7
  #console: 0
7
8
  #event_cache: 100
@@ -0,0 +1,1341 @@
1
+ /*
2
+ Copyright (c) 2006, Yahoo! Inc. All rights reserved.
3
+ Code licensed under the BSD License:
4
+ http://developer.yahoo.net/yui/license.txt
5
+ version: 0.12.2
6
+ */
7
+ /**
8
+ * The animation module provides allows effects to be added to HTMLElements.
9
+ * @module animation
10
+ * @requires yahoo, event, dom
11
+ */
12
+
13
+ /**
14
+ *
15
+ * Base animation class that provides the interface for building animated effects.
16
+ * <p>Usage: var myAnim = new YAHOO.util.Anim(el, { width: { from: 10, to: 100 } }, 1, YAHOO.util.Easing.easeOut);</p>
17
+ * @class Anim
18
+ * @namespace YAHOO.util
19
+ * @requires YAHOO.util.AnimMgr
20
+ * @requires YAHOO.util.Easing
21
+ * @requires YAHOO.util.Dom
22
+ * @requires YAHOO.util.Event
23
+ * @requires YAHOO.util.CustomEvent
24
+ * @constructor
25
+ * @param {String | HTMLElement} el Reference to the element that will be animated
26
+ * @param {Object} attributes The attribute(s) to be animated.
27
+ * Each attribute is an object with at minimum a "to" or "by" member defined.
28
+ * Additional optional members are "from" (defaults to current value), "units" (defaults to "px").
29
+ * All attribute names use camelCase.
30
+ * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
31
+ * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method)
32
+ */
33
+
34
+ YAHOO.util.Anim = function(el, attributes, duration, method) {
35
+ if (el) {
36
+ this.init(el, attributes, duration, method);
37
+ }
38
+ };
39
+
40
+ YAHOO.util.Anim.prototype = {
41
+ /**
42
+ * Provides a readable name for the Anim instance.
43
+ * @method toString
44
+ * @return {String}
45
+ */
46
+ toString: function() {
47
+ var el = this.getEl();
48
+ var id = el.id || el.tagName;
49
+ return ("Anim " + id);
50
+ },
51
+
52
+ patterns: { // cached for performance
53
+ noNegatives: /width|height|opacity|padding/i, // keep at zero or above
54
+ offsetAttribute: /^((width|height)|(top|left))$/, // use offsetValue as default
55
+ defaultUnit: /width|height|top$|bottom$|left$|right$/i, // use 'px' by default
56
+ offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i // IE may return these, so convert these to offset
57
+ },
58
+
59
+ /**
60
+ * Returns the value computed by the animation's "method".
61
+ * @method doMethod
62
+ * @param {String} attr The name of the attribute.
63
+ * @param {Number} start The value this attribute should start from for this animation.
64
+ * @param {Number} end The value this attribute should end at for this animation.
65
+ * @return {Number} The Value to be applied to the attribute.
66
+ */
67
+ doMethod: function(attr, start, end) {
68
+ return this.method(this.currentFrame, start, end - start, this.totalFrames);
69
+ },
70
+
71
+ /**
72
+ * Applies a value to an attribute.
73
+ * @method setAttribute
74
+ * @param {String} attr The name of the attribute.
75
+ * @param {Number} val The value to be applied to the attribute.
76
+ * @param {String} unit The unit ('px', '%', etc.) of the value.
77
+ */
78
+ setAttribute: function(attr, val, unit) {
79
+ if ( this.patterns.noNegatives.test(attr) ) {
80
+ val = (val > 0) ? val : 0;
81
+ }
82
+
83
+ YAHOO.util.Dom.setStyle(this.getEl(), attr, val + unit);
84
+ },
85
+
86
+ /**
87
+ * Returns current value of the attribute.
88
+ * @method getAttribute
89
+ * @param {String} attr The name of the attribute.
90
+ * @return {Number} val The current value of the attribute.
91
+ */
92
+ getAttribute: function(attr) {
93
+ var el = this.getEl();
94
+ var val = YAHOO.util.Dom.getStyle(el, attr);
95
+
96
+ if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
97
+ return parseFloat(val);
98
+ }
99
+
100
+ var a = this.patterns.offsetAttribute.exec(attr) || [];
101
+ var pos = !!( a[3] ); // top or left
102
+ var box = !!( a[2] ); // width or height
103
+
104
+ // use offsets for width/height and abs pos top/left
105
+ if ( box || (YAHOO.util.Dom.getStyle(el, 'position') == 'absolute' && pos) ) {
106
+ val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
107
+ } else { // default to zero for other 'auto'
108
+ val = 0;
109
+ }
110
+
111
+ return val;
112
+ },
113
+
114
+ /**
115
+ * Returns the unit to use when none is supplied.
116
+ * @method getDefaultUnit
117
+ * @param {attr} attr The name of the attribute.
118
+ * @return {String} The default unit to be used.
119
+ */
120
+ getDefaultUnit: function(attr) {
121
+ if ( this.patterns.defaultUnit.test(attr) ) {
122
+ return 'px';
123
+ }
124
+
125
+ return '';
126
+ },
127
+
128
+ /**
129
+ * Sets the actual values to be used during the animation. Should only be needed for subclass use.
130
+ * @method setRuntimeAttribute
131
+ * @param {Object} attr The attribute object
132
+ * @private
133
+ */
134
+ setRuntimeAttribute: function(attr) {
135
+ var start;
136
+ var end;
137
+ var attributes = this.attributes;
138
+
139
+ this.runtimeAttributes[attr] = {};
140
+
141
+ var isset = function(prop) {
142
+ return (typeof prop !== 'undefined');
143
+ };
144
+
145
+ if ( !isset(attributes[attr]['to']) && !isset(attributes[attr]['by']) ) {
146
+ return false; // note return; nothing to animate to
147
+ }
148
+
149
+ start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
150
+
151
+ // To beats by, per SMIL 2.1 spec
152
+ if ( isset(attributes[attr]['to']) ) {
153
+ end = attributes[attr]['to'];
154
+ } else if ( isset(attributes[attr]['by']) ) {
155
+ if (start.constructor == Array) {
156
+ end = [];
157
+ for (var i = 0, len = start.length; i < len; ++i) {
158
+ end[i] = start[i] + attributes[attr]['by'][i];
159
+ }
160
+ } else {
161
+ end = start + attributes[attr]['by'];
162
+ }
163
+ }
164
+
165
+ this.runtimeAttributes[attr].start = start;
166
+ this.runtimeAttributes[attr].end = end;
167
+
168
+ // set units if needed
169
+ this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
170
+ },
171
+
172
+ /**
173
+ * Constructor for Anim instance.
174
+ * @method init
175
+ * @param {String | HTMLElement} el Reference to the element that will be animated
176
+ * @param {Object} attributes The attribute(s) to be animated.
177
+ * Each attribute is an object with at minimum a "to" or "by" member defined.
178
+ * Additional optional members are "from" (defaults to current value), "units" (defaults to "px").
179
+ * All attribute names use camelCase.
180
+ * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
181
+ * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method)
182
+ */
183
+ init: function(el, attributes, duration, method) {
184
+ /**
185
+ * Whether or not the animation is running.
186
+ * @property isAnimated
187
+ * @private
188
+ * @type Boolean
189
+ */
190
+ var isAnimated = false;
191
+
192
+ /**
193
+ * A Date object that is created when the animation begins.
194
+ * @property startTime
195
+ * @private
196
+ * @type Date
197
+ */
198
+ var startTime = null;
199
+
200
+ /**
201
+ * The number of frames this animation was able to execute.
202
+ * @property actualFrames
203
+ * @private
204
+ * @type Int
205
+ */
206
+ var actualFrames = 0;
207
+
208
+ /**
209
+ * The element to be animated.
210
+ * @property el
211
+ * @private
212
+ * @type HTMLElement
213
+ */
214
+ el = YAHOO.util.Dom.get(el);
215
+
216
+ /**
217
+ * The collection of attributes to be animated.
218
+ * Each attribute must have at least a "to" or "by" defined in order to animate.
219
+ * If "to" is supplied, the animation will end with the attribute at that value.
220
+ * If "by" is supplied, the animation will end at that value plus its starting value.
221
+ * If both are supplied, "to" is used, and "by" is ignored.
222
+ * Optional additional member include "from" (the value the attribute should start animating from, defaults to current value), and "unit" (the units to apply to the values).
223
+ * @property attributes
224
+ * @type Object
225
+ */
226
+ this.attributes = attributes || {};
227
+
228
+ /**
229
+ * The length of the animation. Defaults to "1" (second).
230
+ * @property duration
231
+ * @type Number
232
+ */
233
+ this.duration = duration || 1;
234
+
235
+ /**
236
+ * The method that will provide values to the attribute(s) during the animation.
237
+ * Defaults to "YAHOO.util.Easing.easeNone".
238
+ * @property method
239
+ * @type Function
240
+ */
241
+ this.method = method || YAHOO.util.Easing.easeNone;
242
+
243
+ /**
244
+ * Whether or not the duration should be treated as seconds.
245
+ * Defaults to true.
246
+ * @property useSeconds
247
+ * @type Boolean
248
+ */
249
+ this.useSeconds = true; // default to seconds
250
+
251
+ /**
252
+ * The location of the current animation on the timeline.
253
+ * In time-based animations, this is used by AnimMgr to ensure the animation finishes on time.
254
+ * @property currentFrame
255
+ * @type Int
256
+ */
257
+ this.currentFrame = 0;
258
+
259
+ /**
260
+ * The total number of frames to be executed.
261
+ * In time-based animations, this is used by AnimMgr to ensure the animation finishes on time.
262
+ * @property totalFrames
263
+ * @type Int
264
+ */
265
+ this.totalFrames = YAHOO.util.AnimMgr.fps;
266
+
267
+
268
+ /**
269
+ * Returns a reference to the animated element.
270
+ * @method getEl
271
+ * @return {HTMLElement}
272
+ */
273
+ this.getEl = function() { return el; };
274
+
275
+ /**
276
+ * Checks whether the element is currently animated.
277
+ * @method isAnimated
278
+ * @return {Boolean} current value of isAnimated.
279
+ */
280
+ this.isAnimated = function() {
281
+ return isAnimated;
282
+ };
283
+
284
+ /**
285
+ * Returns the animation start time.
286
+ * @method getStartTime
287
+ * @return {Date} current value of startTime.
288
+ */
289
+ this.getStartTime = function() {
290
+ return startTime;
291
+ };
292
+
293
+ this.runtimeAttributes = {};
294
+
295
+
296
+
297
+ /**
298
+ * Starts the animation by registering it with the animation manager.
299
+ * @method animate
300
+ */
301
+ this.animate = function() {
302
+ if ( this.isAnimated() ) {
303
+ return false;
304
+ }
305
+
306
+ this.currentFrame = 0;
307
+
308
+ this.totalFrames = ( this.useSeconds ) ? Math.ceil(YAHOO.util.AnimMgr.fps * this.duration) : this.duration;
309
+
310
+ YAHOO.util.AnimMgr.registerElement(this);
311
+ };
312
+
313
+ /**
314
+ * Stops the animation. Normally called by AnimMgr when animation completes.
315
+ * @method stop
316
+ * @param {Boolean} finish (optional) If true, animation will jump to final frame.
317
+ */
318
+ this.stop = function(finish) {
319
+ if (finish) {
320
+ this.currentFrame = this.totalFrames;
321
+ this._onTween.fire();
322
+ }
323
+ YAHOO.util.AnimMgr.stop(this);
324
+ };
325
+
326
+ var onStart = function() {
327
+ this.onStart.fire();
328
+
329
+ this.runtimeAttributes = {};
330
+ for (var attr in this.attributes) {
331
+ this.setRuntimeAttribute(attr);
332
+ }
333
+
334
+ isAnimated = true;
335
+ actualFrames = 0;
336
+ startTime = new Date();
337
+ };
338
+
339
+ /**
340
+ * Feeds the starting and ending values for each animated attribute to doMethod once per frame, then applies the resulting value to the attribute(s).
341
+ * @private
342
+ */
343
+
344
+ var onTween = function() {
345
+ var data = {
346
+ duration: new Date() - this.getStartTime(),
347
+ currentFrame: this.currentFrame
348
+ };
349
+
350
+ data.toString = function() {
351
+ return (
352
+ 'duration: ' + data.duration +
353
+ ', currentFrame: ' + data.currentFrame
354
+ );
355
+ };
356
+
357
+ this.onTween.fire(data);
358
+
359
+ var runtimeAttributes = this.runtimeAttributes;
360
+
361
+ for (var attr in runtimeAttributes) {
362
+ this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
363
+ }
364
+
365
+ actualFrames += 1;
366
+ };
367
+
368
+ var onComplete = function() {
369
+ var actual_duration = (new Date() - startTime) / 1000 ;
370
+
371
+ var data = {
372
+ duration: actual_duration,
373
+ frames: actualFrames,
374
+ fps: actualFrames / actual_duration
375
+ };
376
+
377
+ data.toString = function() {
378
+ return (
379
+ 'duration: ' + data.duration +
380
+ ', frames: ' + data.frames +
381
+ ', fps: ' + data.fps
382
+ );
383
+ };
384
+
385
+ isAnimated = false;
386
+ actualFrames = 0;
387
+ this.onComplete.fire(data);
388
+ };
389
+
390
+ /**
391
+ * Custom event that fires after onStart, useful in subclassing
392
+ * @private
393
+ */
394
+ this._onStart = new YAHOO.util.CustomEvent('_start', this, true);
395
+
396
+ /**
397
+ * Custom event that fires when animation begins
398
+ * Listen via subscribe method (e.g. myAnim.onStart.subscribe(someFunction)
399
+ * @event onStart
400
+ */
401
+ this.onStart = new YAHOO.util.CustomEvent('start', this);
402
+
403
+ /**
404
+ * Custom event that fires between each frame
405
+ * Listen via subscribe method (e.g. myAnim.onTween.subscribe(someFunction)
406
+ * @event onTween
407
+ */
408
+ this.onTween = new YAHOO.util.CustomEvent('tween', this);
409
+
410
+ /**
411
+ * Custom event that fires after onTween
412
+ * @private
413
+ */
414
+ this._onTween = new YAHOO.util.CustomEvent('_tween', this, true);
415
+
416
+ /**
417
+ * Custom event that fires when animation ends
418
+ * Listen via subscribe method (e.g. myAnim.onComplete.subscribe(someFunction)
419
+ * @event onComplete
420
+ */
421
+ this.onComplete = new YAHOO.util.CustomEvent('complete', this);
422
+ /**
423
+ * Custom event that fires after onComplete
424
+ * @private
425
+ */
426
+ this._onComplete = new YAHOO.util.CustomEvent('_complete', this, true);
427
+
428
+ this._onStart.subscribe(onStart);
429
+ this._onTween.subscribe(onTween);
430
+ this._onComplete.subscribe(onComplete);
431
+ }
432
+ };
433
+
434
+ /**
435
+ * Handles animation queueing and threading.
436
+ * Used by Anim and subclasses.
437
+ * @class AnimMgr
438
+ * @namespace YAHOO.util
439
+ */
440
+ YAHOO.util.AnimMgr = new function() {
441
+ /**
442
+ * Reference to the animation Interval.
443
+ * @property thread
444
+ * @private
445
+ * @type Int
446
+ */
447
+ var thread = null;
448
+
449
+ /**
450
+ * The current queue of registered animation objects.
451
+ * @property queue
452
+ * @private
453
+ * @type Array
454
+ */
455
+ var queue = [];
456
+
457
+ /**
458
+ * The number of active animations.
459
+ * @property tweenCount
460
+ * @private
461
+ * @type Int
462
+ */
463
+ var tweenCount = 0;
464
+
465
+ /**
466
+ * Base frame rate (frames per second).
467
+ * Arbitrarily high for better x-browser calibration (slower browsers drop more frames).
468
+ * @property fps
469
+ * @type Int
470
+ *
471
+ */
472
+ this.fps = 1000;
473
+
474
+ /**
475
+ * Interval delay in milliseconds, defaults to fastest possible.
476
+ * @property delay
477
+ * @type Int
478
+ *
479
+ */
480
+ this.delay = 1;
481
+
482
+ /**
483
+ * Adds an animation instance to the animation queue.
484
+ * All animation instances must be registered in order to animate.
485
+ * @method registerElement
486
+ * @param {object} tween The Anim instance to be be registered
487
+ */
488
+ this.registerElement = function(tween) {
489
+ queue[queue.length] = tween;
490
+ tweenCount += 1;
491
+ tween._onStart.fire();
492
+ this.start();
493
+ };
494
+
495
+ /**
496
+ * removes an animation instance from the animation queue.
497
+ * All animation instances must be registered in order to animate.
498
+ * @method unRegister
499
+ * @param {object} tween The Anim instance to be be registered
500
+ * @param {Int} index The index of the Anim instance
501
+ * @private
502
+ */
503
+ this.unRegister = function(tween, index) {
504
+ tween._onComplete.fire();
505
+ index = index || getIndex(tween);
506
+ if (index != -1) { queue.splice(index, 1); }
507
+
508
+ tweenCount -= 1;
509
+ if (tweenCount <= 0) { this.stop(); }
510
+ };
511
+
512
+ /**
513
+ * Starts the animation thread.
514
+ * Only one thread can run at a time.
515
+ * @method start
516
+ */
517
+ this.start = function() {
518
+ if (thread === null) { thread = setInterval(this.run, this.delay); }
519
+ };
520
+
521
+ /**
522
+ * Stops the animation thread or a specific animation instance.
523
+ * @method stop
524
+ * @param {object} tween A specific Anim instance to stop (optional)
525
+ * If no instance given, Manager stops thread and all animations.
526
+ */
527
+ this.stop = function(tween) {
528
+ if (!tween) {
529
+ clearInterval(thread);
530
+ for (var i = 0, len = queue.length; i < len; ++i) {
531
+ if (queue[i].isAnimated()) {
532
+ this.unRegister(tween, i);
533
+ }
534
+ }
535
+ queue = [];
536
+ thread = null;
537
+ tweenCount = 0;
538
+ }
539
+ else {
540
+ this.unRegister(tween);
541
+ }
542
+ };
543
+
544
+ /**
545
+ * Called per Interval to handle each animation frame.
546
+ * @method run
547
+ */
548
+ this.run = function() {
549
+ for (var i = 0, len = queue.length; i < len; ++i) {
550
+ var tween = queue[i];
551
+ if ( !tween || !tween.isAnimated() ) { continue; }
552
+
553
+ if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
554
+ {
555
+ tween.currentFrame += 1;
556
+
557
+ if (tween.useSeconds) {
558
+ correctFrame(tween);
559
+ }
560
+ tween._onTween.fire();
561
+ }
562
+ else { YAHOO.util.AnimMgr.stop(tween, i); }
563
+ }
564
+ };
565
+
566
+ var getIndex = function(anim) {
567
+ for (var i = 0, len = queue.length; i < len; ++i) {
568
+ if (queue[i] == anim) {
569
+ return i; // note return;
570
+ }
571
+ }
572
+ return -1;
573
+ };
574
+
575
+ /**
576
+ * On the fly frame correction to keep animation on time.
577
+ * @method correctFrame
578
+ * @private
579
+ * @param {Object} tween The Anim instance being corrected.
580
+ */
581
+ var correctFrame = function(tween) {
582
+ var frames = tween.totalFrames;
583
+ var frame = tween.currentFrame;
584
+ var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
585
+ var elapsed = (new Date() - tween.getStartTime());
586
+ var tweak = 0;
587
+
588
+ if (elapsed < tween.duration * 1000) { // check if falling behind
589
+ tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
590
+ } else { // went over duration, so jump to end
591
+ tweak = frames - (frame + 1);
592
+ }
593
+ if (tweak > 0 && isFinite(tweak)) { // adjust if needed
594
+ if (tween.currentFrame + tweak >= frames) {// dont go past last frame
595
+ tweak = frames - (frame + 1);
596
+ }
597
+
598
+ tween.currentFrame += tweak;
599
+ }
600
+ };
601
+ };
602
+ /**
603
+ * Used to calculate Bezier splines for any number of control points.
604
+ * @class Bezier
605
+ * @namespace YAHOO.util
606
+ *
607
+ */
608
+ YAHOO.util.Bezier = new function() {
609
+ /**
610
+ * Get the current position of the animated element based on t.
611
+ * Each point is an array of "x" and "y" values (0 = x, 1 = y)
612
+ * At least 2 points are required (start and end).
613
+ * First point is start. Last point is end.
614
+ * Additional control points are optional.
615
+ * @method getPosition
616
+ * @param {Array} points An array containing Bezier points
617
+ * @param {Number} t A number between 0 and 1 which is the basis for determining current position
618
+ * @return {Array} An array containing int x and y member data
619
+ */
620
+ this.getPosition = function(points, t) {
621
+ var n = points.length;
622
+ var tmp = [];
623
+
624
+ for (var i = 0; i < n; ++i){
625
+ tmp[i] = [points[i][0], points[i][1]]; // save input
626
+ }
627
+
628
+ for (var j = 1; j < n; ++j) {
629
+ for (i = 0; i < n - j; ++i) {
630
+ tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
631
+ tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
632
+ }
633
+ }
634
+
635
+ return [ tmp[0][0], tmp[0][1] ];
636
+
637
+ };
638
+ };
639
+ (function() {
640
+ /**
641
+ * Anim subclass for color transitions.
642
+ * <p>Usage: <code>var myAnim = new Y.ColorAnim(el, { backgroundColor: { from: '#FF0000', to: '#FFFFFF' } }, 1, Y.Easing.easeOut);</code> Color values can be specified with either 112233, #112233,
643
+ * [255,255,255], or rgb(255,255,255)</p>
644
+ * @class ColorAnim
645
+ * @namespace YAHOO.util
646
+ * @requires YAHOO.util.Anim
647
+ * @requires YAHOO.util.AnimMgr
648
+ * @requires YAHOO.util.Easing
649
+ * @requires YAHOO.util.Bezier
650
+ * @requires YAHOO.util.Dom
651
+ * @requires YAHOO.util.Event
652
+ * @constructor
653
+ * @extends YAHOO.util.Anim
654
+ * @param {HTMLElement | String} el Reference to the element that will be animated
655
+ * @param {Object} attributes The attribute(s) to be animated.
656
+ * Each attribute is an object with at minimum a "to" or "by" member defined.
657
+ * Additional optional members are "from" (defaults to current value), "units" (defaults to "px").
658
+ * All attribute names use camelCase.
659
+ * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
660
+ * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method)
661
+ */
662
+ YAHOO.util.ColorAnim = function(el, attributes, duration, method) {
663
+ YAHOO.util.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
664
+ };
665
+
666
+ YAHOO.extend(YAHOO.util.ColorAnim, YAHOO.util.Anim);
667
+
668
+ // shorthand
669
+ var Y = YAHOO.util;
670
+ var superclass = Y.ColorAnim.superclass;
671
+ var proto = Y.ColorAnim.prototype;
672
+
673
+ proto.toString = function() {
674
+ var el = this.getEl();
675
+ var id = el.id || el.tagName;
676
+ return ("ColorAnim " + id);
677
+ };
678
+
679
+ proto.patterns.color = /color$/i;
680
+ proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
681
+ proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
682
+ proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
683
+ proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/; // need rgba for safari
684
+
685
+ /**
686
+ * Attempts to parse the given string and return a 3-tuple.
687
+ * @method parseColor
688
+ * @param {String} s The string to parse.
689
+ * @return {Array} The 3-tuple of rgb values.
690
+ */
691
+ proto.parseColor = function(s) {
692
+ if (s.length == 3) { return s; }
693
+
694
+ var c = this.patterns.hex.exec(s);
695
+ if (c && c.length == 4) {
696
+ return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
697
+ }
698
+
699
+ c = this.patterns.rgb.exec(s);
700
+ if (c && c.length == 4) {
701
+ return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
702
+ }
703
+
704
+ c = this.patterns.hex3.exec(s);
705
+ if (c && c.length == 4) {
706
+ return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
707
+ }
708
+
709
+ return null;
710
+ };
711
+
712
+ proto.getAttribute = function(attr) {
713
+ var el = this.getEl();
714
+ if ( this.patterns.color.test(attr) ) {
715
+ var val = YAHOO.util.Dom.getStyle(el, attr);
716
+
717
+ if (this.patterns.transparent.test(val)) { // bgcolor default
718
+ var parent = el.parentNode; // try and get from an ancestor
719
+ val = Y.Dom.getStyle(parent, attr);
720
+
721
+ while (parent && this.patterns.transparent.test(val)) {
722
+ parent = parent.parentNode;
723
+ val = Y.Dom.getStyle(parent, attr);
724
+ if (parent.tagName.toUpperCase() == 'HTML') {
725
+ val = '#fff';
726
+ }
727
+ }
728
+ }
729
+ } else {
730
+ val = superclass.getAttribute.call(this, attr);
731
+ }
732
+
733
+ return val;
734
+ };
735
+
736
+ proto.doMethod = function(attr, start, end) {
737
+ var val;
738
+
739
+ if ( this.patterns.color.test(attr) ) {
740
+ val = [];
741
+ for (var i = 0, len = start.length; i < len; ++i) {
742
+ val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
743
+ }
744
+
745
+ val = 'rgb('+Math.floor(val[0])+','+Math.floor(val[1])+','+Math.floor(val[2])+')';
746
+ }
747
+ else {
748
+ val = superclass.doMethod.call(this, attr, start, end);
749
+ }
750
+
751
+ return val;
752
+ };
753
+
754
+ proto.setRuntimeAttribute = function(attr) {
755
+ superclass.setRuntimeAttribute.call(this, attr);
756
+
757
+ if ( this.patterns.color.test(attr) ) {
758
+ var attributes = this.attributes;
759
+ var start = this.parseColor(this.runtimeAttributes[attr].start);
760
+ var end = this.parseColor(this.runtimeAttributes[attr].end);
761
+ // fix colors if going "by"
762
+ if ( typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined' ) {
763
+ end = this.parseColor(attributes[attr].by);
764
+
765
+ for (var i = 0, len = start.length; i < len; ++i) {
766
+ end[i] = start[i] + end[i];
767
+ }
768
+ }
769
+
770
+ this.runtimeAttributes[attr].start = start;
771
+ this.runtimeAttributes[attr].end = end;
772
+ }
773
+ };
774
+ })();/*
775
+ TERMS OF USE - EASING EQUATIONS
776
+ Open source under the BSD License.
777
+ Copyright 2001 Robert Penner All rights reserved.
778
+
779
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
780
+
781
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
782
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
783
+ * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission.
784
+
785
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
786
+ */
787
+
788
+ /**
789
+ * Singleton that determines how an animation proceeds from start to end.
790
+ * @class Easing
791
+ * @namespace YAHOO.util
792
+ */
793
+
794
+ YAHOO.util.Easing = {
795
+
796
+ /**
797
+ * Uniform speed between points.
798
+ * @method easeNone
799
+ * @param {Number} t Time value used to compute current value
800
+ * @param {Number} b Starting value
801
+ * @param {Number} c Delta between start and end values
802
+ * @param {Number} d Total length of animation
803
+ * @return {Number} The computed value for the current animation frame
804
+ */
805
+ easeNone: function (t, b, c, d) {
806
+ return c*t/d + b;
807
+ },
808
+
809
+ /**
810
+ * Begins slowly and accelerates towards end. (quadratic)
811
+ * @method easeIn
812
+ * @param {Number} t Time value used to compute current value
813
+ * @param {Number} b Starting value
814
+ * @param {Number} c Delta between start and end values
815
+ * @param {Number} d Total length of animation
816
+ * @return {Number} The computed value for the current animation frame
817
+ */
818
+ easeIn: function (t, b, c, d) {
819
+ return c*(t/=d)*t + b;
820
+ },
821
+
822
+ /**
823
+ * Begins quickly and decelerates towards end. (quadratic)
824
+ * @method easeOut
825
+ * @param {Number} t Time value used to compute current value
826
+ * @param {Number} b Starting value
827
+ * @param {Number} c Delta between start and end values
828
+ * @param {Number} d Total length of animation
829
+ * @return {Number} The computed value for the current animation frame
830
+ */
831
+ easeOut: function (t, b, c, d) {
832
+ return -c *(t/=d)*(t-2) + b;
833
+ },
834
+
835
+ /**
836
+ * Begins slowly and decelerates towards end. (quadratic)
837
+ * @method easeBoth
838
+ * @param {Number} t Time value used to compute current value
839
+ * @param {Number} b Starting value
840
+ * @param {Number} c Delta between start and end values
841
+ * @param {Number} d Total length of animation
842
+ * @return {Number} The computed value for the current animation frame
843
+ */
844
+ easeBoth: function (t, b, c, d) {
845
+ if ((t/=d/2) < 1) {
846
+ return c/2*t*t + b;
847
+ }
848
+
849
+ return -c/2 * ((--t)*(t-2) - 1) + b;
850
+ },
851
+
852
+ /**
853
+ * Begins slowly and accelerates towards end. (quartic)
854
+ * @method easeInStrong
855
+ * @param {Number} t Time value used to compute current value
856
+ * @param {Number} b Starting value
857
+ * @param {Number} c Delta between start and end values
858
+ * @param {Number} d Total length of animation
859
+ * @return {Number} The computed value for the current animation frame
860
+ */
861
+ easeInStrong: function (t, b, c, d) {
862
+ return c*(t/=d)*t*t*t + b;
863
+ },
864
+
865
+ /**
866
+ * Begins quickly and decelerates towards end. (quartic)
867
+ * @method easeOutStrong
868
+ * @param {Number} t Time value used to compute current value
869
+ * @param {Number} b Starting value
870
+ * @param {Number} c Delta between start and end values
871
+ * @param {Number} d Total length of animation
872
+ * @return {Number} The computed value for the current animation frame
873
+ */
874
+ easeOutStrong: function (t, b, c, d) {
875
+ return -c * ((t=t/d-1)*t*t*t - 1) + b;
876
+ },
877
+
878
+ /**
879
+ * Begins slowly and decelerates towards end. (quartic)
880
+ * @method easeBothStrong
881
+ * @param {Number} t Time value used to compute current value
882
+ * @param {Number} b Starting value
883
+ * @param {Number} c Delta between start and end values
884
+ * @param {Number} d Total length of animation
885
+ * @return {Number} The computed value for the current animation frame
886
+ */
887
+ easeBothStrong: function (t, b, c, d) {
888
+ if ((t/=d/2) < 1) {
889
+ return c/2*t*t*t*t + b;
890
+ }
891
+
892
+ return -c/2 * ((t-=2)*t*t*t - 2) + b;
893
+ },
894
+
895
+ /**
896
+ * Snap in elastic effect.
897
+ * @method elasticIn
898
+ * @param {Number} t Time value used to compute current value
899
+ * @param {Number} b Starting value
900
+ * @param {Number} c Delta between start and end values
901
+ * @param {Number} d Total length of animation
902
+ * @param {Number} a Amplitude (optional)
903
+ * @param {Number} p Period (optional)
904
+ * @return {Number} The computed value for the current animation frame
905
+ */
906
+
907
+ elasticIn: function (t, b, c, d, a, p) {
908
+ if (t == 0) {
909
+ return b;
910
+ }
911
+ if ( (t /= d) == 1 ) {
912
+ return b+c;
913
+ }
914
+ if (!p) {
915
+ p=d*.3;
916
+ }
917
+
918
+ if (!a || a < Math.abs(c)) {
919
+ a = c;
920
+ var s = p/4;
921
+ }
922
+ else {
923
+ var s = p/(2*Math.PI) * Math.asin (c/a);
924
+ }
925
+
926
+ return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
927
+ },
928
+
929
+ /**
930
+ * Snap out elastic effect.
931
+ * @method elasticOut
932
+ * @param {Number} t Time value used to compute current value
933
+ * @param {Number} b Starting value
934
+ * @param {Number} c Delta between start and end values
935
+ * @param {Number} d Total length of animation
936
+ * @param {Number} a Amplitude (optional)
937
+ * @param {Number} p Period (optional)
938
+ * @return {Number} The computed value for the current animation frame
939
+ */
940
+ elasticOut: function (t, b, c, d, a, p) {
941
+ if (t == 0) {
942
+ return b;
943
+ }
944
+ if ( (t /= d) == 1 ) {
945
+ return b+c;
946
+ }
947
+ if (!p) {
948
+ p=d*.3;
949
+ }
950
+
951
+ if (!a || a < Math.abs(c)) {
952
+ a = c;
953
+ var s = p / 4;
954
+ }
955
+ else {
956
+ var s = p/(2*Math.PI) * Math.asin (c/a);
957
+ }
958
+
959
+ return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
960
+ },
961
+
962
+ /**
963
+ * Snap both elastic effect.
964
+ * @method elasticBoth
965
+ * @param {Number} t Time value used to compute current value
966
+ * @param {Number} b Starting value
967
+ * @param {Number} c Delta between start and end values
968
+ * @param {Number} d Total length of animation
969
+ * @param {Number} a Amplitude (optional)
970
+ * @param {Number} p Period (optional)
971
+ * @return {Number} The computed value for the current animation frame
972
+ */
973
+ elasticBoth: function (t, b, c, d, a, p) {
974
+ if (t == 0) {
975
+ return b;
976
+ }
977
+
978
+ if ( (t /= d/2) == 2 ) {
979
+ return b+c;
980
+ }
981
+
982
+ if (!p) {
983
+ p = d*(.3*1.5);
984
+ }
985
+
986
+ if ( !a || a < Math.abs(c) ) {
987
+ a = c;
988
+ var s = p/4;
989
+ }
990
+ else {
991
+ var s = p/(2*Math.PI) * Math.asin (c/a);
992
+ }
993
+
994
+ if (t < 1) {
995
+ return -.5*(a*Math.pow(2,10*(t-=1)) *
996
+ Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
997
+ }
998
+ return a*Math.pow(2,-10*(t-=1)) *
999
+ Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
1000
+ },
1001
+
1002
+ /**
1003
+ * Backtracks slightly, then reverses direction and moves to end.
1004
+ * @method backIn
1005
+ * @param {Number} t Time value used to compute current value
1006
+ * @param {Number} b Starting value
1007
+ * @param {Number} c Delta between start and end values
1008
+ * @param {Number} d Total length of animation
1009
+ * @param {Number} s Overshoot (optional)
1010
+ * @return {Number} The computed value for the current animation frame
1011
+ */
1012
+ backIn: function (t, b, c, d, s) {
1013
+ if (typeof s == 'undefined') {
1014
+ s = 1.70158;
1015
+ }
1016
+ return c*(t/=d)*t*((s+1)*t - s) + b;
1017
+ },
1018
+
1019
+ /**
1020
+ * Overshoots end, then reverses and comes back to end.
1021
+ * @method backOut
1022
+ * @param {Number} t Time value used to compute current value
1023
+ * @param {Number} b Starting value
1024
+ * @param {Number} c Delta between start and end values
1025
+ * @param {Number} d Total length of animation
1026
+ * @param {Number} s Overshoot (optional)
1027
+ * @return {Number} The computed value for the current animation frame
1028
+ */
1029
+ backOut: function (t, b, c, d, s) {
1030
+ if (typeof s == 'undefined') {
1031
+ s = 1.70158;
1032
+ }
1033
+ return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
1034
+ },
1035
+
1036
+ /**
1037
+ * Backtracks slightly, then reverses direction, overshoots end,
1038
+ * then reverses and comes back to end.
1039
+ * @method backBoth
1040
+ * @param {Number} t Time value used to compute current value
1041
+ * @param {Number} b Starting value
1042
+ * @param {Number} c Delta between start and end values
1043
+ * @param {Number} d Total length of animation
1044
+ * @param {Number} s Overshoot (optional)
1045
+ * @return {Number} The computed value for the current animation frame
1046
+ */
1047
+ backBoth: function (t, b, c, d, s) {
1048
+ if (typeof s == 'undefined') {
1049
+ s = 1.70158;
1050
+ }
1051
+
1052
+ if ((t /= d/2 ) < 1) {
1053
+ return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
1054
+ }
1055
+ return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
1056
+ },
1057
+
1058
+ /**
1059
+ * Bounce off of start.
1060
+ * @method bounceIn
1061
+ * @param {Number} t Time value used to compute current value
1062
+ * @param {Number} b Starting value
1063
+ * @param {Number} c Delta between start and end values
1064
+ * @param {Number} d Total length of animation
1065
+ * @return {Number} The computed value for the current animation frame
1066
+ */
1067
+ bounceIn: function (t, b, c, d) {
1068
+ return c - YAHOO.util.Easing.bounceOut(d-t, 0, c, d) + b;
1069
+ },
1070
+
1071
+ /**
1072
+ * Bounces off end.
1073
+ * @method bounceOut
1074
+ * @param {Number} t Time value used to compute current value
1075
+ * @param {Number} b Starting value
1076
+ * @param {Number} c Delta between start and end values
1077
+ * @param {Number} d Total length of animation
1078
+ * @return {Number} The computed value for the current animation frame
1079
+ */
1080
+ bounceOut: function (t, b, c, d) {
1081
+ if ((t/=d) < (1/2.75)) {
1082
+ return c*(7.5625*t*t) + b;
1083
+ } else if (t < (2/2.75)) {
1084
+ return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
1085
+ } else if (t < (2.5/2.75)) {
1086
+ return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
1087
+ }
1088
+ return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
1089
+ },
1090
+
1091
+ /**
1092
+ * Bounces off start and end.
1093
+ * @method bounceBoth
1094
+ * @param {Number} t Time value used to compute current value
1095
+ * @param {Number} b Starting value
1096
+ * @param {Number} c Delta between start and end values
1097
+ * @param {Number} d Total length of animation
1098
+ * @return {Number} The computed value for the current animation frame
1099
+ */
1100
+ bounceBoth: function (t, b, c, d) {
1101
+ if (t < d/2) {
1102
+ return YAHOO.util.Easing.bounceIn(t*2, 0, c, d) * .5 + b;
1103
+ }
1104
+ return YAHOO.util.Easing.bounceOut(t*2-d, 0, c, d) * .5 + c*.5 + b;
1105
+ }
1106
+ };
1107
+
1108
+ (function() {
1109
+ /**
1110
+ * Anim subclass for moving elements along a path defined by the "points"
1111
+ * member of "attributes". All "points" are arrays with x, y coordinates.
1112
+ * <p>Usage: <code>var myAnim = new YAHOO.util.Motion(el, { points: { to: [800, 800] } }, 1, YAHOO.util.Easing.easeOut);</code></p>
1113
+ * @class Motion
1114
+ * @namespace YAHOO.util
1115
+ * @requires YAHOO.util.Anim
1116
+ * @requires YAHOO.util.AnimMgr
1117
+ * @requires YAHOO.util.Easing
1118
+ * @requires YAHOO.util.Bezier
1119
+ * @requires YAHOO.util.Dom
1120
+ * @requires YAHOO.util.Event
1121
+ * @requires YAHOO.util.CustomEvent
1122
+ * @constructor
1123
+ * @extends YAHOO.util.Anim
1124
+ * @param {String | HTMLElement} el Reference to the element that will be animated
1125
+ * @param {Object} attributes The attribute(s) to be animated.
1126
+ * Each attribute is an object with at minimum a "to" or "by" member defined.
1127
+ * Additional optional members are "from" (defaults to current value), "units" (defaults to "px").
1128
+ * All attribute names use camelCase.
1129
+ * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
1130
+ * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method)
1131
+ */
1132
+ YAHOO.util.Motion = function(el, attributes, duration, method) {
1133
+ if (el) { // dont break existing subclasses not using YAHOO.extend
1134
+ YAHOO.util.Motion.superclass.constructor.call(this, el, attributes, duration, method);
1135
+ }
1136
+ };
1137
+
1138
+ YAHOO.extend(YAHOO.util.Motion, YAHOO.util.ColorAnim);
1139
+
1140
+ // shorthand
1141
+ var Y = YAHOO.util;
1142
+ var superclass = Y.Motion.superclass;
1143
+ var proto = Y.Motion.prototype;
1144
+
1145
+ proto.toString = function() {
1146
+ var el = this.getEl();
1147
+ var id = el.id || el.tagName;
1148
+ return ("Motion " + id);
1149
+ };
1150
+
1151
+ proto.patterns.points = /^points$/i;
1152
+
1153
+ proto.setAttribute = function(attr, val, unit) {
1154
+ if ( this.patterns.points.test(attr) ) {
1155
+ unit = unit || 'px';
1156
+ superclass.setAttribute.call(this, 'left', val[0], unit);
1157
+ superclass.setAttribute.call(this, 'top', val[1], unit);
1158
+ } else {
1159
+ superclass.setAttribute.call(this, attr, val, unit);
1160
+ }
1161
+ };
1162
+
1163
+ proto.getAttribute = function(attr) {
1164
+ if ( this.patterns.points.test(attr) ) {
1165
+ var val = [
1166
+ superclass.getAttribute.call(this, 'left'),
1167
+ superclass.getAttribute.call(this, 'top')
1168
+ ];
1169
+ } else {
1170
+ val = superclass.getAttribute.call(this, attr);
1171
+ }
1172
+
1173
+ return val;
1174
+ };
1175
+
1176
+ proto.doMethod = function(attr, start, end) {
1177
+ var val = null;
1178
+
1179
+ if ( this.patterns.points.test(attr) ) {
1180
+ var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
1181
+ val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
1182
+ } else {
1183
+ val = superclass.doMethod.call(this, attr, start, end);
1184
+ }
1185
+ return val;
1186
+ };
1187
+
1188
+ proto.setRuntimeAttribute = function(attr) {
1189
+ if ( this.patterns.points.test(attr) ) {
1190
+ var el = this.getEl();
1191
+ var attributes = this.attributes;
1192
+ var start;
1193
+ var control = attributes['points']['control'] || [];
1194
+ var end;
1195
+ var i, len;
1196
+
1197
+ if (control.length > 0 && !(control[0] instanceof Array) ) { // could be single point or array of points
1198
+ control = [control];
1199
+ } else { // break reference to attributes.points.control
1200
+ var tmp = [];
1201
+ for (i = 0, len = control.length; i< len; ++i) {
1202
+ tmp[i] = control[i];
1203
+ }
1204
+ control = tmp;
1205
+ }
1206
+
1207
+ if (Y.Dom.getStyle(el, 'position') == 'static') { // default to relative
1208
+ Y.Dom.setStyle(el, 'position', 'relative');
1209
+ }
1210
+
1211
+ if ( isset(attributes['points']['from']) ) {
1212
+ Y.Dom.setXY(el, attributes['points']['from']); // set position to from point
1213
+ }
1214
+ else { Y.Dom.setXY( el, Y.Dom.getXY(el) ); } // set it to current position
1215
+
1216
+ start = this.getAttribute('points'); // get actual top & left
1217
+
1218
+ // TO beats BY, per SMIL 2.1 spec
1219
+ if ( isset(attributes['points']['to']) ) {
1220
+ end = translateValues.call(this, attributes['points']['to'], start);
1221
+
1222
+ var pageXY = Y.Dom.getXY(this.getEl());
1223
+ for (i = 0, len = control.length; i < len; ++i) {
1224
+ control[i] = translateValues.call(this, control[i], start);
1225
+ }
1226
+
1227
+
1228
+ } else if ( isset(attributes['points']['by']) ) {
1229
+ end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
1230
+
1231
+ for (i = 0, len = control.length; i < len; ++i) {
1232
+ control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
1233
+ }
1234
+ }
1235
+
1236
+ this.runtimeAttributes[attr] = [start];
1237
+
1238
+ if (control.length > 0) {
1239
+ this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
1240
+ }
1241
+
1242
+ this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
1243
+ }
1244
+ else {
1245
+ superclass.setRuntimeAttribute.call(this, attr);
1246
+ }
1247
+ };
1248
+
1249
+ var translateValues = function(val, start) {
1250
+ var pageXY = Y.Dom.getXY(this.getEl());
1251
+ val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
1252
+
1253
+ return val;
1254
+ };
1255
+
1256
+ var isset = function(prop) {
1257
+ return (typeof prop !== 'undefined');
1258
+ };
1259
+ })();
1260
+ (function() {
1261
+ /**
1262
+ * Anim subclass for scrolling elements to a position defined by the "scroll"
1263
+ * member of "attributes". All "scroll" members are arrays with x, y scroll positions.
1264
+ * <p>Usage: <code>var myAnim = new YAHOO.util.Scroll(el, { scroll: { to: [0, 800] } }, 1, YAHOO.util.Easing.easeOut);</code></p>
1265
+ * @class Scroll
1266
+ * @namespace YAHOO.util
1267
+ * @requires YAHOO.util.Anim
1268
+ * @requires YAHOO.util.AnimMgr
1269
+ * @requires YAHOO.util.Easing
1270
+ * @requires YAHOO.util.Bezier
1271
+ * @requires YAHOO.util.Dom
1272
+ * @requires YAHOO.util.Event
1273
+ * @requires YAHOO.util.CustomEvent
1274
+ * @extends YAHOO.util.Anim
1275
+ * @constructor
1276
+ * @param {String or HTMLElement} el Reference to the element that will be animated
1277
+ * @param {Object} attributes The attribute(s) to be animated.
1278
+ * Each attribute is an object with at minimum a "to" or "by" member defined.
1279
+ * Additional optional members are "from" (defaults to current value), "units" (defaults to "px").
1280
+ * All attribute names use camelCase.
1281
+ * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
1282
+ * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method)
1283
+ */
1284
+ YAHOO.util.Scroll = function(el, attributes, duration, method) {
1285
+ if (el) { // dont break existing subclasses not using YAHOO.extend
1286
+ YAHOO.util.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
1287
+ }
1288
+ };
1289
+
1290
+ YAHOO.extend(YAHOO.util.Scroll, YAHOO.util.ColorAnim);
1291
+
1292
+ // shorthand
1293
+ var Y = YAHOO.util;
1294
+ var superclass = Y.Scroll.superclass;
1295
+ var proto = Y.Scroll.prototype;
1296
+
1297
+ proto.toString = function() {
1298
+ var el = this.getEl();
1299
+ var id = el.id || el.tagName;
1300
+ return ("Scroll " + id);
1301
+ };
1302
+
1303
+ proto.doMethod = function(attr, start, end) {
1304
+ var val = null;
1305
+
1306
+ if (attr == 'scroll') {
1307
+ val = [
1308
+ this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
1309
+ this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
1310
+ ];
1311
+
1312
+ } else {
1313
+ val = superclass.doMethod.call(this, attr, start, end);
1314
+ }
1315
+ return val;
1316
+ };
1317
+
1318
+ proto.getAttribute = function(attr) {
1319
+ var val = null;
1320
+ var el = this.getEl();
1321
+
1322
+ if (attr == 'scroll') {
1323
+ val = [ el.scrollLeft, el.scrollTop ];
1324
+ } else {
1325
+ val = superclass.getAttribute.call(this, attr);
1326
+ }
1327
+
1328
+ return val;
1329
+ };
1330
+
1331
+ proto.setAttribute = function(attr, val, unit) {
1332
+ var el = this.getEl();
1333
+
1334
+ if (attr == 'scroll') {
1335
+ el.scrollLeft = val[0];
1336
+ el.scrollTop = val[1];
1337
+ } else {
1338
+ superclass.setAttribute.call(this, attr, val, unit);
1339
+ }
1340
+ };
1341
+ })();