sproutcore 1.0.1042 → 1.0.1043

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.
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 = ''; }