sproutcore 1.0.1042 → 1.0.1043

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION.yml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- :digest: 0d264600bbd6854ae2fca462e6ef64fb9ec9f114
2
+ :digest: 27241da4db9a4fd342f444b171b497ccb7272fe0
3
3
  :dist:
4
- frameworks/sproutcore: 77d6e1c493db4cc03be061890c3c53409523b534
4
+ frameworks/sproutcore: e9b957ac68b9adc9eb9cef27396eea85f3075553
5
5
  :major: 1
6
6
  :minor: 0
7
- :patch: 1042
7
+ :patch: 1043
@@ -13,7 +13,8 @@ function superTextile(s) {
13
13
  ['\\+', '\\+', 'ins'], //fixed
14
14
  ['~', '~', 'sub'],
15
15
  ['\\^', '\\^', 'sup'], // me
16
- ['{{{', '}}}', 'code']];
16
+ ['{{{', '}}}', 'code'],
17
+ ['@', '@', 'code']];
17
18
 
18
19
  for (var i=0;i<qtags.length;i++) {
19
20
  var ttag_o = qtags[i][0], ttag_c = qtags[i][1], htag = qtags[i][2];
@@ -26,7 +26,8 @@ h1.app-title img {
26
26
  }
27
27
 
28
28
  .sc-view.sc-toolbar-view.navigation-bar {
29
- border-bottom: 1px #999 solid;
29
+ border-top:0;
30
+ border-bottom: 1px #4D5567 solid;
30
31
  }
31
32
 
32
33
  .sc-label-view.center-label {
@@ -34,8 +35,12 @@ h1.app-title img {
34
35
  opacity: 0.8;
35
36
  filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80);
36
37
  -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)";
37
- -moz-opacity:0.8;
38
-
38
+ -moz-opacity:0.8;
39
+ }
40
+
41
+ .sc-view.sc-toolbar-view.bottom-toolbar {
42
+ z-index:2;
43
+ -webkit-box-shadow: none;
39
44
  }
40
45
 
41
46
  .sc-view.sc-toolbar-view .sc-checkbox-view {
@@ -62,6 +62,7 @@ TestRunner.mainPage = SC.Page.design({
62
62
  anchorLocation: SC.ANCHOR_BOTTOM,
63
63
 
64
64
  childViews: 'logo continuousIntegrationCheckbox runTestsButton'.w(),
65
+ classNames: 'bottom-toolbar',
65
66
 
66
67
  logo: SC.View.design({
67
68
  layout: { left: 0, top: 0, bottom: 0, width: 200 },
@@ -204,17 +205,17 @@ TestRunner.mainPage = SC.Page.design({
204
205
  navigationView: SC.ToolbarView.design({
205
206
  classNames: 'navigation-bar',
206
207
 
207
- layout: { top: -4, left: 0, right: 0, height: 28 },
208
+ layout: { top: 0, left: 0, right: 0, height: 32 },
208
209
  childViews: "backButton locationLabel".w(),
209
210
 
210
211
  backButton: SC.ButtonView.design({
211
- layout: { top: 5, left: 8, width: 80, height: 20 },
212
+ layout: { left: 8, centerY: 0, width: 80, height: 24 },
212
213
  title: "« Tests",
213
214
  action: "back"
214
215
  }),
215
216
 
216
217
  locationLabel: SC.LabelView.design({
217
- layout: { right: 8, top: 8, height: 18, left: 100 },
218
+ layout: { right: 8, centerY: -2, height: 16, left: 100 },
218
219
  textAlign: SC.ALIGN_RIGHT,
219
220
  valueBinding: "TestRunner.detailController.displayName"
220
221
  })
@@ -222,7 +223,7 @@ TestRunner.mainPage = SC.Page.design({
222
223
  }),
223
224
 
224
225
  webView: SC.WebView.design({
225
- layout: { top: 28, left: 2, right: 0, bottom: 0 },
226
+ layout: { top: 33, left: 2, right: 0, bottom: 0 },
226
227
  valueBinding: "TestRunner.detailController.uncachedUrl"
227
228
  })
228
229
  })
@@ -75,6 +75,9 @@ SC.Animatable = {
75
75
  // substitute our didUpdateLayer method (but saving the old one)
76
76
  this._animatable_original_did_update_layer = this.didUpdateLayer || function(){};
77
77
  this.didUpdateLayer = this._animatable_did_update_layer;
78
+
79
+ this._animatable_original_willRemoveFromParent = this.willRemoveFromParent || function(){};
80
+ this.willRemoveFromParent = this._animatable_will_remove_from_parent;
78
81
 
79
82
  // for debugging
80
83
  this._animateTickPixel.displayName = "animate-tick";
@@ -101,12 +104,20 @@ SC.Animatable = {
101
104
  }
102
105
 
103
106
  // live animators
107
+ this._animatableCurrentStyle = null;
104
108
  this._animators = {}; // keyAnimated => object describing it.
105
109
  this._animatableSetCSS = "";
106
110
  this._last_transition_css = ""; // to keep from re-setting unnecessarily
107
111
  this._disableAnimation = 0; // calls to disableAnimation add one; enableAnimation remove one.
108
112
  },
109
113
 
114
+ /**
115
+ Stops all animations on the layer when this occurs by calling resetAnimation.
116
+ */
117
+ _animatable_will_remove_from_parent: function() {
118
+ this.resetAnimation();
119
+ },
120
+
110
121
  /**
111
122
  Disables animation.
112
123
 
@@ -114,12 +125,17 @@ SC.Animatable = {
114
125
  If you call disable twice, you need two enables to start it. Three times, you need
115
126
  three enables.
116
127
  */
117
- disableAnimation: function() { this._disableAnimation++; },
128
+ disableAnimation: function() {
129
+ this._disableAnimation++;
130
+ },
118
131
 
119
132
  /**
120
133
  Enables animation if it was disabled (or moves towards that direction, at least).
121
134
  */
122
- enableAnimation: function() { this._disableAnimation--; if (this._disableAnimation < 0) this._disableAnimation = 0; },
135
+ enableAnimation: function() {
136
+ this._disableAnimation--;
137
+ if (this._disableAnimation < 0) this._disableAnimation = 0;
138
+ },
123
139
 
124
140
  /**
125
141
  Adds support for some style properties to adjust.
@@ -175,17 +191,40 @@ SC.Animatable = {
175
191
  // call base with whatever is leftover
176
192
  return this;
177
193
  },
178
-
194
+
179
195
  /**
180
- Resets animation so that next manipulation of style will not animate.
196
+ Returns the current set of styles and layout according to JavaScript transitions.
197
+
198
+ That is, for transitions managed by JavaScript (rather than CSS), the current position
199
+ (even mid-transition) will be returned. For CSS-based transitions, the target position
200
+ will be returned. This function is mostly useful for testing.
201
+
202
+ It will return null if there is no such style.
203
+ */
204
+ getCurrentJavaScriptStyles: function() {
205
+ return this._animatableCurrentStyle
206
+ },
181
207
 
182
- Currently does not stop existing animations, so won't work very well
183
- if there are any (will actually stutter).
208
+ /**
209
+ Resets animation, stopping all existing animations.
184
210
  */
185
- resetAnimation: function()
186
- {
187
- this._animatableCurrentStyle = this.style;
211
+ resetAnimation: function() {
212
+ this._animatableCurrentStyle = null;
213
+ this._stopJavaScriptAnimations();
214
+ this.disableAnimation();
188
215
  this.updateStyle();
216
+ this.enableAnimation();
217
+ },
218
+
219
+ /**
220
+ Stops all JavaScript animations on the object. In their tracks. Hah hah.
221
+ */
222
+ _stopJavaScriptAnimations: function() {
223
+ for (var i in this._animators) {
224
+ if (this._animators[i] && this._animators[i].isQueued) {
225
+ SC.Animatable.removeTimer(this._animators[i]);
226
+ }
227
+ }
189
228
  },
190
229
 
191
230
  _getStartStyleHash: function(start, target)
@@ -196,6 +235,7 @@ SC.Animatable = {
196
235
  this.layout = start;
197
236
 
198
237
  // get our frame and parent's frame
238
+ this.notifyPropertyChange("layout");
199
239
  var f = this.get("frame");
200
240
  var p = this.getPath("layoutView.frame");
201
241
 
@@ -211,7 +251,7 @@ SC.Animatable = {
211
251
  if (f)
212
252
  {
213
253
  if (i == "left") { l[i] = f.x; continue; }
214
- else if (i == " top") { l[i] = f.y; continue; }
254
+ else if (i == "top") { l[i] = f.y; continue; }
215
255
  else if (i == "right") { l[i] = p.width - f.x - f.width; continue; }
216
256
  else if (i == "bottom") { l[i] = p.height - f.y - f.height; continue; }
217
257
  else if (i == "width") { l[i] = f.width; continue; }
@@ -248,7 +288,7 @@ SC.Animatable = {
248
288
  // make sure there _is_ a previous style to animate from. Otherwise,
249
289
  // we don't animate—and this is sometimes used to temporarily disable animation.
250
290
  var i;
251
- if (!this._animatableCurrentStyle || this._disableAnimation > 0)
291
+ if (!this._animatableCurrentStyle || this._disableAnimation > 0 || !layer)
252
292
  {
253
293
  // clone it to be a nice starting point next time.
254
294
  this._animatableCurrentStyle = {};
@@ -430,7 +470,7 @@ SC.Animatable = {
430
470
  _animatableApplyStyles: function(layer, styles)
431
471
  {
432
472
  if (!layer) return;
433
-
473
+
434
474
  // handle a specific style first: display. There is a special case because it disrupts transitions.
435
475
  if (styles["display"]) {
436
476
  layer.style["display"] = styles["display"];
@@ -447,23 +487,21 @@ SC.Animatable = {
447
487
 
448
488
  // get timer
449
489
  var timer = this._animators["display-styles"];
450
-
451
- // fire if there is already a pending one
452
- if (timer.isQueued) {
453
- // timer.action.call(timer, 0);
454
- }
455
-
490
+
491
+ // set settings
456
492
  timer.holder = this;
457
493
  timer.action = this._animatableApplyNonDisplayStyles;
458
494
  timer.layer = layer;
459
495
  timer.styles = styles;
460
496
  this._animatableCurrentStyle = styles;
497
+
498
+ // schedule.
461
499
  SC.Animatable.addTimer(timer);
462
500
  },
463
501
 
464
502
  _animatableApplyNonDisplayStyles: function(){
465
503
  var loop = SC.RunLoop.begin();
466
- var layer = this.layer, styles = this.styles;
504
+ var layer = this.layer, styles = this.styles; // this == timer
467
505
  var styleHelpers = {
468
506
  opacity: this.holder._style_opacity_helper
469
507
  // more to be added here...
@@ -495,7 +533,7 @@ SC.Animatable = {
495
533
  // apply the styles (but we have to mix it in, because we still have transitions, etc. that we set)
496
534
  var ls = this.holder.get("layoutStyle");
497
535
  for (var key in ls) {
498
- if (SC.none(ls[key])) delete style[key];
536
+ if (SC.none(ls[key])) style[key] = ""; // because IE is stupid and can't handle delete or null
499
537
  else if (style[key] != ls[key]) style[key] = ls[key];
500
538
  }
501
539
 
@@ -511,17 +549,20 @@ SC.Animatable = {
511
549
  _animatable_did_update_layer: function()
512
550
  {
513
551
  this._animatable_original_did_update_layer();
514
- var styles = this._animatableCurrentStyle || (this.get("style") || {}), layer = this.get("layer");
552
+ var styles = this._animatableCurrentStyle, layer = this.get("layer");
553
+ if (!styles) {
554
+ styles = {};
555
+ var s = this.get("style");
556
+ var l = this.get("layout");
557
+ SC.mixin(styles, s, l);
558
+ }
515
559
  this._animatableApplyStyles(layer, styles);
516
560
  },
517
561
 
518
562
  /**
519
563
  Overriden to support animation.
520
564
 
521
- Works by keeping a copy of the current layout, called animatableCurrentLayout.
522
- Whenever the layout needs updating, the old layout is consulted.
523
-
524
- "layout" is kept at the new layout
565
+ Works by copying the styles to the object's "style" property.
525
566
  */
526
567
  updateLayout: function(context, firstTime)
527
568
  {
@@ -533,7 +574,7 @@ SC.Animatable = {
533
574
  var key = ls[i];
534
575
  if (style[key] !== newLayout[key])
535
576
  {
536
- if (SC.none(newLayout[key])) delete style[key];
577
+ if (SC.none(newLayout[key])) style[key] = ""; // because IE is stupid and can't handle delete or debug.
537
578
  else style[key] = newLayout[key];
538
579
  didChange = YES;
539
580
  }
@@ -796,7 +837,7 @@ SC.mixin(SC.Animatable, {
796
837
  TRANSITION_CSS_EASE: "ease",
797
838
  TRANSITION_CSS_EASE_IN: "ease-in",
798
839
  TRANSITION_CSS_EASE_OUT: "ease-out",
799
- TRANSITION_CSS_EASE_OUT: "ease-in-out",
840
+ TRANSITION_CSS_EASE_IN_OUT: "ease-in-out",
800
841
 
801
842
  // JavaScript-enabled
802
843
  TRANSITION_EASE: [0.25, 0.1, 0.25, 1.0],
@@ -833,14 +874,22 @@ SC.mixin(SC.Animatable, {
833
874
  lastFPS: 0
834
875
  }),
835
876
 
836
- addTimer: function(animator)
837
- {
877
+ addTimer: function(animator) {
838
878
  if (animator.isQueued) return;
879
+ animator.prev = SC.Animatable.baseTimer;
839
880
  animator.next = SC.Animatable.baseTimer.next;
840
- SC.Animatable.baseTimer.next = animator;
881
+ if (SC.Animatable.baseTimer.next) SC.Animatable.baseTimer.next.prev = animator; // adjust next prev.
882
+ SC.Animatable.baseTimer.next = animator; // switcheroo.
841
883
  animator.isQueued = true;
842
884
  if (!SC.Animatable.going) SC.Animatable.start();
843
885
  },
886
+
887
+ removeTimer: function(animator) {
888
+ if (!animator.isQueued) return;
889
+ if (animator.next) animator.next.prev = animator.prev; // splice ;)
890
+ animator.prev.next = animator.next; // it should always have a prev.
891
+ animator.isQueued = false;
892
+ },
844
893
 
845
894
  start: function()
846
895
  {
@@ -865,6 +914,7 @@ SC.mixin(SC.Animatable, {
865
914
  var t = next.next;
866
915
  next.isQueued = false;
867
916
  next.next = null;
917
+ next.prev = null;
868
918
  next.action.call(next, start);
869
919
  next = t;
870
920
  i++;
@@ -8,10 +8,12 @@ module("Animatable", {
8
8
  setup: function() {
9
9
  view = SC.View.create(SC.Animatable, {
10
10
  layout: { left: 100, top: 100, height: 100, width: 100 },
11
+ style: { opacity: .5 },
11
12
  transitions: {
12
13
  left: 0.25,
13
14
  top: { duration: 0.35 },
14
- width: { duration: 0.2, timing: SC.Animatable.TRANSITION_EASE_IN_OUT }
15
+ width: { duration: 0.2, timing: SC.Animatable.TRANSITION_EASE_IN_OUT },
16
+ style: { opacity: 1 }
15
17
  }
16
18
  });
17
19
 
@@ -63,3 +65,26 @@ test("animatable should handle concatenated transitions properly", function(){
63
65
  equals(width["timing"], SC.Animatable.TRANSITION_EASE_IN_OUT, "SC.Animatable.TRANSITION_EASE_IN_OUT for width.");
64
66
  });
65
67
 
68
+ test("animatable handler for layer update should ensure both layout and styles are set in the 'current style'.", function() {
69
+ var original_transition_enabled = SC.Animatable.enableCSSTransitions;
70
+ SC.Animatable.enableCSSTransitions = NO;
71
+
72
+ // check current style (should be none yet)
73
+ var current = view.getCurrentJavaScriptStyles();
74
+ equals(current, null, "There should be no current style yet.");
75
+
76
+ // create the layer
77
+ view.createLayer();
78
+ view.updateLayer();
79
+
80
+ // check again. Now, we should have a style
81
+ current = view.getCurrentJavaScriptStyles();
82
+ ok(!SC.none(current), "There now SHOULD be a current JS style.");
83
+
84
+ // and now, make sure we have both style AND layout set properly.
85
+ equals(current["opacity"], .5, "opacity should be .5");
86
+ equals(current["left"], 100, "left should be 100");
87
+
88
+ // go back to the beginning
89
+ SC.Animatable.enableCSSTransitions = original_transition_enabled;
90
+ });
@@ -1683,6 +1683,52 @@ SC.Store = SC.Object.extend( /** @scope SC.Store.prototype */ {
1683
1683
  array.length = 0 ;
1684
1684
  return this;
1685
1685
  },
1686
+
1687
+ /**
1688
+ Convenience method can be called by the store or other parts of your
1689
+ application to load a record into the store. This method will take a
1690
+ recordType and a data hashes and either add or update the
1691
+ record in the store.
1692
+
1693
+ The loaded records will be in an SC.Record.READY_CLEAN state, indicating
1694
+ they were loaded from the data source and do not need to be committed
1695
+ back before changing.
1696
+
1697
+ This method will check the state of the storeKey and call either
1698
+ pushRetrieve() or dataSourceDidComplete(). The standard state constraints
1699
+ for these methods apply here.
1700
+
1701
+ The return value will be the storeKey used for the push. This is often
1702
+ convenient to pass into loadQuery(), if you are fetching a remote query.
1703
+
1704
+ If you are upgrading from a pre SproutCore 1.0 application, this method
1705
+ is the closest to the old updateRecord().
1706
+
1707
+ @param {SC.Record} recordType the record type
1708
+ @param {Array} dataHash to update
1709
+ @param {Array} id optional. if not passed lookup on the hash
1710
+ @returns {String} store keys assigned to these id
1711
+ */
1712
+ loadRecord: function(recordType, dataHash, id) {
1713
+ var K = SC.Record,
1714
+ ret, primaryKey, dataHash, storeKey;
1715
+
1716
+ // save lookup info
1717
+ recordType = recordType || SC.Record;
1718
+ primaryKey = recordType.prototype.primaryKey;
1719
+
1720
+
1721
+ // push each record
1722
+ id = id || dataHash[primaryKey];
1723
+ ret = storeKey = recordType.storeKeyFor(id); // needed to cache
1724
+
1725
+ if (this.readStatus(storeKey) & K.BUSY) {
1726
+ this.dataSourceDidComplete(storeKey, dataHash, id);
1727
+ } else this.pushRetrieve(recordType, id, dataHash, storeKey);
1728
+
1729
+ // return storeKey
1730
+ return ret ;
1731
+ },
1686
1732
 
1687
1733
  /**
1688
1734
  Convenience method can be called by the store or other parts of your
@@ -1730,11 +1776,8 @@ SC.Store = SC.Object.extend( /** @scope SC.Store.prototype */ {
1730
1776
  primaryKey = recordType.prototype.primaryKey ;
1731
1777
  }
1732
1778
  id = (ids) ? ids.objectAt(idx) : dataHash[primaryKey];
1733
- ret[idx] = storeKey = recordType.storeKeyFor(id); // needed to cache
1779
+ ret[idx] = this.loadRecord(recordType, dataHash, id);
1734
1780
 
1735
- if (this.readStatus(storeKey) & K.BUSY) {
1736
- this.dataSourceDidComplete(storeKey, dataHash, id);
1737
- } else this.pushRetrieve(recordType, id, dataHash, storeKey);
1738
1781
  }
1739
1782
 
1740
1783
  // return storeKeys
@@ -1,6 +1,5 @@
1
1
  /* SC.ToolbarView */
2
2
 
3
3
  .sc-toolbar-view {
4
- border-top: 1px #999 solid;
5
4
  background-color: #ddd ;
6
5
  }
@@ -168,6 +168,7 @@ SC.Button = {
168
168
  // get the icon. If there is an icon, then get the image and update it.
169
169
  // if there is no image element yet, create it and insert it just before
170
170
  // title.
171
+
171
172
  if (icon) {
172
173
  var blank = SC.BLANK_IMAGE_URL;
173
174
 
@@ -192,10 +193,16 @@ SC.Button = {
192
193
  if(needsTitle) {
193
194
  if(this.get('needsEllipsis')){
194
195
  elem.addClass('ellipsis');
195
- if(this._ImageTitleCached !== imgTitle) htmlNode.innerHTML = imgTitle;
196
+ if(this._ImageTitleCached !== imgTitle) {
197
+ this._ImageTitleCached = imgTitle; // Update the cache
198
+ htmlNode.innerHTML = imgTitle;
199
+ }
196
200
  }else{
197
201
  elem.removeClass('ellipsis');
198
- if(this._ImageTitleCached !== imgTitle) htmlNode.innerHTML = imgTitle;
202
+ if(this._ImageTitleCached !== imgTitle) {
203
+ this._ImageTitleCached = imgTitle; // Update the cache
204
+ htmlNode.innerHTML = imgTitle;
205
+ }
199
206
  }
200
207
  }
201
208
  else { htmlNode.innerHTML = ''; }