sproutcore 0.9.6 → 0.9.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -1 +1,15 @@
1
- SproutCore is a framework for building applications in JavaScript. It eliminates much of the glue code you would often write to build applications on the web so you can focus on building features. To get started using SproutCore, visit the website at http://www.sproutcore.com, where you can find documentation and tutorials.
1
+ SproutCore JavaScript Application Framework
2
+
3
+ SproutCore is a framework for building desktop-like applications in the web without the use of plugins. With SproutCore, you build rich, interactive
4
+ applications in the web in less code than most simple web pages require today.
5
+
6
+ The easiest way to get started with SproutCore is using the BlueRibbon build
7
+ tools included with the SproutCore package when you install it from the Ruby
8
+ Gems. Please see the Getting Started documentation on the SproutCore website
9
+ for more information.
10
+
11
+ http://www.sproutcore.com
12
+
13
+ If you would like to contact the authors, you can reach the current maintainer
14
+ at charles@sproutit.com
15
+
@@ -133,6 +133,7 @@ Object.extend(SC,
133
133
  /** Finds the absolute viewportOffset for a given element.
134
134
  This method is more accurate than the version provided by prototype.
135
135
 
136
+ If you pass NULL to this method, it will return a { x:0, y:0 }
136
137
  @param el The DOM element
137
138
  @returns {Point} A hash with x,y offsets.
138
139
  */
@@ -141,7 +142,7 @@ Object.extend(SC,
141
142
 
142
143
  // add up all the offsets for the element.
143
144
  var element = el ;
144
- do {
145
+ while (element) {
145
146
  valueT += (element.offsetTop || 0) + (element.clientTop || 0);
146
147
  valueL += (element.offsetLeft || 0) + (element.clientLeft || 0);
147
148
 
@@ -163,17 +164,19 @@ Object.extend(SC,
163
164
  if (element.offsetParent == document.body &&
164
165
  Element.getStyle(element, 'position') == 'absolute') break;
165
166
 
167
+ element = element.offsetParent ;
166
168
 
167
-
168
- } while (element = element.offsetParent);
169
+ }
169
170
 
170
171
  element = el;
171
- do {
172
+ while (element) {
172
173
  if (!Prototype.Browser.Opera || element.tagName == 'BODY') {
173
174
  valueT -= element.scrollTop || 0;
174
175
  valueL -= element.scrollLeft || 0;
175
176
  }
176
- } while (element = element.parentNode);
177
+
178
+ element = element.parentNode ;
179
+ }
177
180
 
178
181
  return { x: valueL, y: valueT } ;
179
182
  },
@@ -8,7 +8,7 @@ Test.context("A SC.PopupButtonView with no configured menu", {
8
8
  {
9
9
  for (var i=0, n=this.buttons.length; i < n; i++)
10
10
  {
11
- (this.buttons[i].get('menu') == null).shouldEqual(true);
11
+ (buttons[i].get('menu') == null).shouldEqual(true);
12
12
  }
13
13
  },
14
14
  "Should return false if asked to trigger it's action": function()
@@ -32,9 +32,10 @@ Test.context("A SC.PopupButtonView with no configured menu", {
32
32
  SC.PopupButtonView.extend({ menuName: '' }).viewFor(null),
33
33
  SC.PopupButtonView.extend({ menuName: 'foobarMenu' }).viewFor(null),
34
34
  SC.PopupButtonView.extend({ menuName: false }).viewFor(null),
35
- SC.PopupButtonView.extend({ menuName: null }).viewFor(null),
35
+ SC.PopupButtonView.extend({ menuName: null }).viewFor(null)
36
36
  ];
37
37
  },
38
+
38
39
  teardown: function()
39
40
  {
40
41
  delete this.buttons;
@@ -583,12 +583,12 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
583
583
  @returns {Range} a range of objects
584
584
  */
585
585
  groupRangeForContentIndex: function(contentIndex) {
586
+ var content = Array.from(this.get('content')) ;
587
+ var len = content.get('length') ;
586
588
  var groupBy = this.get('groupBy') ;
587
- if (!groupBy) return { start: contentIndex, length: 1 } ;
589
+ if (!groupBy) return { start: 0, length: len } ;
588
590
 
589
591
  var min = contentIndex, max = contentIndex ;
590
- var content = Array.from(this.get('content')) ;
591
- var len = content.get('length') ;
592
592
  var cur = content.objectAt(contentIndex) ;
593
593
  var groupValue = (cur) ? cur.get(groupBy) : null ;
594
594
 
@@ -2111,7 +2111,6 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
2111
2111
  // index.
2112
2112
  var loc = drag.get('location') ;
2113
2113
  loc = this.convertFrameFromView(loc, null) ;
2114
-
2115
2114
  var dropOp = SC.DROP_BEFORE ;
2116
2115
  var dragOp = SC.DRAG_NONE ;
2117
2116
 
@@ -2125,7 +2124,7 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
2125
2124
  dropOp = idx[1] ;
2126
2125
  idx = idx[0] ;
2127
2126
  }
2128
-
2127
+
2129
2128
  // if the return drop operation is DROP_ON, then just check it with the
2130
2129
  // delegate method. If the delegate method does not support dropping on,
2131
2130
  // then it will return DRAG_NONE, in which case we will try again with
@@ -392,9 +392,11 @@ SC.SourceListView = SC.CollectionView.extend(
392
392
  var f = this.get('innerFrame') ;
393
393
  var sf = this.get('scrollFrame') ;
394
394
  var rowHeight = this.get('rowHeight') || 0 ;
395
-
395
+ var headerRowCount = (this.get("groupBy")) ? 1 : 0;
396
+
396
397
  // find the offset to work with.
397
398
  var offset = loc.y - f.y - sf.y ;
399
+
398
400
  var ret = -1; // the return value
399
401
  var retOp = SC.DROP_BEFORE ;
400
402
 
@@ -402,13 +404,14 @@ SC.SourceListView = SC.CollectionView.extend(
402
404
  var top = 0;
403
405
  var idx = 0 ;
404
406
  while((ret<0) && (range = this.groupRangeForContentIndex(idx)).length>0){
405
- var max = top + ((range.length+1) * rowHeight) ;
407
+ var max = top + ((range.length+headerRowCount) * rowHeight) ;
406
408
 
407
409
  // the offset is within the group, find the row in the group. Remember
408
410
  // that the top row is actually the label, so we should return -1 if
409
411
  // we hit there.
410
412
  if (max >= offset) {
411
413
  offset -= top ;
414
+
412
415
  ret = Math.floor(offset / rowHeight) ;
413
416
 
414
417
  // find the percent through the row...
@@ -426,11 +429,11 @@ SC.SourceListView = SC.CollectionView.extend(
426
429
  }
427
430
 
428
431
  // handle dropping on top row...
429
- if (ret < 1) return [-1, SC.DROP_BEFORE] ; // top row!
432
+ if (ret < headerRowCount) return [-1, SC.DROP_BEFORE] ; // top row!
430
433
 
431
434
  // convert to index
432
- ret = (ret - 1) + idx ;
433
-
435
+ ret = (ret - headerRowCount) + idx ;
436
+
434
437
  // we are not yet within the group, go on to the next group.
435
438
  } else {
436
439
  idx += range.length ;
@@ -100,7 +100,9 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
100
100
  this._isFocused = true ;
101
101
  if (this.get('isVisibleInWindow')) {
102
102
  this.rootElement.focus();
103
- this.rootElement.select.bind(this.rootElement).delay(0.05);
103
+
104
+ this.invokeLater(this._selectRootElement, 1) ;
105
+
104
106
  }
105
107
  }
106
108
 
@@ -108,6 +110,12 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
108
110
  this._updateFieldHint() ;
109
111
  },
110
112
 
113
+ // In IE, you can't modify functions on DOM elements so we need to wrap the call to select()
114
+ // like this.
115
+ _selectRootElement: function() {
116
+ this.rootElement.select() ;
117
+ },
118
+
111
119
  // when we lose first responder, blur the text field if needed and show
112
120
  // the hint text if needed.
113
121
  /** @private */
@@ -115,12 +123,15 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
115
123
 
116
124
  if (this._isFocused) {
117
125
  this._isFocused = false ;
126
+ this._updateFieldHint() ;
118
127
  return this.rootElement.blur() ;
119
128
  }
120
-
121
- this._value = this.rootElement.value ;
122
- this.fieldValueDidChange() ;
123
- this._updateFieldHint() ;
129
+ else {
130
+ this._value = this.rootElement.value ;
131
+ this.fieldValueDidChange() ;
132
+ this._updateFieldHint() ;
133
+ return true;
134
+ }
124
135
  },
125
136
 
126
137
  _isFocused: false,
@@ -877,7 +877,25 @@ SC.View = SC.Responder.extend(SC.PathModule, SC.DelegateSupport,
877
877
  @type {Element}
878
878
  */
879
879
  offsetParent: function() {
880
- return Position.offsetParent(this.rootElement) ;
880
+
881
+ // handle simple cases.
882
+ var el = this.rootElement ;
883
+ if (!el || el === document.body) return el;
884
+ if (el.offsetParent) return el.offsetParent ;
885
+
886
+ // in some cases, we can't find the offset parent so we walk up the
887
+ // chain until an element is found with a position other than
888
+ // 'static'
889
+ //
890
+ // Note that IE places DOM elements not in the main body inside of a
891
+ // document-fragment root. We need to treat document-fragments (i.e.
892
+ // nodeType === 11) as null values
893
+ var ret = null ;
894
+ while(!ret && (el = el.parentNode) && (el.nodeType !== 11) && (el !== document.body)) {
895
+ if (Element.getStyle(el, 'position') !== 'static') ret = el;
896
+ }
897
+ if (!ret && (el === document.body)) ret = el ;
898
+ return ret ;
881
899
  }.property(),
882
900
 
883
901
  /**
@@ -575,7 +575,7 @@ module SproutCore
575
575
  str.scan(/['"](.+)['"]\s*:\s*['"](.+)['"],?\s*$/) do |x,y|
576
576
  # x & y are JS strings that must be evaled as such..
577
577
  #x = eval(%("#{x}"))
578
- y = eval(%[%(#{y})])
578
+ y = eval(%[<<__EOF__\n#{y}\n__EOF__]).chop
579
579
  ret[x] = y
580
580
  end
581
581
 
@@ -2,7 +2,7 @@ module SproutCore #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 9
5
- TINY = 6
5
+ TINY = 7
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sproutcore
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.6
4
+ version: 0.9.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Charles Jolley
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-05-19 00:00:00 -07:00
12
+ date: 2008-05-27 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -90,8 +90,10 @@ files:
90
90
  - clients/sc_docs/english.lproj/strings.js
91
91
  - clients/sc_docs/english.lproj/tabs.rhtml
92
92
  - clients/sc_docs/fixtures/doc.js
93
+ - clients/sc_docs/HISTORY
93
94
  - clients/sc_docs/main.js
94
95
  - clients/sc_docs/models/doc.js
96
+ - clients/sc_docs/README
95
97
  - clients/sc_docs/tests/controllers/docs.rhtml
96
98
  - clients/sc_docs/tests/models/doc.rhtml
97
99
  - clients/sc_docs/tests/views/doc_frame.rhtml
@@ -111,14 +113,22 @@ files:
111
113
  - clients/sc_test_runner/english.lproj/no_tests.rhtml
112
114
  - clients/sc_test_runner/english.lproj/strings.js
113
115
  - clients/sc_test_runner/fixtures/test.js
116
+ - clients/sc_test_runner/HISTORY
114
117
  - clients/sc_test_runner/main.js
115
118
  - clients/sc_test_runner/models/test.js
119
+ - clients/sc_test_runner/README
116
120
  - clients/sc_test_runner/views/runner_frame.js
117
121
  - clients/sc_test_runner/views/test_label.js
122
+ - clients/view_builder/core.js
123
+ - clients/view_builder/english.lproj/body.css
124
+ - clients/view_builder/english.lproj/body.rhtml
125
+ - clients/view_builder/english.lproj/strings.js
126
+ - clients/view_builder/main.js
118
127
  - config/hoe.rb
119
128
  - config/requirements.rb
129
+ - frameworks/prototype/HISTORY
120
130
  - frameworks/prototype/prototype.js
121
- - frameworks/sproutcore/animation/animation.js
131
+ - frameworks/prototype/README
122
132
  - frameworks/sproutcore/controllers/array.js
123
133
  - frameworks/sproutcore/controllers/collection.js
124
134
  - frameworks/sproutcore/controllers/controller.js
@@ -174,7 +184,6 @@ files:
174
184
  - frameworks/sproutcore/foundation/run_loop.js
175
185
  - frameworks/sproutcore/foundation/server.js
176
186
  - frameworks/sproutcore/foundation/set.js
177
- - frameworks/sproutcore/foundation/sorted_set.js
178
187
  - frameworks/sproutcore/foundation/string.js
179
188
  - frameworks/sproutcore/foundation/timer.js
180
189
  - frameworks/sproutcore/foundation/undo_manager.js
@@ -183,6 +192,7 @@ files:
183
192
  - frameworks/sproutcore/globals/panels.js
184
193
  - frameworks/sproutcore/globals/popups.js
185
194
  - frameworks/sproutcore/globals/window.js
195
+ - frameworks/sproutcore/HISTORY
186
196
  - frameworks/sproutcore/lib/button_views.rb
187
197
  - frameworks/sproutcore/lib/collection_view.rb
188
198
  - frameworks/sproutcore/lib/core_views.rb
@@ -1,411 +0,0 @@
1
- // ========================================================================
2
- // SproutCore
3
- // copyright 2006-2008 Sprout Systems, Inc.
4
- // ========================================================================
5
-
6
- require('Core') ;
7
- require('foundation/timer') ;
8
-
9
- /**
10
- @class
11
-
12
- An animator is a special timer that will transition its value property from
13
- 0 to 1 according to a transform function you define. You can also specify
14
- one or more "subjects" that will be invoked whenever the animation value
15
- changes, which can apply the animation to any target you like.
16
-
17
- This class and its related classes are based on Bernie's Better Animator
18
- class.
19
-
20
- Use Cases:
21
-
22
- 1. I just want to transition from x=0 -> x=20.
23
- v.transitionTo('styleLeft', 20) ;
24
- -> creates an animation for styleLeft. If you add a new animation for
25
- the same effect, it will cancel the old one automatically.
26
-
27
- 2. I want to have an 'animation behavior' attached to some property.
28
- whenever I change it, it should automatically transition the property
29
- instead of just updating it. i.e. a "Tracker".
30
-
31
- -> I may want the tracker to update several things at once. But that
32
- could be done through changing one property which will in turn
33
- update everything else. Better idea.
34
-
35
- Tracker simply stores some animation properties and calls transitionTo
36
- whenever your target value changes.
37
-
38
- 3. I want to have some property animating on its own. For example a
39
- throbbing button
40
-
41
- a = v.addAnimation('opacity', {
42
- repeatCount: ,
43
- autoreverses: YES,
44
- end: 1.0,
45
- start: 0.0,
46
- property: 'opacity'
47
- }) ;
48
-
49
- a.set('isPaused', YES) ;
50
- v.removeAnimation('opacity');
51
-
52
- --
53
- We will need an animation builder. It would be nice if I could have a
54
- complete timeline for an animation setup and you just tell it to run. Set
55
- the timecode to anytime that you want, tell it to start or stop.
56
-
57
- @extends SC.Timer
58
- @author Charles Jolley
59
- @since SproutCore 1.0
60
- */
61
- SC.Animation = SC.Timer.extend(
62
- /** @scope SC.Animation.prototype */ {
63
-
64
- /**
65
- The target frame rate. This is used to determine the interval of the
66
- timer.
67
-
68
- @type {Number}
69
- @field
70
- */
71
- frameRate: 60,
72
-
73
- /**
74
- The interval between frames. Calculated automatically from the frameRate.
75
- This property is read only.
76
-
77
- @type {Number}
78
- @field
79
- */
80
- interval: function() {
81
- return 1000 / this.get('frameRate') ;
82
- }.property('frameRate'),
83
-
84
- /**
85
- The total amount of time in msec you want to take for the animation to
86
- go from 0-1.
87
- */
88
- duration: 0,
89
-
90
- /**
91
- The speed at which the timecode for the animation will progress. 1.0
92
- means it will progress in real time, 2.0 means twice as fast, etc.
93
- */
94
- speed: 1.0,
95
-
96
- /**
97
- The total number of times you want the animation to repeat.
98
-
99
- This can be any number, including partial numbers. If you set this
100
- value you must not set repeatDuration as well. This will be ignored
101
- if the value is 0, which is the default.
102
-
103
- If you set this property to -1, then the animation will repeat
104
- indefinitely.
105
-
106
- Setting this property will update the targetTimecode.
107
-
108
- @type {Number}
109
- @field
110
- */
111
- repeatCount: 0,
112
-
113
- /**
114
- The total amount of time the animation should run, repeating itself, in
115
- msec.
116
-
117
- If you set this value you must not set repeatCount as well. This will
118
- be ignored if the value is 0, which is the default.
119
-
120
- Setting this property will update the targetTimecode.
121
-
122
- @type {Number}
123
- @field
124
- */
125
- repeatDuration: 0,
126
-
127
- /**
128
- If YES, then the animation will automatically reverse itself on each
129
- repeat.
130
-
131
- @type {Boolean}
132
- @field
133
- */
134
- autoreverses: NO,
135
-
136
- /**
137
- A transition function. This is used to convert the progress into a
138
- state value. You can supply your own transition function to provide
139
- varied behaviors such as ease in, ease out, etc.
140
-
141
- The function must have a signature like:
142
-
143
- transition: function(value, animator)
144
-
145
- It must accept a value from 0-1 indicating the current animation progress
146
- and return a value from 0-1 indication the current transition progress.
147
-
148
- @type {Function}
149
- @field
150
- */
151
- transition: null,
152
-
153
- /**
154
- This is the current timecode for the animation, in msec. You can set
155
- this to any value that you want and the animation to compute the current
156
- transition value from it.
157
-
158
- To move instantly to any part of your animation, you can simply set this
159
- timecode or use jumpTo().
160
-
161
- @type {Number}
162
- @field
163
- */
164
- currentTimecode: 0,
165
-
166
- /**
167
- This is the target timecode. Whenever the target timecode and the
168
- current timecode do not match, the animation will animate until it
169
- reaches the target timecode.
170
-
171
- To transition the animation to a new state, set the timecode to any
172
- value that you want.
173
-
174
- @type {Number}
175
- */
176
- targetTimecode: 0,
177
-
178
- /**
179
- The current animation progress.
180
-
181
- This value will loop from 0-1 based on the current timecode and the
182
- setting of autoreverses. You generally do not want to use this value.
183
- Instead use the value property to compute the current transition.
184
-
185
- @type {Number}
186
- @field
187
- */
188
- progress: function() {
189
-
190
- // current progress is calculated from the currentTimecode by dividing
191
- // it by the animation duration and autoreverses.
192
- var currentTimecode = this.get('currentTimecode') ;
193
- var duration = this.get('duration') ;
194
- var reverses = this.get('autoreverses') ;
195
-
196
- // find the progress through the current cycle.
197
- var cycle = Math.floor(currentTimecode / duration) ;
198
- var progress = (currentTimecode - (duration * cycle)) / duration;
199
-
200
- // if we autoreverse and the cycle is odd numbered, invert.
201
- if (reverses && (cycle % 2) > 0) progress = 1 - progress ;
202
- return progress ;
203
- }.property('currentTimecode', 'duration', 'autoreverses'),
204
-
205
- /**
206
- The current animation value. Transform functions can observe this
207
- property and update the target object accordingly.
208
-
209
- @type {Number}
210
- @field
211
- */
212
- value: function() {
213
- var value = this.get('progress');
214
- if (this.transition) value = this.transition(value, this) ;
215
- return value ;
216
- }.property('progress'),
217
-
218
- /**
219
- The target object of the animation. This is often used by transform
220
- functions as the target of their change. It is not strictly required.
221
-
222
- @type {Object}
223
- @field
224
- */
225
- target: null,
226
-
227
-
228
- /**
229
- This method must be called once when the animation is created to schedule
230
- it with the run loop. Once animation has been started, you should can
231
- pause it to remove it from the runloop temporarily.
232
-
233
- @returns {void}
234
- */
235
- play: function() {
236
- this.beginPropertyChanges() ;
237
- if (!this.get('isScheduled')) {
238
- this.schedule() ;
239
- this._lastActionTime = SC.runLoop.get('startTime') ;
240
- }
241
-
242
- if (this.get('isPaused')) this.set('isPaused', NO) ;
243
- this.endPropertyChanges() ;
244
- },
245
-
246
- /**
247
- Once an animation has been started, you can pause it anytime with this
248
- method. Call start() to restart it or set isPaused to NO.
249
-
250
- @returns {void}
251
- */
252
- pause: function() {
253
- this.set('isPaused', YES) ;
254
- },
255
-
256
- /**
257
- Immediately changes the currentTimecode to reflect the requested amount
258
- of progress through a single cycle of the animation.
259
-
260
- @param progress {Number} a progress value from 0 to 1.
261
- @returns {void}
262
- */
263
- jumpTo: function(progress) {
264
- // get the current progress.
265
- var cur = this.get('progress') ;
266
- var diff = progress - cur ;
267
- var duration = this.get('duration') ;
268
- diff *= duration ;
269
-
270
- var timecode = this.get('currentTimecode') ;
271
- if (diff !== 0) this.set('currentTimecode', timecode + diff) ;
272
- },
273
-
274
- /**
275
- Changes the targetTimecode to reflect the request amount of progress
276
- through the current cycle of the animation. If the animation is in
277
- reverse, this could move the timecode in the opposite direction.
278
-
279
- @param progress {Number} a progress value from 0 to 1.
280
- @returns {void}
281
- */
282
- seekTo: function(progress) {
283
- // get the current progress.
284
- var cur = this.get('progress') ;
285
- var diff = progress - cur ;
286
- var duration = this.get('duration') ;
287
- diff *= duration ;
288
-
289
- var timecode = this.get('currentTimecode') ;
290
- if (diff !== 0) this.set('targetTimecode', timecode + diff) ;
291
- },
292
-
293
- /**
294
- Changes the currentTimecode and targetTimecode to reflect the requested
295
- amount of progress through the current cycle of the animation. If the
296
- animation is in reverse, this could move the timecode in the opposite
297
- direction.
298
-
299
- @param fromProgress {Number} a progress value from 0 to 1
300
- @param toProgress {Number} a progress value from 0 to 1
301
- @returns {void}
302
- */
303
- seekFromTo: function(fromProgress, toProgress) {
304
- // get the current progress.
305
- var timecode = this.get('currentTimecode') ;
306
- var cur = this.get('progress') ;
307
- var duration = this.get('duration') ;
308
-
309
- this.beginPropertyChanges() ;
310
-
311
- var diff = fromProgress - cur ;
312
- diff *= duration ;
313
- if (diff !== 0) this.set('currentTimecode', timecode + diff) ;
314
-
315
- diff = toProgress - cur ;
316
- diff *= duration ;
317
- if (diff !== 0) this.set('targetTimecode', timecode + diff) ;
318
-
319
- this.endPropertyChanges() ;
320
- },
321
-
322
- /**
323
- Changes the targetTimecode to invert the direction of the animation.
324
- If the progress value is currently headed towards 1.0, it will be instead
325
- headed to 0.
326
-
327
- @returns {Number} the new progress
328
- */
329
- toggle: function() {
330
- throw "toggle not yet implemented" ;
331
- },
332
-
333
- /**
334
- The core action executed by the timer.
335
- */
336
- performAction: function() {
337
-
338
- // if timecodes match, then we suspend the animation and return, there
339
- // is nothing more to do.
340
- var cur = this.get('currentTimecode') ;
341
- var target = this.get('targetTimecode') ;
342
- if (cur == target) {
343
- this.set('isPaused', YES) ;
344
- return ;
345
- }
346
-
347
- // determine the amount of time that has elapsed since the last time
348
- // we were called.
349
- var curTime = SC.runLoop.get('startTime') ;
350
- var lapsed = (curTime - this._lastActionTime) * this.get('speed') ;
351
- this._lastActionTime = curTime ;
352
-
353
- // update the current timecode. Moving in the direction of the target
354
- // timecode. If timecodes match, there is nothing to do.
355
- if (target > cur) {
356
- cur += lapsed ;
357
- if (cur > target) cur = target ;
358
- } else {
359
- cur -= lapsed ;
360
- if (cur < target) cur = target ;
361
- }
362
-
363
- // now set the new timecode, this should trigger other observers to
364
- // update.
365
- this.set('currentTimecode', cur) ;
366
- },
367
-
368
- // ......................................
369
- // INTERNAL METHODS
370
- //
371
-
372
- /** @private
373
- Observes changes to repeatCount; updates the targetTimecode.
374
- */
375
- _repeatCountObserver: function() {
376
- var repeatCount = this.get('repeatCount') ;
377
- var target ;
378
- if (repeatCount < 0) {
379
- target = Date.now() * 2 ;
380
- } else if (repeatCount > 0) {
381
- target = this.get('duration') * repeatCount ;
382
- } else return ; // nothing to do.
383
- this.set('targetTimecode', target) ;
384
- }.observes('repeatCount'),
385
-
386
- /** @private
387
- Observes changes to the repeatDuration; updates the targetTimecode.
388
- */
389
- _repeatDurationObserver: function() {
390
- var dur = this.get('repeatDuration') ;
391
- if (dur < 0) {
392
- dur = Date.now() * 2 ;
393
- } else if (dur == 0) return; // nothing to do
394
- this.set('targetTimecode', dur) ;
395
- }.observes('repeatDuration'),
396
-
397
- init: function() {
398
- arguments.callee.base.call(this) ;
399
-
400
- this.targetTimecode = this.get('duration') ;
401
- this._repeatDurationObserver() ;
402
- this._repeatCountObserver() ;
403
- },
404
-
405
- repeats: YES, // for timer
406
-
407
- _logValueObserver: function() {
408
- console.log('value did change to: %@'.fmt(this.get('value')));
409
- }.observes('value')
410
-
411
- });