sproutcore 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) hide show
  1. data/History.txt +4 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +269 -0
  4. data/README.txt +67 -0
  5. data/Rakefile +4 -0
  6. data/app_generators/sproutcore/USAGE +5 -0
  7. data/app_generators/sproutcore/sproutcore_generator.rb +66 -0
  8. data/app_generators/sproutcore/templates/README +77 -0
  9. data/app_generators/sproutcore/templates/environment.yml +4 -0
  10. data/bin/sc-build +145 -0
  11. data/bin/sc-gen +24 -0
  12. data/bin/sc-server +63 -0
  13. data/bin/sproutcore +21 -0
  14. data/clients/sc_docs/controllers/docs.js +118 -0
  15. data/clients/sc_docs/core.js +19 -0
  16. data/clients/sc_docs/english.lproj/body.css +159 -0
  17. data/clients/sc_docs/english.lproj/body.rhtml +33 -0
  18. data/clients/sc_docs/english.lproj/controls.css +0 -0
  19. data/clients/sc_docs/english.lproj/icons/small/next.png +0 -0
  20. data/clients/sc_docs/english.lproj/icons/small/reset.png +0 -0
  21. data/clients/sc_docs/english.lproj/images/gradients.png +0 -0
  22. data/clients/sc_docs/english.lproj/images/indicator.gif +0 -0
  23. data/clients/sc_docs/english.lproj/images/toolbar.png +0 -0
  24. data/clients/sc_docs/english.lproj/no_docs.rhtml +7 -0
  25. data/clients/sc_docs/english.lproj/strings.js +14 -0
  26. data/clients/sc_docs/english.lproj/warning.rhtml +6 -0
  27. data/clients/sc_docs/fixtures/doc.js +11 -0
  28. data/clients/sc_docs/main.js +21 -0
  29. data/clients/sc_docs/models/doc.js +9 -0
  30. data/clients/sc_docs/tests/controllers/docs.rhtml +21 -0
  31. data/clients/sc_docs/tests/models/doc.rhtml +21 -0
  32. data/clients/sc_docs/tests/views/doc_frame.rhtml +21 -0
  33. data/clients/sc_docs/tests/views/doc_label_view.rhtml +21 -0
  34. data/clients/sc_docs/views/doc_frame.js +33 -0
  35. data/clients/sc_docs/views/doc_label.js +20 -0
  36. data/clients/sc_test_runner/controllers/runner.js +175 -0
  37. data/clients/sc_test_runner/core.js +19 -0
  38. data/clients/sc_test_runner/english.lproj/body.css +151 -0
  39. data/clients/sc_test_runner/english.lproj/body.rhtml +35 -0
  40. data/clients/sc_test_runner/english.lproj/controls.css +0 -0
  41. data/clients/sc_test_runner/english.lproj/icons/small/next.png +0 -0
  42. data/clients/sc_test_runner/english.lproj/icons/small/reset.png +0 -0
  43. data/clients/sc_test_runner/english.lproj/images/gradients.png +0 -0
  44. data/clients/sc_test_runner/english.lproj/images/indicator.gif +0 -0
  45. data/clients/sc_test_runner/english.lproj/images/toolbar.png +0 -0
  46. data/clients/sc_test_runner/english.lproj/no_tests.rhtml +6 -0
  47. data/clients/sc_test_runner/english.lproj/strings.js +14 -0
  48. data/clients/sc_test_runner/english.lproj/warning.rhtml +6 -0
  49. data/clients/sc_test_runner/fixtures/test.js +12 -0
  50. data/clients/sc_test_runner/main.js +26 -0
  51. data/clients/sc_test_runner/models/test.js +11 -0
  52. data/clients/sc_test_runner/views/runner_frame.js +72 -0
  53. data/clients/sc_test_runner/views/test_label.js +20 -0
  54. data/config/hoe.rb +70 -0
  55. data/config/requirements.rb +17 -0
  56. data/environment.yml +9 -0
  57. data/frameworks/prototype/prototype.js +4186 -0
  58. data/frameworks/sproutcore/Core.js +378 -0
  59. data/frameworks/sproutcore/README +3 -0
  60. data/frameworks/sproutcore/controllers/array.js +236 -0
  61. data/frameworks/sproutcore/controllers/collection.js +305 -0
  62. data/frameworks/sproutcore/controllers/controller.js +323 -0
  63. data/frameworks/sproutcore/controllers/object.js +372 -0
  64. data/frameworks/sproutcore/drag/drag.js +549 -0
  65. data/frameworks/sproutcore/drag/drag_data_source.js +32 -0
  66. data/frameworks/sproutcore/drag/drag_source.js +64 -0
  67. data/frameworks/sproutcore/drag/drop_target.js +153 -0
  68. data/frameworks/sproutcore/english.lproj/blank.gif +0 -0
  69. data/frameworks/sproutcore/english.lproj/buttons.css +589 -0
  70. data/frameworks/sproutcore/english.lproj/buttons.png +0 -0
  71. data/frameworks/sproutcore/english.lproj/inline_text_editor.css +21 -0
  72. data/frameworks/sproutcore/english.lproj/menu.css +121 -0
  73. data/frameworks/sproutcore/english.lproj/panels/background-fat.jpg +0 -0
  74. data/frameworks/sproutcore/english.lproj/panels/background-thin.jpg +0 -0
  75. data/frameworks/sproutcore/english.lproj/panels/bottom-edge.png +0 -0
  76. data/frameworks/sproutcore/english.lproj/panels/bottom-left-corner.png +0 -0
  77. data/frameworks/sproutcore/english.lproj/panels/bottom-right-corner.png +0 -0
  78. data/frameworks/sproutcore/english.lproj/panels/left-edge.png +0 -0
  79. data/frameworks/sproutcore/english.lproj/panels/overlay.png +0 -0
  80. data/frameworks/sproutcore/english.lproj/panels/right-edge.png +0 -0
  81. data/frameworks/sproutcore/english.lproj/panels/top-edge.png +0 -0
  82. data/frameworks/sproutcore/english.lproj/panels/top-left-corner.png +0 -0
  83. data/frameworks/sproutcore/english.lproj/panels/top-right-corner.png +0 -0
  84. data/frameworks/sproutcore/english.lproj/panes.css +155 -0
  85. data/frameworks/sproutcore/english.lproj/picker.css +22 -0
  86. data/frameworks/sproutcore/english.lproj/strings.js +15 -0
  87. data/frameworks/sproutcore/english.lproj/tab.css +23 -0
  88. data/frameworks/sproutcore/english.lproj/tests.css +67 -0
  89. data/frameworks/sproutcore/english.lproj/theme.css +77 -0
  90. data/frameworks/sproutcore/foundation/animator.js +670 -0
  91. data/frameworks/sproutcore/foundation/application.js +199 -0
  92. data/frameworks/sproutcore/foundation/array.js +348 -0
  93. data/frameworks/sproutcore/foundation/benchmark.js +211 -0
  94. data/frameworks/sproutcore/foundation/binding.js +384 -0
  95. data/frameworks/sproutcore/foundation/date.js +357 -0
  96. data/frameworks/sproutcore/foundation/error.js +39 -0
  97. data/frameworks/sproutcore/foundation/input_manager.js +153 -0
  98. data/frameworks/sproutcore/foundation/json.js +296 -0
  99. data/frameworks/sproutcore/foundation/mock.js +42 -0
  100. data/frameworks/sproutcore/foundation/node_descriptor.js +56 -0
  101. data/frameworks/sproutcore/foundation/object.js +777 -0
  102. data/frameworks/sproutcore/foundation/observable.js +451 -0
  103. data/frameworks/sproutcore/foundation/page.js +63 -0
  104. data/frameworks/sproutcore/foundation/path_module.js +413 -0
  105. data/frameworks/sproutcore/foundation/responder.js +310 -0
  106. data/frameworks/sproutcore/foundation/routes.js +371 -0
  107. data/frameworks/sproutcore/foundation/run_loop.js +21 -0
  108. data/frameworks/sproutcore/foundation/server.js +491 -0
  109. data/frameworks/sproutcore/foundation/set.js +96 -0
  110. data/frameworks/sproutcore/foundation/string.js +149 -0
  111. data/frameworks/sproutcore/foundation/undo_manager.js +186 -0
  112. data/frameworks/sproutcore/foundation/unittest.js +622 -0
  113. data/frameworks/sproutcore/foundation/utils.js +61 -0
  114. data/frameworks/sproutcore/globals/panels.js +182 -0
  115. data/frameworks/sproutcore/globals/popups.js +60 -0
  116. data/frameworks/sproutcore/globals/window.js +381 -0
  117. data/frameworks/sproutcore/lib/index.rhtml +66 -0
  118. data/frameworks/sproutcore/models/collection.js +395 -0
  119. data/frameworks/sproutcore/models/record.js +622 -0
  120. data/frameworks/sproutcore/models/store.js +295 -0
  121. data/frameworks/sproutcore/panes/dialog.js +16 -0
  122. data/frameworks/sproutcore/panes/manager.js +164 -0
  123. data/frameworks/sproutcore/panes/menu.js +45 -0
  124. data/frameworks/sproutcore/panes/overlay.js +231 -0
  125. data/frameworks/sproutcore/panes/pane.js +90 -0
  126. data/frameworks/sproutcore/panes/panel.js +19 -0
  127. data/frameworks/sproutcore/panes/picker.js +45 -0
  128. data/frameworks/sproutcore/tests/controllers/array.rhtml +86 -0
  129. data/frameworks/sproutcore/tests/controllers/controller.rhtml +273 -0
  130. data/frameworks/sproutcore/tests/controllers/object.rhtml +327 -0
  131. data/frameworks/sproutcore/tests/foundation/application.rhtml +125 -0
  132. data/frameworks/sproutcore/tests/foundation/array.rhtml +221 -0
  133. data/frameworks/sproutcore/tests/foundation/object.rhtml +69 -0
  134. data/frameworks/sproutcore/tests/globals/window.rhtml +45 -0
  135. data/frameworks/sproutcore/tests/panes/pane.rhtml +88 -0
  136. data/frameworks/sproutcore/tests/views/collection.rhtml +137 -0
  137. data/frameworks/sproutcore/tests/views/popup_button.rhtml +115 -0
  138. data/frameworks/sproutcore/tests/views/text_field.rhtml +37 -0
  139. data/frameworks/sproutcore/validators/credit_card.js +92 -0
  140. data/frameworks/sproutcore/validators/date.js +36 -0
  141. data/frameworks/sproutcore/validators/email.js +29 -0
  142. data/frameworks/sproutcore/validators/not_empty.js +24 -0
  143. data/frameworks/sproutcore/validators/number.js +55 -0
  144. data/frameworks/sproutcore/validators/password.js +78 -0
  145. data/frameworks/sproutcore/validators/validator.js +304 -0
  146. data/frameworks/sproutcore/views/button.js +425 -0
  147. data/frameworks/sproutcore/views/checkbox_field.js +30 -0
  148. data/frameworks/sproutcore/views/collection.js +1521 -0
  149. data/frameworks/sproutcore/views/container.js +62 -0
  150. data/frameworks/sproutcore/views/error_explanation.js +45 -0
  151. data/frameworks/sproutcore/views/field.js +214 -0
  152. data/frameworks/sproutcore/views/filter_button.js +29 -0
  153. data/frameworks/sproutcore/views/form.js +591 -0
  154. data/frameworks/sproutcore/views/image.js +141 -0
  155. data/frameworks/sproutcore/views/inline_text_editor.js +96 -0
  156. data/frameworks/sproutcore/views/label.js +176 -0
  157. data/frameworks/sproutcore/views/menu_item.js +90 -0
  158. data/frameworks/sproutcore/views/pagination.js +54 -0
  159. data/frameworks/sproutcore/views/popup_button.js +86 -0
  160. data/frameworks/sproutcore/views/popup_menu.js +137 -0
  161. data/frameworks/sproutcore/views/progress.js +100 -0
  162. data/frameworks/sproutcore/views/radio_field.js +107 -0
  163. data/frameworks/sproutcore/views/radio_group.js +48 -0
  164. data/frameworks/sproutcore/views/segmented.js +80 -0
  165. data/frameworks/sproutcore/views/select_field.js +272 -0
  166. data/frameworks/sproutcore/views/spinner.js +11 -0
  167. data/frameworks/sproutcore/views/tab.js +126 -0
  168. data/frameworks/sproutcore/views/text_field.js +179 -0
  169. data/frameworks/sproutcore/views/textarea_field.js +14 -0
  170. data/frameworks/sproutcore/views/toolbar.js +29 -0
  171. data/frameworks/sproutcore/views/view.js +1389 -0
  172. data/frameworks/sproutcore/views/workspace.js +170 -0
  173. data/generators/client/README +3 -0
  174. data/generators/client/USAGE +12 -0
  175. data/generators/client/client_generator.rb +53 -0
  176. data/generators/client/templates/core.js +19 -0
  177. data/generators/client/templates/english.lproj/body.css +0 -0
  178. data/generators/client/templates/english.lproj/body.rhtml +3 -0
  179. data/generators/client/templates/english.lproj/controls.css +0 -0
  180. data/generators/client/templates/english.lproj/strings.js +14 -0
  181. data/generators/client/templates/main.js +37 -0
  182. data/generators/controller/USAGE +16 -0
  183. data/generators/controller/controller_generator.rb +51 -0
  184. data/generators/controller/templates/controller.js +21 -0
  185. data/generators/controller/templates/test.rhtml +21 -0
  186. data/generators/framework/README +7 -0
  187. data/generators/framework/USAGE +12 -0
  188. data/generators/framework/framework_generator.rb +53 -0
  189. data/generators/framework/templates/core.js +20 -0
  190. data/generators/framework/templates/english.lproj/body.css +0 -0
  191. data/generators/framework/templates/english.lproj/body.rhtml +3 -0
  192. data/generators/framework/templates/english.lproj/controls.css +0 -0
  193. data/generators/framework/templates/english.lproj/strings.js +14 -0
  194. data/generators/language/USAGE +16 -0
  195. data/generators/language/language_generator.rb +47 -0
  196. data/generators/language/templates/strings.js +10 -0
  197. data/generators/model/USAGE +24 -0
  198. data/generators/model/model_generator.rb +55 -0
  199. data/generators/model/templates/fixture.js +11 -0
  200. data/generators/model/templates/model.js +20 -0
  201. data/generators/model/templates/test.rhtml +21 -0
  202. data/generators/test/USAGE +16 -0
  203. data/generators/test/templates/test.rhtml +21 -0
  204. data/generators/test/test_generator.rb +47 -0
  205. data/generators/view/USAGE +16 -0
  206. data/generators/view/templates/test.rhtml +21 -0
  207. data/generators/view/templates/view.js +20 -0
  208. data/generators/view/view_generator.rb +51 -0
  209. data/jsdoc/README.txt +119 -0
  210. data/jsdoc/app/DocFile.js +137 -0
  211. data/jsdoc/app/DocTag.js +110 -0
  212. data/jsdoc/app/Doclet.js +63 -0
  213. data/jsdoc/app/Dumper.js +143 -0
  214. data/jsdoc/app/JsDoc.js +103 -0
  215. data/jsdoc/app/JsHilite.js +45 -0
  216. data/jsdoc/app/JsIO.js +163 -0
  217. data/jsdoc/app/JsParse.js +385 -0
  218. data/jsdoc/app/JsPlate.js +130 -0
  219. data/jsdoc/app/JsTestrun.js +129 -0
  220. data/jsdoc/app/JsToke.js +564 -0
  221. data/jsdoc/app/Symbol.js +298 -0
  222. data/jsdoc/app/Transformer.js +14 -0
  223. data/jsdoc/app/Util.js +97 -0
  224. data/jsdoc/app/js.jar +0 -0
  225. data/jsdoc/app/run.js +144 -0
  226. data/jsdoc/plugins/min.js +316 -0
  227. data/jsdoc/plugins/strip.js +20 -0
  228. data/jsdoc/templates/sproutcore/class.tmpl +438 -0
  229. data/jsdoc/templates/sproutcore/default.css +241 -0
  230. data/jsdoc/templates/sproutcore/index.html +13 -0
  231. data/jsdoc/templates/sproutcore/index.tmpl +21 -0
  232. data/jsdoc/templates/sproutcore/prototype.js +4186 -0
  233. data/jsdoc/templates/sproutcore/publish.js +236 -0
  234. data/jsdoc/templates/sproutcore/splash.html +7 -0
  235. data/lib/sproutcore/build_tools/html_builder.rb +88 -0
  236. data/lib/sproutcore/build_tools/resource_builder.rb +194 -0
  237. data/lib/sproutcore/build_tools.rb +44 -0
  238. data/lib/sproutcore/bundle.rb +517 -0
  239. data/lib/sproutcore/bundle_manifest.rb +397 -0
  240. data/lib/sproutcore/generator_helper.rb +170 -0
  241. data/lib/sproutcore/helpers/capture_helper.rb +42 -0
  242. data/lib/sproutcore/helpers/static_helper.rb +80 -0
  243. data/lib/sproutcore/helpers/tag_helper.rb +110 -0
  244. data/lib/sproutcore/helpers/text_helper.rb +336 -0
  245. data/lib/sproutcore/helpers.rb +3 -0
  246. data/lib/sproutcore/jsdoc.rb +40 -0
  247. data/lib/sproutcore/jsmin.rb +247 -0
  248. data/lib/sproutcore/library.rb +258 -0
  249. data/lib/sproutcore/merb/bundle_controller.rb +179 -0
  250. data/lib/sproutcore/merb/router.rb +43 -0
  251. data/lib/sproutcore/merb.rb +27 -0
  252. data/lib/sproutcore/version.rb +9 -0
  253. data/lib/sproutcore/view_helpers/button_views.rb +302 -0
  254. data/lib/sproutcore/view_helpers/core_views.rb +284 -0
  255. data/lib/sproutcore/view_helpers/form_views.rb +258 -0
  256. data/lib/sproutcore/view_helpers/menu_views.rb +94 -0
  257. data/lib/sproutcore/view_helpers.rb +628 -0
  258. data/lib/sproutcore.rb +30 -0
  259. data/script/destroy +14 -0
  260. data/script/generate +14 -0
  261. data/script/txt2html +74 -0
  262. data/setup.rb +1585 -0
  263. data/spec/spec.opts +1 -0
  264. data/spec/spec_helper.rb +7 -0
  265. data/spec/sproutcore_spec.rb +11 -0
  266. data/tasks/deployment.rake +34 -0
  267. data/tasks/environment.rake +7 -0
  268. data/tasks/rspec.rake +21 -0
  269. data/tasks/website.rake +17 -0
  270. metadata +365 -0
@@ -0,0 +1,670 @@
1
+ /*
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
+
34
+ // Applies a sequence of numbers between 0 and 1 to a number of subjects
35
+ // construct - see setOptions for parameters
36
+ function Animator(options) {
37
+ this.setOptions(options);
38
+ var _this = this;
39
+ this.timerDelegate = function(){_this.onTimerEvent()};
40
+ this.subjects = [];
41
+ this.target = 0;
42
+ this.state = 0;
43
+ this.lastTime = null;
44
+ };
45
+ Animator.prototype = {
46
+ // apply defaults
47
+ setOptions: function(options) {
48
+ this.options = Animator.applyDefaults({
49
+ interval: 20, // time between animation frames
50
+ duration: 400, // length of animation
51
+ onComplete: function(){},
52
+ onStep: function(){},
53
+ transition: Animator.tx.easeInOut
54
+ }, options);
55
+ },
56
+ // animate from the current state to provided value
57
+ seekTo: function(to) {
58
+ this.seekFromTo(this.state, to);
59
+ },
60
+ // animate from the current state to provided value
61
+ seekFromTo: function(from, to) {
62
+ this.target = Math.max(0, Math.min(1, to));
63
+ this.state = Math.max(0, Math.min(1, from));
64
+ this.lastTime = new Date().getTime();
65
+ if (!this.intervalId) {
66
+ this.intervalId = window.setInterval(this.timerDelegate, this.options.interval);
67
+ }
68
+ },
69
+ // animate from the current state to provided value
70
+ jumpTo: function(to) {
71
+ this.target = this.state = Math.max(0, Math.min(1, to));
72
+ this.propagate();
73
+ },
74
+ // seek to the opposite of the current target
75
+ toggle: function() {
76
+ this.seekTo(1 - this.target);
77
+ },
78
+ // add a function or an object with a method setState(state) that will be called with a number
79
+ // between 0 and 1 on each frame of the animation
80
+ addSubject: function(subject) {
81
+ this.subjects[this.subjects.length] = subject;
82
+ return this;
83
+ },
84
+ // remove all subjects
85
+ clearSubjects: function() {
86
+ this.subjects = [];
87
+ },
88
+ // forward the current state to the animation subjects
89
+ propagate: function() {
90
+ var value = this.options.transition(this.state);
91
+ for (var i=0; i<this.subjects.length; i++) {
92
+ if (this.subjects[i].setState) {
93
+ this.subjects[i].setState(value);
94
+ } else {
95
+ this.subjects[i](value);
96
+ }
97
+ }
98
+ },
99
+ // called once per frame to update the current state
100
+ onTimerEvent: function() {
101
+ var now = new Date().getTime();
102
+ var timePassed = now - this.lastTime;
103
+ this.lastTime = now;
104
+ var movement = (timePassed / this.options.duration) * (this.state < this.target ? 1 : -1);
105
+ if (Math.abs(movement) >= Math.abs(this.state - this.target)) {
106
+ this.state = this.target;
107
+ } else {
108
+ this.state += movement;
109
+ }
110
+
111
+ try {
112
+ this.propagate();
113
+ } finally {
114
+ this.options.onStep.call(this);
115
+ if (this.target == this.state) {
116
+ window.clearInterval(this.intervalId);
117
+ this.intervalId = null;
118
+ this.options.onComplete.call(this);
119
+ }
120
+ }
121
+ },
122
+ // shortcuts
123
+ play: function() {this.seekFromTo(0, 1)},
124
+ reverse: function() {this.seekFromTo(1, 0)},
125
+ // return a string describing this Animator, for debugging
126
+ inspect: function() {
127
+ var str = "#<Animator:\n";
128
+ for (var i=0; i<this.subjects.length; i++) {
129
+ str += this.subjects[i].inspect();
130
+ }
131
+ str += ">";
132
+ return str;
133
+ }
134
+ }
135
+ // merge the properties of two objects
136
+ Animator.applyDefaults = function(defaults, prefs) {
137
+ prefs = prefs || {};
138
+ var prop, result = {};
139
+ for (prop in defaults) result[prop] = prefs[prop] !== undefined ? prefs[prop] : defaults[prop];
140
+ return result;
141
+ }
142
+ // make an array from any object
143
+ Animator.makeArray = function(o) {
144
+ if (o == null) return [];
145
+ if (!o.length) return [o];
146
+ var result = [];
147
+ for (var i=0; i<o.length; i++) result[i] = o[i];
148
+ return result;
149
+ }
150
+ // convert a dash-delimited-property to a camelCaseProperty (c/o Prototype, thanks Sam!)
151
+ Animator.camelize = function(string) {
152
+ var oStringList = string.split('-');
153
+ if (oStringList.length == 1) return oStringList[0];
154
+
155
+ var camelizedString = string.indexOf('-') == 0
156
+ ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
157
+ : oStringList[0];
158
+
159
+ for (var i = 1, len = oStringList.length; i < len; i++) {
160
+ var s = oStringList[i];
161
+ camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
162
+ }
163
+ return camelizedString;
164
+ }
165
+ // syntactic sugar for creating CSSStyleSubjects
166
+ Animator.apply = function(el, style, options) {
167
+ if (style instanceof Array) {
168
+ return new Animator(options).addSubject(new CSSStyleSubject(el, style[0], style[1]));
169
+ }
170
+ return new Animator(options).addSubject(new CSSStyleSubject(el, style));
171
+ }
172
+ // make a transition function that gradually accelerates. pass a=1 for smooth
173
+ // gravitational acceleration, higher values for an exaggerated effect
174
+ Animator.makeEaseIn = function(a) {
175
+ return function(state) {
176
+ return Math.pow(state, a*2);
177
+ }
178
+ }
179
+ // as makeEaseIn but for deceleration
180
+ Animator.makeEaseOut = function(a) {
181
+ return function(state) {
182
+ return 1 - Math.pow(1 - state, a*2);
183
+ }
184
+ }
185
+ // make a transition function that, like an object with momentum being attracted to a point,
186
+ // goes past the target then returns
187
+ Animator.makeElastic = function(bounces) {
188
+ return function(state) {
189
+ state = Animator.tx.easeInOut(state);
190
+ return ((1-Math.cos(state * Math.PI * bounces)) * (1 - state)) + state;
191
+ }
192
+ }
193
+ // make an Attack Decay Sustain Release envelope that starts and finishes on the same level
194
+ //
195
+ Animator.makeADSR = function(attackEnd, decayEnd, sustainEnd, sustainLevel) {
196
+ if (sustainLevel == null) sustainLevel = 0.5;
197
+ return function(state) {
198
+ if (state < attackEnd) {
199
+ return state / attackEnd;
200
+ }
201
+ if (state < decayEnd) {
202
+ return 1 - ((state - attackEnd) / (decayEnd - attackEnd) * (1 - sustainLevel));
203
+ }
204
+ if (state < sustainEnd) {
205
+ return sustainLevel;
206
+ }
207
+ return sustainLevel * (1 - ((state - sustainEnd) / (1 - sustainEnd)));
208
+ }
209
+ }
210
+ // make a transition function that, like a ball falling to floor, reaches the target and/
211
+ // bounces back again
212
+ Animator.makeBounce = function(bounces) {
213
+ var fn = Animator.makeElastic(bounces);
214
+ return function(state) {
215
+ state = fn(state);
216
+ return state <= 1 ? state : 2-state;
217
+ }
218
+ }
219
+
220
+ // pre-made transition functions to use with the 'transition' option
221
+ Animator.tx = {
222
+ easeInOut: function(pos){
223
+ return ((-Math.cos(pos*Math.PI)/2) + 0.5);
224
+ },
225
+ linear: function(x) {
226
+ return x;
227
+ },
228
+ easeIn: Animator.makeEaseIn(1.5),
229
+ easeOut: Animator.makeEaseOut(1.5),
230
+ strongEaseIn: Animator.makeEaseIn(2.5),
231
+ strongEaseOut: Animator.makeEaseOut(2.5),
232
+ elastic: Animator.makeElastic(1),
233
+ veryElastic: Animator.makeElastic(3),
234
+ bouncy: Animator.makeBounce(1),
235
+ veryBouncy: Animator.makeBounce(3)
236
+ }
237
+
238
+ // animates a pixel-based style property between two integer values
239
+ function NumericalStyleSubject(els, property, from, to, units) {
240
+ this.els = Animator.makeArray(els);
241
+ if (property == 'opacity' && window.ActiveXObject) {
242
+ this.property = 'filter';
243
+ } else {
244
+ this.property = Animator.camelize(property);
245
+ }
246
+ this.from = parseFloat(from);
247
+ this.to = parseFloat(to);
248
+ this.units = units != null ? units : 'px';
249
+ }
250
+ NumericalStyleSubject.prototype = {
251
+ setState: function(state) {
252
+ var style = this.getStyle(state);
253
+ var visibility = (this.property == 'opacity' && state == 0) ? 'hidden' : '';
254
+ var j=0;
255
+ for (var i=0; i<this.els.length; i++) {
256
+ try {
257
+ this.els[i].style[this.property] = style;
258
+ } catch (e) {
259
+ // ignore fontWeight - intermediate numerical values cause exeptions in firefox
260
+ if (this.property != 'fontWeight') throw e;
261
+ }
262
+ if (j++ > 20) return;
263
+ }
264
+ },
265
+ getStyle: function(state) {
266
+ state = this.from + ((this.to - this.from) * state);
267
+ if (this.property == 'filter') return "alpha(opacity=" + Math.round(state*100) + ")";
268
+ if (this.property == 'opacity') return state;
269
+ return Math.round(state) + this.units;
270
+ },
271
+ inspect: function() {
272
+ return "\t" + this.property + "(" + this.from + this.units + " to " + this.to + this.units + ")\n";
273
+ }
274
+ }
275
+
276
+ // animates a colour based style property between two hex values
277
+ function ColorStyleSubject(els, property, from, to) {
278
+ this.els = Animator.makeArray(els);
279
+ this.property = Animator.camelize(property);
280
+ this.to = this.expandColor(to);
281
+ this.from = this.expandColor(from);
282
+ this.origFrom = from;
283
+ this.origTo = to;
284
+ }
285
+
286
+ ColorStyleSubject.prototype = {
287
+ // parse "#FFFF00" to [256, 256, 0]
288
+ expandColor: function(color) {
289
+ var hexColor, red, green, blue;
290
+ hexColor = ColorStyleSubject.parseColor(color);
291
+ if (hexColor) {
292
+ red = parseInt(hexColor.slice(1, 3), 16);
293
+ green = parseInt(hexColor.slice(3, 5), 16);
294
+ blue = parseInt(hexColor.slice(5, 7), 16);
295
+ return [red,green,blue]
296
+ }
297
+ if (window.DEBUG) {
298
+ alert("Invalid colour: '" + color + "'");
299
+ }
300
+ },
301
+ getValueForState: function(color, state) {
302
+ return Math.round(this.from[color] + ((this.to[color] - this.from[color]) * state));
303
+ },
304
+ setState: function(state) {
305
+ var color = '#'
306
+ + ColorStyleSubject.toColorPart(this.getValueForState(0, state))
307
+ + ColorStyleSubject.toColorPart(this.getValueForState(1, state))
308
+ + ColorStyleSubject.toColorPart(this.getValueForState(2, state));
309
+ for (var i=0; i<this.els.length; i++) {
310
+ this.els[i].style[this.property] = color;
311
+ }
312
+ },
313
+ inspect: function() {
314
+ return "\t" + this.property + "(" + this.origFrom + " to " + this.origTo + ")\n";
315
+ }
316
+ }
317
+
318
+ // return a properly formatted 6-digit hex colour spec, or false
319
+ ColorStyleSubject.parseColor = function(string) {
320
+ var color = '#', match;
321
+ if(match = ColorStyleSubject.parseColor.rgbRe.exec(string)) {
322
+ var part;
323
+ for (var i=1; i<=3; i++) {
324
+ part = Math.max(0, Math.min(255, parseInt(match[i])));
325
+ color += ColorStyleSubject.toColorPart(part);
326
+ }
327
+ return color;
328
+ }
329
+ if (match = ColorStyleSubject.parseColor.hexRe.exec(string)) {
330
+ if(match[1].length == 3) {
331
+ for (var i=0; i<3; i++) {
332
+ color += match[1].charAt(i) + match[1].charAt(i);
333
+ }
334
+ return color;
335
+ }
336
+ return '#' + match[1];
337
+ }
338
+ return false;
339
+ }
340
+ // convert a number to a 2 digit hex string
341
+ ColorStyleSubject.toColorPart = function(number) {
342
+ if (number > 255) number = 255;
343
+ var digits = number.toString(16);
344
+ if (number < 16) return '0' + digits;
345
+ return digits;
346
+ }
347
+ ColorStyleSubject.parseColor.rgbRe = /^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i;
348
+ ColorStyleSubject.parseColor.hexRe = /^\#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
349
+
350
+ // Animates discrete styles, i.e. ones that do not scale but have discrete values
351
+ // that can't be interpolated
352
+ function DiscreteStyleSubject(els, property, from, to, threshold) {
353
+ this.els = Animator.makeArray(els);
354
+ this.property = Animator.camelize(property);
355
+ this.from = from;
356
+ this.to = to;
357
+ this.threshold = threshold || 0.5;
358
+ }
359
+
360
+ DiscreteStyleSubject.prototype = {
361
+ setState: function(state) {
362
+ var j=0;
363
+ for (var i=0; i<this.els.length; i++) {
364
+ this.els[i].style[this.property] = state <= this.threshold ? this.from : this.to;
365
+ }
366
+ },
367
+ inspect: function() {
368
+ return "\t" + this.property + "(" + this.from + " to " + this.to + " @ " + this.threshold + ")\n";
369
+ }
370
+ }
371
+
372
+ // animates between two styles defined using CSS.
373
+ // if style1 and style2 are present, animate between them, if only style1
374
+ // is present, animate between the element's current style and style1
375
+ function CSSStyleSubject(els, style1, style2) {
376
+ els = Animator.makeArray(els);
377
+ this.subjects = [];
378
+ if (els.length == 0) return;
379
+ var prop, toStyle, fromStyle;
380
+ if (style2) {
381
+ fromStyle = this.parseStyle(style1, els[0]);
382
+ toStyle = this.parseStyle(style2, els[0]);
383
+ } else {
384
+ toStyle = this.parseStyle(style1, els[0]);
385
+ fromStyle = {};
386
+ for (prop in toStyle) {
387
+ fromStyle[prop] = CSSStyleSubject.getStyle(els[0], prop);
388
+ }
389
+ }
390
+ // remove unchanging properties
391
+ var prop;
392
+ for (prop in fromStyle) {
393
+ if (fromStyle[prop] == toStyle[prop]) {
394
+ delete fromStyle[prop];
395
+ delete toStyle[prop];
396
+ }
397
+ }
398
+ // discover the type (numerical or colour) of each style
399
+ var prop, units, match, type, from, to;
400
+ for (prop in fromStyle) {
401
+ var fromProp = String(fromStyle[prop]);
402
+ var toProp = String(toStyle[prop]);
403
+ if (toStyle[prop] == null) {
404
+ if (window.DEBUG) alert("No to style provided for '" + prop + '"');
405
+ continue;
406
+ }
407
+
408
+ if (from = ColorStyleSubject.parseColor(fromProp)) {
409
+ to = ColorStyleSubject.parseColor(toProp);
410
+ type = ColorStyleSubject;
411
+ } else if (fromProp.match(CSSStyleSubject.numericalRe)
412
+ && toProp.match(CSSStyleSubject.numericalRe)) {
413
+ from = parseFloat(fromProp);
414
+ to = parseFloat(toProp);
415
+ type = NumericalStyleSubject;
416
+ match = CSSStyleSubject.numericalRe.exec(fromProp);
417
+ var reResult = CSSStyleSubject.numericalRe.exec(toProp);
418
+ if (match[1] != null) {
419
+ units = match[1];
420
+ } else if (reResult[1] != null) {
421
+ units = reResult[1];
422
+ } else {
423
+ units = reResult;
424
+ }
425
+ } else if (fromProp.match(CSSStyleSubject.discreteRe)
426
+ && toProp.match(CSSStyleSubject.discreteRe)) {
427
+ from = fromProp;
428
+ to = toProp;
429
+ type = DiscreteStyleSubject;
430
+ units = 0; // hack - how to get an animator option down to here
431
+ } else {
432
+ if (window.DEBUG) {
433
+ alert("Unrecognised format for value of "
434
+ + prop + ": '" + fromStyle[prop] + "'");
435
+ }
436
+ continue;
437
+ }
438
+ this.subjects[this.subjects.length] = new type(els, prop, from, to, units);
439
+ }
440
+ }
441
+
442
+ CSSStyleSubject.prototype = {
443
+ // parses "width: 400px; color: #FFBB2E" to {width: "400px", color: "#FFBB2E"}
444
+ parseStyle: function(style, el) {
445
+ var rtn = {};
446
+ // if style is a rule set
447
+ if (style.indexOf(":") != -1) {
448
+ var styles = style.split(";");
449
+ for (var i=0; i<styles.length; i++) {
450
+ var parts = CSSStyleSubject.ruleRe.exec(styles[i]);
451
+ if (parts) {
452
+ rtn[parts[1]] = parts[2];
453
+ }
454
+ }
455
+ }
456
+ // else assume style is a class name
457
+ else {
458
+ var prop, value, oldClass;
459
+ oldClass = el.className;
460
+ el.className = style;
461
+ for (var i=0; i<CSSStyleSubject.cssProperties.length; i++) {
462
+ prop = CSSStyleSubject.cssProperties[i];
463
+ value = CSSStyleSubject.getStyle(el, prop);
464
+ if (value != null) {
465
+ rtn[prop] = value;
466
+ }
467
+ }
468
+ el.className = oldClass;
469
+ }
470
+ return rtn;
471
+
472
+ },
473
+ setState: function(state) {
474
+ for (var i=0; i<this.subjects.length; i++) {
475
+ this.subjects[i].setState(state);
476
+ }
477
+ },
478
+ inspect: function() {
479
+ var str = "";
480
+ for (var i=0; i<this.subjects.length; i++) {
481
+ str += this.subjects[i].inspect();
482
+ }
483
+ return str;
484
+ }
485
+ }
486
+ // get the current value of a css property,
487
+ CSSStyleSubject.getStyle = function(el, property){
488
+ var style;
489
+ if(document.defaultView && document.defaultView.getComputedStyle){
490
+ style = document.defaultView.getComputedStyle(el, "").getPropertyValue(property);
491
+ if (style) {
492
+ return style;
493
+ }
494
+ }
495
+ property = Animator.camelize(property);
496
+ if(el.currentStyle){
497
+ style = el.currentStyle[property];
498
+ }
499
+ return style || el.style[property]
500
+ }
501
+
502
+
503
+ CSSStyleSubject.ruleRe = /^\s*([a-zA-Z\-]+)\s*:\s*(\S(.+\S)?)\s*$/;
504
+ CSSStyleSubject.numericalRe = /^-?\d+(?:\.\d+)?(%|[a-zA-Z]{2})?$/;
505
+ CSSStyleSubject.discreteRe = /^\w+$/;
506
+
507
+ // required because the style object of elements isn't enumerable in Safari
508
+ /*
509
+ CSSStyleSubject.cssProperties = ['background-color','border','border-color','border-spacing',
510
+ 'border-style','border-top','border-right','border-bottom','border-left','border-top-color',
511
+ 'border-right-color','border-bottom-color','border-left-color','border-top-width','border-right-width',
512
+ 'border-bottom-width','border-left-width','border-width','bottom','color','font-size','font-size-adjust',
513
+ 'font-stretch','font-style','height','left','letter-spacing','line-height','margin','margin-top',
514
+ 'margin-right','margin-bottom','margin-left','marker-offset','max-height','max-width','min-height',
515
+ 'min-width','orphans','outline','outline-color','outline-style','outline-width','overflow','padding',
516
+ 'padding-top','padding-right','padding-bottom','padding-left','quotes','right','size','text-indent',
517
+ 'top','width','word-spacing','z-index','opacity','outline-offset'];*/
518
+
519
+
520
+ 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'];
521
+
522
+
523
+ // chains several Animator objects together
524
+ function AnimatorChain(animators, options) {
525
+ this.animators = animators;
526
+ this.setOptions(options);
527
+ for (var i=0; i<this.animators.length; i++) {
528
+ this.listenTo(this.animators[i]);
529
+ }
530
+ this.forwards = false;
531
+ this.current = 0;
532
+ }
533
+
534
+ AnimatorChain.prototype = {
535
+ // apply defaults
536
+ setOptions: function(options) {
537
+ this.options = Animator.applyDefaults({
538
+ // by default, each call to AnimatorChain.play() calls jumpTo(0) of each animator
539
+ // before playing, which can cause flickering if you have multiple animators all
540
+ // targeting the same element. Set this to false to avoid this.
541
+ resetOnPlay: true
542
+ }, options);
543
+ },
544
+ // play each animator in turn
545
+ play: function() {
546
+ this.forwards = true;
547
+ this.current = -1;
548
+ if (this.options.resetOnPlay) {
549
+ for (var i=0; i<this.animators.length; i++) {
550
+ this.animators[i].jumpTo(0);
551
+ }
552
+ }
553
+ this.advance();
554
+ },
555
+ // play all animators backwards
556
+ reverse: function() {
557
+ this.forwards = false;
558
+ this.current = this.animators.length;
559
+ if (this.options.resetOnPlay) {
560
+ for (var i=0; i<this.animators.length; i++) {
561
+ this.animators[i].jumpTo(1);
562
+ }
563
+ }
564
+ this.advance();
565
+ },
566
+ // if we have just play()'d, then call reverse(), and vice versa
567
+ toggle: function() {
568
+ if (this.forwards) {
569
+ this.seekTo(0);
570
+ } else {
571
+ this.seekTo(1);
572
+ }
573
+ },
574
+ // internal: install an event listener on an animator's onComplete option
575
+ // to trigger the next animator
576
+ listenTo: function(animator) {
577
+ var oldOnComplete = animator.options.onComplete;
578
+ var _this = this;
579
+ animator.options.onComplete = function() {
580
+ if (oldOnComplete) oldOnComplete.call(animator);
581
+ _this.advance();
582
+ }
583
+ },
584
+ // play the next animator
585
+ advance: function() {
586
+ if (this.forwards) {
587
+ if (this.animators[this.current + 1] == null) return;
588
+ this.current++;
589
+ this.animators[this.current].play();
590
+ } else {
591
+ if (this.animators[this.current - 1] == null) return;
592
+ this.current--;
593
+ this.animators[this.current].reverse();
594
+ }
595
+ },
596
+ // this function is provided for drop-in compatibility with Animator objects,
597
+ // but only accepts 0 and 1 as target values
598
+ seekTo: function(target) {
599
+ if (target <= 0) {
600
+ this.forwards = false;
601
+ this.animators[this.current].seekTo(0);
602
+ } else {
603
+ this.forwards = true;
604
+ this.animators[this.current].seekTo(1);
605
+ }
606
+ }
607
+ }
608
+
609
+ // an Accordion is a class that creates and controls a number of Animators. An array of elements is passed in,
610
+ // and for each element an Animator and a activator button is created. When an Animator's activator button is
611
+ // clicked, the Animator and all before it seek to 0, and all Animators after it seek to 1. This can be used to
612
+ // create the classic Accordion effect, hence the name.
613
+ // see setOptions for arguments
614
+ function Accordion(options) {
615
+ this.setOptions(options);
616
+ var selected = this.options.initialSection, current;
617
+ if (this.options.rememberance) {
618
+ current = document.location.hash.substring(1);
619
+ }
620
+ this.rememberanceTexts = [];
621
+ this.ans = [];
622
+ var _this = this;
623
+ for (var i=0; i<this.options.sections.length; i++) {
624
+ var el = this.options.sections[i];
625
+ var an = new Animator(this.options.animatorOptions);
626
+ var from = this.options.from + (this.options.shift * i);
627
+ var to = this.options.to + (this.options.shift * i);
628
+ an.addSubject(new NumericalStyleSubject(el, this.options.property, from, to, this.options.units));
629
+ an.jumpTo(0);
630
+ var activator = this.options.getActivator(el);
631
+ activator.index = i;
632
+ activator.onclick = function(){_this.show(this.index)};
633
+ this.ans[this.ans.length] = an;
634
+ this.rememberanceTexts[i] = activator.innerHTML.replace(/\s/g, "");
635
+ if (this.rememberanceTexts[i] === current) {
636
+ selected = i;
637
+ }
638
+ }
639
+ this.show(selected);
640
+ }
641
+
642
+ Accordion.prototype = {
643
+ // apply defaults
644
+ setOptions: function(options) {
645
+ this.options = Object.extend({
646
+ // REQUIRED: an array of elements to use as the accordion sections
647
+ sections: null,
648
+ // a function that locates an activator button element given a section element.
649
+ // by default it takes a button id from the section's "activator" attibute
650
+ getActivator: function(el) {return document.getElementById(el.getAttribute("activator"))},
651
+ // shifts each animator's range, for example with options {from:0,to:100,shift:20}
652
+ // the animators' ranges will be 0-100, 20-120, 40-140 etc.
653
+ shift: 0,
654
+ // the first page to show
655
+ initialSection: 0,
656
+ // if set to true, document.location.hash will be used to preserve the open section across page reloads
657
+ rememberance: true,
658
+ // constructor arguments to the Animator objects
659
+ animatorOptions: {}
660
+ }, options || {});
661
+ },
662
+ show: function(section) {
663
+ for (var i=0; i<this.ans.length; i++) {
664
+ this.ans[i].seekTo(i > section ? 1 : 0);
665
+ }
666
+ if (this.options.rememberance) {
667
+ document.location.hash = this.rememberanceTexts[section];
668
+ }
669
+ }
670
+ }