sproutcore 0.9.1 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (208) hide show
  1. data/History.txt +233 -0
  2. data/Manifest.txt +67 -34
  3. data/bin/sc-build +12 -1
  4. data/bin/sc-gen +1 -1
  5. data/bin/sproutcore +14 -0
  6. data/clients/sc_docs/controllers/docs.js +38 -8
  7. data/clients/sc_docs/english.lproj/body.css +80 -127
  8. data/clients/sc_docs/english.lproj/body.rhtml +43 -23
  9. data/clients/sc_docs/english.lproj/no_docs.rhtml +2 -1
  10. data/clients/sc_docs/english.lproj/tabs.rhtml +16 -0
  11. data/clients/sc_docs/main.js +14 -9
  12. data/clients/sc_docs/models/doc.js +1 -1
  13. data/clients/sc_docs/tests/controllers/docs.rhtml +1 -2
  14. data/clients/sc_docs/tests/models/doc.rhtml +1 -2
  15. data/clients/sc_docs/tests/views/doc_frame.rhtml +1 -2
  16. data/clients/sc_docs/tests/views/doc_label_view.rhtml +1 -2
  17. data/clients/sc_docs/views/doc_frame.js +1 -1
  18. data/clients/sc_test_runner/controllers/runner.js +31 -8
  19. data/clients/sc_test_runner/english.lproj/body.css +62 -122
  20. data/clients/sc_test_runner/english.lproj/body.rhtml +62 -26
  21. data/clients/sc_test_runner/main.js +1 -6
  22. data/clients/sc_test_runner/models/test.js +14 -1
  23. data/clients/sc_test_runner/views/runner_frame.js +4 -2
  24. data/clients/view_builder/builders/builder.js +339 -0
  25. data/clients/view_builder/builders/button.js +81 -0
  26. data/clients/view_builder/controllers/document.js +21 -0
  27. data/clients/view_builder/core.js +19 -0
  28. data/clients/view_builder/english.lproj/body.css +77 -0
  29. data/clients/view_builder/english.lproj/body.rhtml +41 -0
  30. data/clients/{sc_docs → view_builder}/english.lproj/controls.css +0 -0
  31. data/clients/view_builder/english.lproj/strings.js +14 -0
  32. data/clients/view_builder/main.js +38 -0
  33. data/clients/view_builder/tests/controllers/document.rhtml +20 -0
  34. data/clients/view_builder/tests/views/builder.rhtml +20 -0
  35. data/clients/view_builder/views/builder.js +23 -0
  36. data/frameworks/prototype/prototype.js +1 -1
  37. data/frameworks/sproutcore/Core.js +32 -7
  38. data/frameworks/sproutcore/README +1 -1
  39. data/frameworks/sproutcore/animation/animation.js +411 -0
  40. data/frameworks/sproutcore/controllers/array.js +17 -9
  41. data/frameworks/sproutcore/controllers/collection.js +9 -110
  42. data/frameworks/sproutcore/controllers/controller.js +1 -1
  43. data/frameworks/sproutcore/controllers/object.js +2 -1
  44. data/frameworks/sproutcore/drag/drag.js +267 -56
  45. data/frameworks/sproutcore/drag/drag_data_source.js +24 -16
  46. data/frameworks/sproutcore/drag/drag_source.js +53 -42
  47. data/frameworks/sproutcore/drag/drop_target.js +2 -2
  48. data/frameworks/sproutcore/english.lproj/buttons.css +337 -236
  49. data/frameworks/sproutcore/english.lproj/core.css +115 -0
  50. data/frameworks/sproutcore/english.lproj/icons.css +227 -0
  51. data/{clients/sc_docs → frameworks/sproutcore}/english.lproj/images/indicator.gif +0 -0
  52. data/frameworks/sproutcore/english.lproj/images/sc-theme-sprite.png +0 -0
  53. data/frameworks/sproutcore/english.lproj/images/sc-theme-ysprite.png +0 -0
  54. data/frameworks/sproutcore/english.lproj/images/shared-icons.png +0 -0
  55. data/frameworks/sproutcore/english.lproj/menu.css +1 -1
  56. data/frameworks/sproutcore/english.lproj/strings.js +1 -1
  57. data/frameworks/sproutcore/english.lproj/theme.css +405 -31
  58. data/frameworks/sproutcore/foundation/application.js +15 -11
  59. data/frameworks/sproutcore/foundation/benchmark.js +1 -1
  60. data/frameworks/sproutcore/foundation/binding.js +2 -2
  61. data/frameworks/sproutcore/foundation/date.js +1 -1
  62. data/frameworks/sproutcore/foundation/error.js +1 -1
  63. data/frameworks/sproutcore/foundation/input_manager.js +32 -21
  64. data/frameworks/sproutcore/foundation/mock.js +1 -1
  65. data/frameworks/sproutcore/foundation/node_descriptor.js +9 -6
  66. data/frameworks/sproutcore/foundation/object.js +249 -177
  67. data/frameworks/sproutcore/foundation/page.js +5 -2
  68. data/frameworks/sproutcore/foundation/path_module.js +11 -10
  69. data/frameworks/sproutcore/foundation/responder.js +5 -2
  70. data/frameworks/sproutcore/foundation/routes.js +17 -13
  71. data/frameworks/sproutcore/foundation/run_loop.js +249 -11
  72. data/frameworks/sproutcore/foundation/server.js +1 -1
  73. data/frameworks/sproutcore/foundation/set.js +3 -3
  74. data/frameworks/sproutcore/foundation/string.js +5 -3
  75. data/frameworks/sproutcore/foundation/timer.js +371 -0
  76. data/frameworks/sproutcore/foundation/undo_manager.js +1 -1
  77. data/frameworks/sproutcore/foundation/unittest.js +3 -3
  78. data/frameworks/sproutcore/foundation/utils.js +161 -2
  79. data/frameworks/sproutcore/globals/panels.js +1 -1
  80. data/frameworks/sproutcore/globals/popups.js +4 -3
  81. data/frameworks/sproutcore/globals/window.js +44 -4
  82. data/frameworks/sproutcore/lib/button_views.rb +328 -0
  83. data/frameworks/sproutcore/lib/collection_view.rb +80 -0
  84. data/frameworks/sproutcore/lib/core_views.rb +281 -0
  85. data/frameworks/sproutcore/lib/form_views.rb +253 -0
  86. data/frameworks/sproutcore/lib/index.rhtml +2 -0
  87. data/frameworks/sproutcore/lib/menu_views.rb +88 -0
  88. data/frameworks/sproutcore/{foundation → mixins}/array.js +60 -29
  89. data/frameworks/sproutcore/mixins/control.js +265 -0
  90. data/frameworks/sproutcore/mixins/delegate_support.js +66 -0
  91. data/frameworks/sproutcore/{foundation → mixins}/observable.js +176 -6
  92. data/frameworks/sproutcore/mixins/scrollable.js +245 -0
  93. data/frameworks/sproutcore/mixins/selection_support.js +148 -0
  94. data/frameworks/sproutcore/mixins/validatable.js +152 -0
  95. data/frameworks/sproutcore/models/collection.js +5 -5
  96. data/frameworks/sproutcore/models/record.js +1 -1
  97. data/frameworks/sproutcore/models/store.js +1 -1
  98. data/frameworks/sproutcore/panes/dialog.js +1 -1
  99. data/frameworks/sproutcore/panes/manager.js +1 -1
  100. data/frameworks/sproutcore/panes/menu.js +1 -1
  101. data/frameworks/sproutcore/panes/overlay.js +2 -2
  102. data/frameworks/sproutcore/panes/panel.js +1 -1
  103. data/frameworks/sproutcore/panes/picker.js +1 -1
  104. data/frameworks/sproutcore/tests/controllers/array.rhtml +44 -4
  105. data/frameworks/sproutcore/tests/foundation/timer/invalidate.rhtml +33 -0
  106. data/frameworks/sproutcore/tests/foundation/timer/invokeLater.rhtml +145 -0
  107. data/frameworks/sproutcore/tests/foundation/timer/isPaused.rhtml +70 -0
  108. data/frameworks/sproutcore/tests/foundation/timer/schedule.rhtml +145 -0
  109. data/frameworks/sproutcore/tests/views/{scroll.rhtml → checkbox.rhtml} +3 -3
  110. data/frameworks/sproutcore/tests/views/{collection.rhtml → collection/base.rhtml} +33 -32
  111. data/frameworks/sproutcore/tests/views/collection/incremental_rendering.rhtml +260 -0
  112. data/frameworks/sproutcore/tests/views/image_cell.rhtml +19 -0
  113. data/frameworks/sproutcore/tests/views/label_item.rhtml +2 -4
  114. data/frameworks/sproutcore/tests/views/list.rhtml +2 -3
  115. data/frameworks/sproutcore/tests/views/list_item.rhtml +20 -0
  116. data/frameworks/sproutcore/tests/views/slider.rhtml +20 -0
  117. data/frameworks/sproutcore/tests/views/text_cell.rhtml +19 -0
  118. data/frameworks/sproutcore/tests/views/view/clippingFrame.rhtml +395 -0
  119. data/frameworks/sproutcore/tests/views/view/frame.rhtml +353 -0
  120. data/frameworks/sproutcore/tests/views/view/innerFrame.rhtml +347 -0
  121. data/frameworks/sproutcore/tests/views/view/isVisibleInWindow.rhtml +148 -0
  122. data/frameworks/sproutcore/tests/views/view/scrollFrame.rhtml +468 -0
  123. data/frameworks/sproutcore/validators/credit_card.js +33 -13
  124. data/frameworks/sproutcore/validators/date.js +26 -6
  125. data/frameworks/sproutcore/validators/email.js +21 -3
  126. data/frameworks/sproutcore/validators/not_empty.js +11 -1
  127. data/frameworks/sproutcore/validators/number.js +18 -4
  128. data/frameworks/sproutcore/validators/password.js +12 -1
  129. data/frameworks/sproutcore/validators/validator.js +204 -194
  130. data/frameworks/sproutcore/views/{button.js → button/button.js} +96 -94
  131. data/frameworks/sproutcore/views/button/checkbox.js +29 -0
  132. data/frameworks/sproutcore/views/button/disclosure.js +42 -0
  133. data/frameworks/sproutcore/views/button/radio.js +29 -0
  134. data/frameworks/sproutcore/views/{collection.js → collection/collection.js} +1373 -1024
  135. data/frameworks/sproutcore/views/collection/grid.js +124 -46
  136. data/frameworks/sproutcore/views/collection/image_cell.js +17 -46
  137. data/frameworks/sproutcore/views/collection/list.js +45 -35
  138. data/frameworks/sproutcore/views/collection/source_list.js +386 -0
  139. data/frameworks/sproutcore/views/collection/table.js +118 -0
  140. data/frameworks/sproutcore/views/container.js +7 -2
  141. data/frameworks/sproutcore/views/error_explanation.js +23 -10
  142. data/frameworks/sproutcore/views/{checkbox_field.js → field/checkbox_field.js} +16 -6
  143. data/frameworks/sproutcore/views/field/field.js +219 -0
  144. data/frameworks/sproutcore/views/{radio_field.js → field/radio_field.js} +27 -12
  145. data/frameworks/sproutcore/views/{select_field.js → field/select_field.js} +116 -90
  146. data/frameworks/sproutcore/views/{text_field.js → field/text_field.js} +57 -8
  147. data/frameworks/sproutcore/views/{textarea_field.js → field/textarea_field.js} +13 -3
  148. data/frameworks/sproutcore/views/filter_button.js +2 -2
  149. data/frameworks/sproutcore/views/form.js +3 -3
  150. data/frameworks/sproutcore/views/image.js +128 -21
  151. data/frameworks/sproutcore/views/inline_text_editor.js +1 -1
  152. data/frameworks/sproutcore/views/label.js +149 -92
  153. data/frameworks/sproutcore/views/list_item.js +225 -0
  154. data/frameworks/sproutcore/views/menu_item.js +10 -4
  155. data/frameworks/sproutcore/views/pagination.js +11 -4
  156. data/frameworks/sproutcore/views/popup_button.js +25 -21
  157. data/frameworks/sproutcore/views/popup_menu.js +10 -4
  158. data/frameworks/sproutcore/views/progress.js +29 -16
  159. data/frameworks/sproutcore/views/radio_group.js +1 -1
  160. data/frameworks/sproutcore/views/scroll.js +60 -20
  161. data/frameworks/sproutcore/views/segmented.js +1 -1
  162. data/frameworks/sproutcore/views/slider.js +132 -0
  163. data/frameworks/sproutcore/views/source_list_group.js +130 -0
  164. data/frameworks/sproutcore/views/spinner.js +1 -1
  165. data/frameworks/sproutcore/views/split.js +292 -0
  166. data/frameworks/sproutcore/views/split_divider.js +109 -0
  167. data/frameworks/sproutcore/views/tab.js +1 -1
  168. data/frameworks/sproutcore/views/toolbar.js +1 -1
  169. data/frameworks/sproutcore/views/view.js +1272 -591
  170. data/generators/client/templates/english.lproj/body.css +1 -1
  171. data/generators/controller/controller_generator.rb +1 -1
  172. data/generators/controller/templates/test.rhtml +2 -1
  173. data/generators/model/templates/test.rhtml +1 -1
  174. data/generators/test/templates/test.rhtml +1 -1
  175. data/generators/view/templates/test.rhtml +1 -1
  176. data/jsdoc/templates/sproutcore/class.tmpl +241 -338
  177. data/jsdoc/templates/sproutcore/default.css +105 -155
  178. data/jsdoc/templates/sproutcore/index.tmpl +43 -8
  179. data/jsdoc/templates/sproutcore/publish.js +9 -4
  180. data/lib/sproutcore/build_tools/html_builder.rb +29 -13
  181. data/lib/sproutcore/build_tools/resource_builder.rb +1 -1
  182. data/lib/sproutcore/bundle.rb +86 -25
  183. data/lib/sproutcore/jsdoc.rb +2 -0
  184. data/lib/sproutcore/version.rb +1 -1
  185. data/lib/sproutcore/view_helpers.rb +36 -3
  186. data/tasks/deployment.rake +1 -1
  187. metadata +69 -36
  188. data/clients/sc_docs/english.lproj/icons/small/next.png +0 -0
  189. data/clients/sc_docs/english.lproj/icons/small/reset.png +0 -0
  190. data/clients/sc_docs/english.lproj/images/gradients.png +0 -0
  191. data/clients/sc_docs/english.lproj/images/toolbar.png +0 -0
  192. data/clients/sc_docs/english.lproj/warning.rhtml +0 -6
  193. data/clients/sc_test_runner/english.lproj/warning.rhtml +0 -6
  194. data/frameworks/sproutcore/english.lproj/buttons.png +0 -0
  195. data/frameworks/sproutcore/english.lproj/collections.css +0 -82
  196. data/frameworks/sproutcore/english.lproj/images/buttons-sprite.png +0 -0
  197. data/frameworks/sproutcore/views/collection/collection_item.js +0 -36
  198. data/frameworks/sproutcore/views/collection/text_cell.js +0 -128
  199. data/frameworks/sproutcore/views/field.js +0 -214
  200. data/frameworks/sproutcore/views/workspace.js +0 -170
  201. data/generators/client/templates/english.lproj/controls.css +0 -0
  202. data/generators/framework/templates/english.lproj/body.css +0 -0
  203. data/generators/framework/templates/english.lproj/body.rhtml +0 -3
  204. data/generators/framework/templates/english.lproj/controls.css +0 -0
  205. data/lib/sproutcore/view_helpers/button_views.rb +0 -302
  206. data/lib/sproutcore/view_helpers/core_views.rb +0 -292
  207. data/lib/sproutcore/view_helpers/form_views.rb +0 -258
  208. data/lib/sproutcore/view_helpers/menu_views.rb +0 -94
@@ -1,6 +1,6 @@
1
1
  // ==========================================================================
2
2
  // SproutCore -- JavaScript Application Framework
3
- // copyright 2006-2007, Sprout Systems, Inc. and contributors.
3
+ // copyright 2006-2008, Sprout Systems, Inc. and contributors.
4
4
  // ==========================================================================
5
5
 
6
6
  // These are basic enhancements to the string class used throughout
@@ -28,7 +28,7 @@ Object.extend(String.prototype,{
28
28
 
29
29
  // first, replace any ORDERED replacements.
30
30
  var str = this.gsub(/%@([0-9]+)/, function(m) {
31
- return args[parseInt(m[1],0)-1] || '';
31
+ return (args[parseInt(m[1],0)-1] || '').toString();
32
32
  }) ;
33
33
 
34
34
  // now, replace any remaining %@ items. Use this indexOf() method b/c
@@ -42,7 +42,9 @@ Object.extend(String.prototype,{
42
42
  loc = idx + 2 ; // 2 to skip '%@'.
43
43
 
44
44
  // add in replacement.
45
- ret.push(args.shift()) ;
45
+ var value = args.shift() ;
46
+ if (value && value.toString) value = value.toString() ;
47
+ ret.push(value) ;
46
48
  }
47
49
 
48
50
  // include any remaining bits of the string.
@@ -0,0 +1,371 @@
1
+ // ========================================================================
2
+ // SproutCore
3
+ // copyright 2006-2008 Sprout Systems, Inc.
4
+ // ========================================================================
5
+
6
+ require('Core') ;
7
+
8
+ /**
9
+ @class
10
+
11
+ A Timer executes a method after a defined period of time. Timers are
12
+ significantly more efficient than using setTimeout() or setInterval()
13
+ because they are cooperatively scheduled using the run loop. Timers are
14
+ also gauranteed to fire at the same time, making it far easier to keep
15
+ multiple timers in sync.
16
+
17
+ h2. Overview
18
+
19
+ Timers were created for SproutCore as a way to efficiently defer execution
20
+ of code fragments for use in Animations, event handling, and other tasks.
21
+
22
+ Browsers are typically fairly inconsistant about when they will fire a
23
+ timeout or interval based on what the browser is currently doing. Timeouts
24
+ and intervals are also fairly expensive for a browser to execute, which
25
+ means if you schedule a large number of them it can quickly slow down the
26
+ browser considerably.
27
+
28
+ Timers, on the other handle, are scheduled cooperatively using the
29
+ SC.runLoop, which uses exactly one timeout to fire itself when needed and
30
+ then executes by timers that need to fire on its own. This approach can
31
+ be many timers faster than using timers and gaurantees that timers scheduled
32
+ to execute at the same time generally will do so, keeping animations and
33
+ other operations in sync.
34
+
35
+ h2. Scheduling a Timer
36
+
37
+ To schedule a basic timer, you can simply call SC.Timer.schedule() with
38
+ a target and action you wish to have invoked:
39
+
40
+ {{{
41
+ var timer = SC.Timer.schedule({
42
+ target: myObject, action: 'timerFired', interval: 100
43
+ });
44
+ }}}
45
+
46
+ When this timer fires, it will call the timerFired() method on myObject.
47
+
48
+ In addition to calling a method on a particular object, you can also use
49
+ a timer to execute a variety of other types of code:
50
+
51
+ - If you include an action name, but not a target object, then the action will be passed down the responder chain.
52
+ - If you include a property path for the action property (e.g. 'MyApp.someController.someMethod'), then the method you name will be executed.
53
+ - If you include a function in the action property, then the function will be executed. If you also include a target object, the function will be called with this set to the target object.
54
+
55
+ In general these properties are read-only. Changing an interval, target,
56
+ or action after creating a timer will have an unknown effect.
57
+
58
+ h2. Scheduling Repeating Timers
59
+
60
+ In addition to scheduling one time timers, you can also schedule timers to
61
+ execute periodically until some termination date. You make a timer
62
+ repeating by adding the repeats: YES property:
63
+
64
+ {{{
65
+ var timer = SC.Timer.schedule({
66
+ target: myObject,
67
+ action: 'updateAnimation',
68
+ interval: 100,
69
+ repeats: YES,
70
+ until: Time.now() + 1000
71
+ }) ;
72
+ }}}
73
+
74
+ The above example will execute the myObject.updateAnimation() every 100msec
75
+ for 1 second from the current time.
76
+
77
+ If you want a timer to repeat without expiration, you can simply omit the
78
+ until: property. The timer will then repeat until you invalidate it.
79
+
80
+ h2. Pausing and Invalidating Timers
81
+
82
+ If you have created a timer but you no longer want it to execute, you can
83
+ call the invalidate() method on it. This will remove the timer from the
84
+ run loop and clear certain properties so that it will not run again.
85
+
86
+ You can use the invalidate() method on both repeating and one-time timers.
87
+
88
+ If you do not want to invalidate a timer completely but you just want to
89
+ stop the timer from execution temporarily, you can alternatively set the
90
+ isPaused property to YES:
91
+
92
+ {{{
93
+ timer.set('isPaused', YES) ;
94
+ // Perform some critical function; timer will not execute
95
+ timer.set('isPaused', NO) ;
96
+ }}}
97
+
98
+ When a timer is paused, it will be scheduled and will fire like normal,
99
+ but it will not actually execute the action method when it fires. For a
100
+ one time timer, this means that if you have the timer paused when it fires,
101
+ it may never actually execute the action method. For repeating timers,
102
+ this means the timer will remain scheduled but simply will not execute its
103
+ action while the timer is paused.
104
+
105
+ h2. Firing Timers
106
+
107
+ If you need a timer to execute immediately, you can always call the fire()
108
+ method yourself. This will execute the timer action, if the timer is not
109
+ paused. For a one time timer, it will also invalidate the timer and remove
110
+ it from the run loop. Repeating timers can be fired anytime and it will
111
+ not interrupt their regular scheduled times.
112
+
113
+
114
+ @extends SC.Object
115
+ @author Charles Jolley
116
+ @version 1.0
117
+ @since version 1.0
118
+ */
119
+ SC.Timer = SC.Object.extend(
120
+ /** @scope SC.Timer.prototype */ {
121
+
122
+ /**
123
+ The target object whose method will be invoked when the time fires.
124
+
125
+ You can set either a target/action property or you can pass a specific
126
+ method.
127
+
128
+ @type {Object}
129
+ @field
130
+ */
131
+ target: null,
132
+
133
+ /**
134
+ The action to execute.
135
+
136
+ The action can be a method name, a property path, or a function. If you
137
+ pass a method name, it will be invoked on the target object or it will
138
+ be called up the responder chain if target is null. If you pass a
139
+ property path and it resolves to a function then the function will be
140
+ called. If you pass a function instead, then the function will be
141
+ called in the context of the target object.
142
+
143
+ @type {String, Function}
144
+ */
145
+ action: null,
146
+
147
+ /**
148
+ The time interval in milliseconds.
149
+
150
+ You generally set this when you create the timer. If you do not set it
151
+ then the timer will fire as soon as possible in the next run loop.
152
+
153
+ @type {Number}
154
+ */
155
+ interval: 0,
156
+
157
+ /**
158
+ Timer start date offset.
159
+
160
+ The start date determines when the timer will be scheduled. The first
161
+ time the timer fires will be interval milliseconds after the start
162
+ date.
163
+
164
+ Generally you will not set this property yourself. Instead it will be
165
+ set automatically to the current run loop start date when you schedule
166
+ the timer. This ensures that all timers scheduled in the same run loop
167
+ cycle will execute in the sync with one another.
168
+
169
+ The value of this property is an offset like waht you get if you call
170
+ Date.now().
171
+
172
+ @type {Number}
173
+ */
174
+ startTime: null,
175
+
176
+ /**
177
+ YES if you want the timer to execute repeatedly.
178
+
179
+ @type {Boolean}
180
+ */
181
+ repeats: NO,
182
+
183
+ /**
184
+ Last date when the timer will execute.
185
+
186
+ If you have set repeats to YES, then you can also set this property to
187
+ have the timer automatically stop executing past a certain date.
188
+
189
+ This property should contain an offset value like startOffset. However if
190
+ you set it to a Date object on create, it will be converted to an offset
191
+ for you.
192
+
193
+ If this property is null, then the timer will continue to repeat until you
194
+ call invalidate().
195
+
196
+ @type {Date, Number}
197
+ */
198
+ until: null,
199
+
200
+ /**
201
+ Set to YES to pause the timer.
202
+
203
+ Pausing a timer does not remove it from the run loop, but it will
204
+ temporarily suspend it from firing. You should use this property if
205
+ you will want the timer to fire again the future, but you want to prevent
206
+ it from firing temporarily.
207
+
208
+ If you are done with a timer, you should call invalidate() instead of
209
+ setting this property.
210
+
211
+ @type {Boolean}
212
+ */
213
+ isPaused: NO,
214
+
215
+ /**
216
+ YES onces the timer has been scheduled for the first time.
217
+ */
218
+ isScheduled: NO,
219
+
220
+ /**
221
+ YES if the timer can still execute.
222
+
223
+ This read only property will return YES as long as the timer may possibly
224
+ fire again in the future. Once a timer has become invalid, it cannot
225
+ become valid again.
226
+
227
+ @field
228
+ @type {Boolean}
229
+ */
230
+ isValid: function() {
231
+ return !this._invalid ;
232
+ }.property('isPaused'),
233
+
234
+ /**
235
+ Returns the next time offset when the property will fire.
236
+
237
+ This property changes automatically after a timer has fired. If the
238
+ timer is invalid this will return 0.
239
+
240
+ @field
241
+ @type {Number}
242
+ */
243
+ fireTime: function() {
244
+ if (this._invalid || !this.get('isValid')) return 0;
245
+
246
+ var now = Date.now() ;
247
+ var start = this.get('startTime') || now ;
248
+ if (this.until && this.until > 0 && now >= this.until) return 0;
249
+
250
+ var interval = this.get('interval') ;
251
+ var cycle = Math.ceil(((now - start) / interval)+0.01) ;
252
+ if ((cycle > 1) && !this.repeats) return 0 ;
253
+
254
+ if (cycle < 1) cycle = 1 ;
255
+ return start + (cycle * interval) ;
256
+ }.property(),
257
+
258
+ /**
259
+ Invalidates the timer so that it will not execute again. If a timer has
260
+ been scheduled, it will be removed from the run loop immediately.
261
+
262
+ @returns {SC.Timer} The receiver
263
+ */
264
+ invalidate: function() {
265
+ this.propertyWillChange('isValid') ;
266
+ this._invalid = YES ;
267
+ SC.runLoop.cancelTimer(this) ;
268
+ this.propertyDidChange('isValid') ;
269
+ this.action = this.target = null ; // avoid memory leaks
270
+ return this ;
271
+ },
272
+
273
+ /**
274
+ Immediately fires the timer.
275
+
276
+ If the timer is not-repeating, it will be invalidated. If it is repeating
277
+ you can call this method without interrupting its normal schedule.
278
+
279
+ @returns {void}
280
+ */
281
+ fire: function() {
282
+ if (this.get('isPaused') === NO) {
283
+ this.performAction() ;
284
+ }
285
+
286
+ (this.repeats && (this.get('fireTime')>0)) ? this.schedule() : this.invalidate() ;
287
+ },
288
+
289
+ /**
290
+ Actually fires the action. You can override this method if you need
291
+ to change how the timer fires its action.
292
+ */
293
+ performAction: function() {
294
+ // if the action is a function, just try to call it.
295
+ if ($type(this.action) == T_FUNCTION) {
296
+ this.action.call((this.target || this), this) ;
297
+
298
+ // otherwise, action should be a string. If it has a period, treat it
299
+ // like a property path.
300
+ } else if (this.action.indexOf('.') >= 0) {
301
+ var path = this.action.split('.') ;
302
+ var property = path.pop() ;
303
+
304
+ var target = SC.Object.objectForPropertyPath(path, window) ;
305
+ var action = (target.get) ? target.get(property) : target[property];
306
+ if (action && $type(action) == T_FUNCTION) {
307
+ action.call(target, this) ;
308
+ } else {
309
+ throw '%@: Timer could not find a function at %@'.fmt(this, this.action) ;
310
+ }
311
+
312
+ // otherwise, try to execute action direction on target or send down
313
+ // responder chain.
314
+ } else SC.app.sendAction(this.action, this.target, this) ;
315
+ },
316
+
317
+ /**
318
+ Schedules the timer to execute in the runloop.
319
+
320
+ This method is called automatically if you create the timer using the
321
+ schedule() class method. If you create the timer manually, you will
322
+ need to call this method yourself for the timer to execute.
323
+
324
+ @returns {SC.Timer} The receiver
325
+ */
326
+ schedule: function() {
327
+ if (!this._invalid) {
328
+ this.set('isScheduled', YES) ;
329
+ SC.runLoop.scheduleTimer(this, this.get('fireTime')) ;
330
+ }
331
+ return this ;
332
+ },
333
+
334
+ init: function() {
335
+ arguments.callee.base.call(this) ;
336
+
337
+ // convert startTime and until to times if they are dates.
338
+ if (this.startTime instanceof Date) {
339
+ this.startTime = this.startTime.getTime() ;
340
+ }
341
+
342
+ if (this.until instanceof Date) {
343
+ this.until = this.until.getTime() ;
344
+ }
345
+
346
+ // if start time was not set, get it from the run loop.
347
+ if (!this.startTime) this.startTime = SC.runLoop.get('startTime') ;
348
+ },
349
+
350
+ // if the paused state changes, notify the runloop so that it can
351
+ // reschedule its timeout.
352
+ _isPausedObserver: function() {
353
+ SC.runLoop.timerPausedStateDidChange(this) ;
354
+ }
355
+
356
+ }) ;
357
+
358
+ /**
359
+ @scope SC.Timer
360
+
361
+ Created a new timer with the passed properties and schedules it to
362
+ execute. This is the same as calling SC.Time.create({ props }).schedule().
363
+
364
+ @params {Hash} props Any properties you want to set on the timer.
365
+ @returns {SC.Timer} new timer instance.
366
+ */
367
+ SC.Timer.schedule = function(props) {
368
+ return this.create(props).schedule() ;
369
+ } ;
370
+
371
+
@@ -1,6 +1,6 @@
1
1
  // ==========================================================================
2
2
  // SproutCore -- JavaScript Application Framework
3
- // copyright 2006-2007, Sprout Systems, Inc. and contributors.
3
+ // copyright 2006-2008, Sprout Systems, Inc. and contributors.
4
4
  // ==========================================================================
5
5
 
6
6
  require('Core');
@@ -1,8 +1,8 @@
1
1
  // script.aculo.us unittest.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007
2
2
 
3
- // Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
4
- // (c) 2005-2007 Jon Tirsen (http://www.tirsen.com)
5
- // (c) 2005-2007 Michael Schuerig (http://www.schuerig.de/michael/)
3
+ // Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
4
+ // (c) 2005-2008 Jon Tirsen (http://www.tirsen.com)
5
+ // (c) 2005-2008 Michael Schuerig (http://www.schuerig.de/michael/)
6
6
  //
7
7
  // script.aculo.us is freely distributable under the terms of an MIT-style license.
8
8
  // For details, see the script.aculo.us web site: http://script.aculo.us/
@@ -1,9 +1,9 @@
1
1
  // ==========================================================================
2
2
  // SproutCore -- JavaScript Application Framework
3
- // copyright 2006-2007, Sprout Systems, Inc. and contributors.
3
+ // copyright 2006-2008, Sprout Systems, Inc. and contributors.
4
4
  // ==========================================================================
5
5
 
6
- // These are helpful utility functions.
6
+ // These are helpful utility functions for calculating range and rect values
7
7
 
8
8
 
9
9
  Object.extend(SC,
@@ -66,12 +66,171 @@ Object.extend(SC,
66
66
  @returns {Boolean} true if rects match
67
67
  */
68
68
  rectsEqual: function(r1, r2, delta) {
69
+ if (!r1 || !r2) return (r1 == r2) ;
70
+
69
71
  if (delta == null) delta = 0.1;
70
72
  if (Math.abs(r1.y - r2.y) > delta) return false ;
71
73
  if (Math.abs(r1.x - r2.x) > delta) return false ;
72
74
  if (Math.abs(r1.width - r2.width) > delta) return false ;
73
75
  if (Math.abs(r1.height - r2.height) > delta) return false ;
74
76
  return true ;
77
+ },
78
+
79
+ /** Returns the insersection between two rectangles.
80
+
81
+ @param r1 {Rect} The first rect
82
+ @param r2 {Rect} the second rect
83
+ @returns {Rect} the intersection rect. width || height will be 0 if they do not interset.
84
+ */
85
+ intersectRects: function(r1, r2) {
86
+ // find all four edges
87
+ var ret = {
88
+ x: Math.max(SC.minX(r1), SC.minX(r2)),
89
+ y: Math.max(SC.minY(r1), SC.minY(r2)),
90
+ width: Math.min(SC.maxX(r1), SC.maxX(r2)),
91
+ height: Math.min(SC.maxY(r1), SC.maxY(r2))
92
+ } ;
93
+
94
+ // convert edges to w/h
95
+ ret.width = Math.max(0, ret.width - ret.x) ;
96
+ ret.height = Math.max(0, ret.height - ret.y) ;
97
+ return ret ;
98
+ },
99
+
100
+ /** Returns the union between two rectangles
101
+
102
+ @param r1 {Rect} The first rect
103
+ @param r2 {Rect} The second rect
104
+ @returns {Rect} The union rect.
105
+ */
106
+ unionRects: function(r1, r2) {
107
+ // find all four edges
108
+ var ret = {
109
+ x: Math.min(SC.minX(r1), SC.minX(r2)),
110
+ y: Math.min(SC.minY(r1), SC.minY(r2)),
111
+ width: Math.max(SC.maxX(r1), SC.maxX(r2)),
112
+ height: Math.max(SC.maxY(r1), SC.maxX(r2))
113
+ } ;
114
+
115
+ // convert edges to w/h
116
+ ret.width = Math.max(0, ret.width - ret.x) ;
117
+ ret.height = Math.max(0, ret.height - ret.y) ;
118
+ return ret ;
119
+ },
120
+
121
+ /** Duplicates the passed rect.
122
+
123
+ This is faster than Object.clone().
124
+
125
+ @param r {Rect} The rect to clone.
126
+ @returns {Rect} The cloned rect
127
+ */
128
+ cloneRect: function(r) {
129
+ return { x: r.x, y: r.y, width: r.width, height: r.height } ;
130
+ },
131
+
132
+
133
+ /** Finds the absolute viewportOffset for a given element.
134
+ This method is more accurate than the version provided by prototype.
135
+
136
+ @param el The DOM element
137
+ @returns {Point} A hash with x,y offsets.
138
+ */
139
+ viewportOffset: function(el) {
140
+ var valueL = 0 ; var valueT = 0;
141
+
142
+ // add up all the offsets for the element.
143
+ var element = el ;
144
+ do {
145
+ valueT += (element.offsetTop || 0) + (element.clientTop || 0);
146
+ valueL += (element.offsetLeft || 0) + (element.clientLeft || 0);
147
+
148
+ // bizarely for FireFox if your offsetParent has a border, then it can
149
+ // impact the offset.
150
+ if (SC.Platform.Firefox) {
151
+ var overflow = Element.getStyle(element, 'overflow') ;
152
+ if (overflow !== 'visible') {
153
+ var left = parseInt(Element.getStyle(element, 'borderLeftWidth'),0) || 0 ;
154
+ var top = parseInt(Element.getStyle(element, 'borderTopWidth'),0) || 0 ;
155
+ if (el !== element) {
156
+ left *= 2; top *= 2 ;
157
+ }
158
+ valueL += left; valueT += top ;
159
+ }
160
+ }
161
+
162
+ // Safari fix
163
+ if (element.offsetParent == document.body &&
164
+ Element.getStyle(element, 'position') == 'absolute') break;
165
+
166
+
167
+
168
+ } while (element = element.offsetParent);
169
+
170
+ element = el;
171
+ do {
172
+ if (!Prototype.Browser.Opera || element.tagName == 'BODY') {
173
+ valueT -= element.scrollTop || 0;
174
+ valueL -= element.scrollLeft || 0;
175
+ }
176
+ } while (element = element.parentNode);
177
+
178
+ return { x: valueL, y: valueT } ;
179
+ },
180
+
181
+ /** A Point at {0,0} */
182
+ ZERO_POINT: { x: 0, y: 0 },
183
+
184
+ /** A zero length range at zero. */
185
+ ZERO_RANGE: { start: 0, length: 0 },
186
+
187
+ RANGE_NOT_FOUND: { start: 0, length: -1 },
188
+
189
+ /** Returns true if the passed index is in the specified range */
190
+ valueInRange: function(value, range) {
191
+ return (range > 0) && (value >= range.start) && (value < (range.start + range.length));
192
+ },
193
+
194
+ /** Returns first value of the range. */
195
+ minRange: function(range) { return range.start; },
196
+
197
+ /** Returns the first value outside of the range. */
198
+ maxRange: function(range) { return (range.length < 0) ? -1 : (range.start + range.length); },
199
+
200
+ /** Returns the union of two ranges. If one range is null, the other
201
+ range will be returned. */
202
+ unionRanges: function(r1, r2) {
203
+ if ((r1 == null) || (r1.length < 0)) return r2 ;
204
+ if ((r2 == null) || (r2.length < 0)) return r1 ;
205
+
206
+ var min = Math.min(r1.start, r2.start) ;
207
+ var max = Math.max(SC.maxRange(r1), SC.maxRange(r2)) ;
208
+ return { start: min, length: max - min } ;
209
+ },
210
+
211
+ /** Returns the intersection of the two ranges or SC.RANGE_NOT_FOUND */
212
+ intersectRanges: function(r1, r2) {
213
+ if ((r1 == null) || (r2 == null)) return SC.RANGE_NOT_FOUND ;
214
+ if ((r1.length < 0) || (r2.length < 0)) return SC.RANGE_NOT_FOUND;
215
+ var min = Math.max(SC.minRange(r1), SC.minRange(r2)) ;
216
+ var max = Math.min(SC.maxRange(r1), SC.maxRange(r2)) ;
217
+ if (max < min) return SC.RANGE_NOT_FOUND ;
218
+ return { start: min, length: max-min };
219
+ },
220
+
221
+ /** Returns a clone of the range. */
222
+ cloneRange: function(r) {
223
+ return { start: r.start, length: r.length };
224
+ },
225
+
226
+ /** Returns true if the two passed ranges are equal. A null value is
227
+ treated like RANGE_NOT_FOUND.
228
+ */
229
+ rangesEqual: function(r1, r2) {
230
+ if (r1===r2) return true ;
231
+ if (r1 == null) return r2.length < 0 ;
232
+ if (r2 == null) return r1.length < 0 ;
233
+ return (r1.start == r2.start) && (r1.length == r2.length) ;
75
234
  }
76
235
 
77
236
  }) ;