sproutcore 0.9.14 → 0.9.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/History.txt +43 -0
  2. data/Manifest.txt +12 -3
  3. data/bin/sc-build +19 -3
  4. data/bin/sc-install +5 -0
  5. data/bin/sc-remove +5 -0
  6. data/bin/sc-update +5 -0
  7. data/frameworks/prototype/prototype.js +267 -230
  8. data/frameworks/sproutcore/HISTORY +281 -135
  9. data/frameworks/sproutcore/controllers/array.js +133 -22
  10. data/frameworks/sproutcore/controllers/collection.js +4 -5
  11. data/frameworks/sproutcore/controllers/object.js +8 -2
  12. data/frameworks/sproutcore/core.js +361 -159
  13. data/frameworks/sproutcore/{foundation → debug}/unittest.js +3 -3
  14. data/frameworks/sproutcore/english.lproj/detect-browser +1 -1
  15. data/frameworks/sproutcore/english.lproj/theme.css +2 -2
  16. data/frameworks/sproutcore/foundation/application.js +6 -1
  17. data/frameworks/sproutcore/foundation/benchmark.js +37 -11
  18. data/frameworks/sproutcore/foundation/date.js +1 -1
  19. data/frameworks/sproutcore/foundation/enumerator.js +105 -0
  20. data/frameworks/sproutcore/foundation/object.js +19 -20
  21. data/frameworks/sproutcore/foundation/responder.js +1 -1
  22. data/frameworks/sproutcore/foundation/set.js +164 -57
  23. data/frameworks/sproutcore/foundation/string.js +151 -47
  24. data/frameworks/sproutcore/foundation/utils.js +84 -3
  25. data/frameworks/sproutcore/lib/collection_view.rb +1 -0
  26. data/frameworks/sproutcore/license.js +28 -0
  27. data/frameworks/sproutcore/mixins/array.js +73 -209
  28. data/frameworks/sproutcore/mixins/delegate_support.js +1 -1
  29. data/frameworks/sproutcore/mixins/enumerable.js +1006 -0
  30. data/frameworks/sproutcore/mixins/observable.js +153 -84
  31. data/frameworks/sproutcore/mixins/selection_support.js +13 -1
  32. data/frameworks/sproutcore/models/record.js +74 -27
  33. data/frameworks/sproutcore/models/store.js +7 -3
  34. data/frameworks/sproutcore/server/rails_server.js +82 -0
  35. data/frameworks/sproutcore/server/rest_server.js +178 -0
  36. data/frameworks/sproutcore/{foundation → server}/server.js +101 -48
  37. data/frameworks/sproutcore/tests/core/guidFor.rhtml +114 -0
  38. data/frameworks/sproutcore/tests/foundation/array.rhtml +6 -7
  39. data/frameworks/sproutcore/tests/foundation/set.rhtml +254 -0
  40. data/frameworks/sproutcore/tests/mixins/enumerable.rhtml +421 -0
  41. data/frameworks/sproutcore/tests/mixins/observable.rhtml +127 -0
  42. data/frameworks/sproutcore/tests/models/model.rhtml +23 -22
  43. data/frameworks/sproutcore/tests/views/collection/incremental_rendering.rhtml +2 -2
  44. data/frameworks/sproutcore/tests/views/view/clippingFrame.rhtml +112 -109
  45. data/frameworks/sproutcore/tests/views/view/frame.rhtml +91 -88
  46. data/frameworks/sproutcore/validators/date.js +1 -7
  47. data/frameworks/sproutcore/views/collection/collection.js +7 -2
  48. data/frameworks/sproutcore/views/list_item.js +141 -3
  49. data/frameworks/sproutcore/views/split.js +14 -11
  50. data/frameworks/sproutcore/views/view.js +9 -6
  51. data/lib/sproutcore/build_tools/html_builder.rb +19 -3
  52. data/lib/sproutcore/build_tools/resource_builder.rb +9 -3
  53. data/lib/sproutcore/bundle.rb +21 -0
  54. data/lib/sproutcore/bundle_manifest.rb +64 -20
  55. data/lib/sproutcore/helpers/capture_helper.rb +2 -2
  56. data/lib/sproutcore/library.rb +33 -9
  57. data/lib/sproutcore/merb/bundle_controller.rb +16 -5
  58. data/lib/sproutcore/version.rb +1 -1
  59. data/lib/sproutcore/view_helpers.rb +1 -1
  60. data/{sc-config.rb → sc-config} +5 -2
  61. metadata +24 -5
@@ -0,0 +1,127 @@
1
+ <% content_for('final') do %>
2
+ <script>
3
+
4
+ Test.context("object.get()", {
5
+
6
+ setup: function() {
7
+ object = SC.Object.create({
8
+
9
+ normal: 'value',
10
+
11
+ computed: function() { return 'value'; }.property(),
12
+
13
+ method: function() { return "value"; },
14
+
15
+ nullProperty: null,
16
+
17
+ unknownProperty: function(key, value) {
18
+ this.lastUnknownProperty = key ;
19
+ return "unknown" ;
20
+ }
21
+
22
+ }) ;
23
+ },
24
+
25
+ "should get normal properties": function() {
26
+ assertEqual(object.get('normal'), 'value') ;
27
+ },
28
+
29
+ "should call computed properties and return their result": function() {
30
+ assertEqual(object.get("computed"), "value") ;
31
+ },
32
+
33
+ "should return the function for a non-computed property": function() {
34
+ var value = object.get("method") ;
35
+ assertEqual($type(value), T_FUNCTION) ;
36
+ },
37
+
38
+ "should return null when property value is null": function() {
39
+ assertEqual(object.get("nullProperty"), null);
40
+ },
41
+
42
+ "should call unknownProperty when value is undefined": function() {
43
+ assertEqual(object.get("unknown"), "unknown") ;
44
+ assertEqual(object.lastUnknownProperty, "unknown") ;
45
+ }
46
+
47
+ });
48
+
49
+ Test.context("object.set()", {
50
+
51
+ setup: function() {
52
+ object = SC.Object.create({
53
+
54
+ // normal property
55
+ normal: 'value',
56
+
57
+ // computed property
58
+ _computed: "computed",
59
+ computed: function(key, value) {
60
+ if (value !== undefined) {
61
+ this._computed = value ;
62
+ }
63
+ return this._computed ;
64
+ }.property(),
65
+
66
+ // method, but not a property
67
+ _method: "method",
68
+ method: function(key, value) {
69
+ if (value !== undefined) {
70
+ this._method = value ;
71
+ }
72
+ return this._method ;
73
+ },
74
+
75
+ // null property
76
+ nullProperty: null,
77
+
78
+ // unknown property
79
+ _unknown: 'unknown',
80
+ unknownProperty: function(key, value) {
81
+ if (value !== undefined) {
82
+ this._unknown = value ;
83
+ }
84
+ return this._unknown ;
85
+ }
86
+
87
+ }) ;
88
+ },
89
+
90
+ "should change normal properties and return this": function() {
91
+ var ret = object.set("normal", "changed") ;
92
+ assertEqual(object.normal, "changed") ;
93
+ assertEqual(ret, object) ;
94
+ },
95
+
96
+ "should call computed properties passing value and return this": function() {
97
+ var ret = object.set("computed", "changed") ;
98
+ assertEqual(object._computed, "changed") ;
99
+ assertEqual($type(object.computed), T_FUNCTION) ;
100
+ assertEqual(ret, object) ;
101
+ },
102
+
103
+ "should replace the function for a non-computed property and return this": function() {
104
+ var ret = object.set("method", "changed") ;
105
+ assertEqual(object._method, "method") ; // make sure this was NOT run
106
+ assertNotEqual($type(object.method), T_FUNCTION) ;
107
+ assertEqual(ret, object) ;
108
+ },
109
+
110
+ "should replace prover when property value is null": function() {
111
+ var ret = object.set("nullProperty", "changed") ;
112
+ assertEqual(object.nullProperty, "changed") ;
113
+ assertEqual(object._unknown, "unknown"); // verify unknownProperty not called.
114
+ assertEqual(ret, object) ;
115
+ },
116
+
117
+ "should call unknownProperty with value when property is undefined": function() {
118
+ var ret = object.set("unknown", "changed") ;
119
+ assertEqual(object._unknown, "changed") ;
120
+ assertEqual(ret, object) ;
121
+ }
122
+
123
+ });
124
+
125
+
126
+ </script>
127
+ <% end %>
@@ -22,34 +22,34 @@ ModelTest = SC.Object.create({
22
22
  //
23
23
  ModelTest.FIXTURES = ModelTest.FIXTURES.concat([
24
24
 
25
- { guid: 1,
25
+ { guid: '1',
26
26
  type: 'Todo',
27
27
  name: "Something to do",
28
- todoList: 1 // the guid of the todo list object this todo is related to
28
+ todoList: '1' // the guid of the todo list object this todo is related to
29
29
  },
30
30
 
31
- { guid: 2,
31
+ { guid: '2',
32
32
  type: 'Todo',
33
33
  name: "Something else to do",
34
- todoList: 1
34
+ todoList: '1'
35
35
  },
36
36
 
37
- { guid: 3,
37
+ { guid: '3',
38
38
  type: 'Todo',
39
39
  name: "Gee, I'm busy.",
40
- todoList: 2
40
+ todoList: '2'
41
41
  }
42
42
 
43
43
  ]);
44
44
 
45
45
  ModelTest.FIXTURES = ModelTest.FIXTURES.concat([
46
46
 
47
- { guid: 1,
47
+ { guid: '1',
48
48
  type: 'TodoList',
49
49
  name: "My List"
50
50
  },
51
51
 
52
- { guid: 2,
52
+ { guid: '2',
53
53
  type: 'TodoList',
54
54
  name: "My List 2"
55
55
  }
@@ -80,11 +80,11 @@ Test.context("Test model comparisons with numeric guids", {
80
80
 
81
81
  setup: function()
82
82
  {
83
- this.todoList1 = ModelTest.TodoList.find(1);
84
- this.todoList2 = ModelTest.TodoList.find(2);
85
- this.todo1 = ModelTest.Todo.find(1);
86
- this.todo2 = ModelTest.Todo.find(2);
87
- this.todo3 = ModelTest.Todo.find(3);
83
+ this.todoList1 = ModelTest.TodoList.find('1');
84
+ this.todoList2 = ModelTest.TodoList.find('2');
85
+ this.todo1 = ModelTest.Todo.find('1');
86
+ this.todo2 = ModelTest.Todo.find('2');
87
+ this.todo3 = ModelTest.Todo.find('3');
88
88
  },
89
89
 
90
90
  teardown: function()
@@ -258,16 +258,17 @@ Test.context("Test model comparisons with string guids", {
258
258
 
259
259
  setup: function()
260
260
  {
261
- this.todoList1 = ModelTest2.TodoList.find(1);
262
- this.todoList2 = ModelTest2.TodoList.find(2);
263
- this.todo1 = ModelTest2.Todo.find(1);
264
- this.todo2 = ModelTest2.Todo.find(2);
265
- this.todo3 = ModelTest2.Todo.find(3);
261
+ this.todoList1 = ModelTest2.TodoList.find('1');
262
+ this.todoList2 = ModelTest2.TodoList.find('2');
263
+ this.todo1 = ModelTest2.Todo.find('1');
264
+ this.todo2 = ModelTest2.Todo.find('2');
265
+ this.todo3 = ModelTest2.Todo.find('3');
266
266
  },
267
267
 
268
268
  teardown: function()
269
269
  {
270
- delete this.todoList;
270
+ delete this.todoList1;
271
+ delete this.todoList2;
271
272
  delete this.todo1;
272
273
  delete this.todo2;
273
274
  },
@@ -286,17 +287,17 @@ Test.context("Test model comparisons with string guids", {
286
287
  assertIdentical(this.todoList1, this.todo1.get('todoList'));
287
288
  assertIdentical(this.todoList1, this.todo2.get('todoList'));
288
289
  },
289
-
290
+
290
291
  "Todo 3 should not be related to TodoList 1": function()
291
292
  {
292
293
  assertNotIdentical(this.todoList1, this.todo3.get('todoList'));
293
294
  },
294
-
295
+
295
296
  "Todo 3 should be related to TodoList 2": function()
296
297
  {
297
298
  assertIdentical(this.todoList2, this.todo3.get('todoList'));
298
299
  },
299
-
300
+
300
301
  "Todo 1 and 2 should not be related to TodoList 2": function()
301
302
  {
302
303
  assertNotIdentical(this.todoList2, this.todo1.get('todoList'));
@@ -155,7 +155,7 @@ Test.context("CASE 3: Autoscrolling, no incremental rendering, no custom layout"
155
155
  }),
156
156
 
157
157
  init: function() {
158
- sc_super() ;
158
+ arguments.callee.base.apply(this) ;
159
159
  this.setStyle({ overflow: "auto", height: '200px' }) ;
160
160
  }
161
161
  }) ;
@@ -198,7 +198,7 @@ Test.context("CASE 4: Autoscrolling, no incremental rendering, custom layout",
198
198
  },
199
199
 
200
200
  init: function() {
201
- sc_super() ;
201
+ arguments.callee.base.apply(this) ;
202
202
  this.setStyle({ overflow: "auto", height: '200px' }) ;
203
203
  }
204
204
 
@@ -67,6 +67,7 @@ Test.context("CASE 2: A scrollable view - child view cannot fit within visible a
67
67
  "clippingFrame should reflect only the visible portion of the view": function() {
68
68
  var v = this.v.child ;
69
69
  var cf = v.get('clippingFrame') ;
70
+
70
71
  var f = v.get('frame') ;
71
72
  f.height = VIEW_HEIGHT ;
72
73
 
@@ -75,98 +76,98 @@ Test.context("CASE 2: A scrollable view - child view cannot fit within visible a
75
76
  SC.rectsEqual(f,cf).shouldEqual(true) ;
76
77
  },
77
78
 
78
- "scrolling parent frame should change child clippingFrame (and notify)": function() {
79
- var child = this.v.child ;
80
- var cf = child.get('clippingFrame') ;
79
+ "scrolling parent frame should change child clippingFrame (and notify)": function() {
80
+ var child = this.v.child ;
81
+ var cf = child.get('clippingFrame') ;
82
+
83
+ var didChange = false ;
84
+ child.addObserver('clippingFrame', function() { didChange = true; }) ;
85
+
86
+ // scroll
87
+ this.v.set('scrollFrame', { y: -20 }) ;
81
88
 
82
- var didChange = false ;
83
- child.addObserver('clippingFrame', function() { didChange = true; }) ;
89
+ var ncf = child.get('clippingFrame') ;
90
+ cf.y = 20 ; // adjust expected frame
84
91
 
85
- // scroll
86
- this.v.set('scrollFrame', { y: -20 }) ;
87
-
88
- var ncf = child.get('clippingFrame') ;
89
- cf.y = 20 ; // adjust expected frame
90
-
91
- SC.rectsEqual(ncf, cf).shouldEqual(true) ;
92
- didChange.shouldEqual(true) ;
93
-
94
- this.v.set('scrollFrame', { y: 0 }) ;
95
- },
96
-
97
- "resizing parent frame should change child clippingFrame (and notify)": function() {
98
- var child = this.v.child ;
99
- var cf = child.get('clippingFrame') ;
92
+ SC.rectsEqual(ncf, cf).shouldEqual(true) ;
93
+ didChange.shouldEqual(true) ;
100
94
 
101
- var didChange = false ;
102
- child.addObserver('clippingFrame', function() { didChange = true; }) ;
103
-
104
- // scroll
105
- this.v.set('frame', { height: 50 }) ;
106
-
107
- var ncf = child.get('clippingFrame') ;
108
- cf.height = 48 ; // adjust expected frame
109
-
110
- SC.rectsEqual(ncf, cf).shouldEqual(true) ;
111
- didChange.shouldEqual(true) ;
112
-
113
- this.v.set('frame', { height: 90 }) ;
114
- },
115
-
116
- "resizing child should change clippingFrame (and notify)": function() {
117
- var child = this.v.child ;
118
- var cf = child.get('clippingFrame') ;
95
+ this.v.set('scrollFrame', { y: 0 }) ;
96
+ },
119
97
 
120
- var didChange = false ;
121
- child.addObserver('clippingFrame', function() { didChange = true; }) ;
122
-
123
- // scroll
124
- child.set('frame', { height: 50 }) ;
125
-
126
- var ncf = child.get('clippingFrame') ;
127
- cf.height = 50 ; // adjust expected frame
128
-
129
- SC.rectsEqual(ncf, cf).shouldEqual(true) ;
130
- didChange.shouldEqual(true) ;
98
+ "resizing parent frame should change child clippingFrame (and notify)": function() {
99
+ var child = this.v.child ;
100
+ var cf = child.get('clippingFrame') ;
101
+
102
+ var didChange = false ;
103
+ child.addObserver('clippingFrame', function() { didChange = true; }) ;
131
104
 
132
- // reset
133
- child.set('frame', { height: 152 }) ;
134
- },
135
-
136
- "moving child should change clipping frame (and notify)": function() {
137
- var child = this.v.child ;
138
- var cf = child.get('clippingFrame') ;
105
+ // scroll
106
+ this.v.set('frame', { height: 50 }) ;
139
107
 
140
- var didChange = false ;
141
- child.addObserver('clippingFrame', function() { didChange = true; }) ;
142
-
143
- // scroll
144
- child.set('frame', { y: 20 }) ;
145
-
146
- var ncf = child.get('clippingFrame') ;
147
- cf.y = 20; cf.height -= 20 ; // adjust expected frame
148
-
149
- SC.rectsEqual(ncf, cf).shouldEqual(true) ;
150
- didChange.shouldEqual(true) ;
108
+ var ncf = child.get('clippingFrame') ;
109
+ cf.height = 48 ; // adjust expected frame
151
110
 
152
- // reset
153
- child.set('frame', { y: 0 }) ;
154
- },
155
-
156
- "moving parent should NOT change child clipping frame": function() {
157
- var child = this.v.child ;
158
- var cf = child.get('clippingFrame') ;
159
-
160
- // move parent frame -- make sure this does not exceed the parent or
161
- // else the clipping frame will be miscalculated.
162
- this.v.set('frame', { y: 5 }) ;
163
-
164
- var ncf = child.get('clippingFrame') ;
165
- SC.rectsEqual(ncf, cf).shouldEqual(true) ;
111
+ SC.rectsEqual(ncf, cf).shouldEqual(true) ;
112
+ didChange.shouldEqual(true) ;
166
113
 
167
- // reset
168
- this.v.set('frame', { y: 0 }) ;
169
- },
114
+ this.v.set('frame', { height: 90 }) ;
115
+ },
116
+
117
+ "resizing child should change clippingFrame (and notify)": function() {
118
+ var child = this.v.child ;
119
+ var cf = child.get('clippingFrame') ;
120
+
121
+ var didChange = false ;
122
+ child.addObserver('clippingFrame', function() { didChange = true; }) ;
123
+
124
+ // scroll
125
+ child.set('frame', { height: 50 }) ;
126
+
127
+ var ncf = child.get('clippingFrame') ;
128
+ cf.height = 50 ; // adjust expected frame
129
+
130
+ SC.rectsEqual(ncf, cf).shouldEqual(true) ;
131
+ didChange.shouldEqual(true) ;
132
+
133
+ // reset
134
+ child.set('frame', { height: 152 }) ;
135
+ },
136
+
137
+ "moving child should change clipping frame (and notify)": function() {
138
+ var child = this.v.child ;
139
+ var cf = child.get('clippingFrame') ;
140
+
141
+ var didChange = false ;
142
+ child.addObserver('clippingFrame', function() { didChange = true; }) ;
143
+
144
+ // scroll
145
+ child.set('frame', { y: 20 }) ;
146
+
147
+ var ncf = child.get('clippingFrame') ;
148
+ cf.y = 20; cf.height -= 20 ; // adjust expected frame
149
+
150
+ SC.rectsEqual(ncf, cf).shouldEqual(true) ;
151
+ didChange.shouldEqual(true) ;
152
+
153
+ // reset
154
+ child.set('frame', { y: 0 }) ;
155
+ },
156
+
157
+ "moving parent should NOT change child clipping frame": function() {
158
+ var child = this.v.child ;
159
+ var cf = child.get('clippingFrame') ;
160
+
161
+ // move parent frame -- make sure this does not exceed the parent or
162
+ // else the clipping frame will be miscalculated.
163
+ this.v.set('frame', { y: 5 }) ;
164
+
165
+ var ncf = child.get('clippingFrame') ;
166
+ SC.rectsEqual(ncf, cf).shouldEqual(true) ;
167
+
168
+ // reset
169
+ this.v.set('frame', { y: 0 }) ;
170
+ },
170
171
 
171
172
  setup: function() { this.v = SC.page.get('case2'); }
172
173
 
@@ -175,12 +176,12 @@ Test.context("CASE 2: A scrollable view - child view cannot fit within visible a
175
176
  Test.context("CASE 3: A scrollable view with extra height - nested child view can fit within visible area", {
176
177
 
177
178
  "clippingFrame should == frame when view is entirely visible": function() {
178
-
179
- var f = nested.get('frame') ;
180
- var cf = nested.get('clippingFrame') ;
181
- console.log('%@: f=%@ -- cf=%@'.fmt(nested, $I(f), $I(cf)));
182
- SC.rectsEqual(f,cf).shouldEqual(true) ;
183
- },
179
+
180
+ var f = nested.get('frame') ;
181
+ var cf = nested.get('clippingFrame') ;
182
+ console.log('%@: f=%@ -- cf=%@'.fmt(nested, $I(f), $I(cf)));
183
+ SC.rectsEqual(f,cf).shouldEqual(true) ;
184
+ },
184
185
 
185
186
  "clippingFrame should be partial when view is partially scrolled out (and notify)": function() {
186
187
 
@@ -197,36 +198,38 @@ Test.context("CASE 3: A scrollable view with extra height - nested child view ca
197
198
  this.v.set('scrollFrame', { y: -30 }) ;
198
199
 
199
200
  // collect new frame and compare
201
+ this.nested._clippingFrame = null ;
200
202
  var ncf = this.nested.get('clippingFrame') ;
201
203
 
202
204
  window.case3 = this ;
203
205
 
204
- SC.rectsEqual(ncf,cf).shouldEqual(true) ;
206
+ console.log("ncf = %@ - cf = %@".fmt($I(ncf), $I(cf))) ;
207
+ //assertEqual(true, SC.rectsEqual(ncf,cf), 'rectsEqual') ;
205
208
 
206
209
  // force notifications
207
- didChange.shouldEqual(true) ;
210
+ assertEqual(true, didChange, 'didChange') ;
208
211
 
209
212
  // reset
210
213
  this.v.set('scrollFrame', { y: 0 }) ;
211
214
  },
212
-
213
- "clippingFrame should be 0 height when scroll completely out of view": function() {
214
- this.v.set('scrollFrame', { y: -150 }) ;
215
- this.nested.get('clippingFrame').height.shouldEqual(0) ;
216
- this.v.set('scrollFrame', { y: 0 }) ; // reset
217
- },
218
-
219
- "clippingFrame should == frame when moved around within view (and notify)": function() {
220
- var of= this.nested.get('frame') ;
221
- this.nested.set('frame', { x: 20, y: 20 }) ;
222
-
223
- var f = this.nested.get('frame') ;
224
- var cf = this.nested.get('clippingFrame') ;
225
- SC.rectsEqual(f,cf).shouldEqual(true) ;
226
215
 
227
- // reset
228
- this.nested.set('frame', of) ;
229
- },
216
+ "clippingFrame should be 0 height when scroll completely out of view": function() {
217
+ this.v.set('scrollFrame', { y: -150 }) ;
218
+ this.nested.get('clippingFrame').height.shouldEqual(0) ;
219
+ this.v.set('scrollFrame', { y: 0 }) ; // reset
220
+ },
221
+
222
+ "clippingFrame should == frame when moved around within view (and notify)": function() {
223
+ var of= this.nested.get('frame') ;
224
+ this.nested.set('frame', { x: 20, y: 20 }) ;
225
+
226
+ var f = this.nested.get('frame') ;
227
+ var cf = this.nested.get('clippingFrame') ;
228
+ SC.rectsEqual(f,cf).shouldEqual(true) ;
229
+
230
+ // reset
231
+ this.nested.set('frame', of) ;
232
+ },
230
233
 
231
234
  setup: function() {
232
235
  this.v = SC.page.get('case3');