sproutcore 1.6.0.rc.1-x86-mingw32 → 1.6.0.rc.2-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (217) hide show
  1. data/CHANGELOG +31 -6
  2. data/{History.txt → History.rdoc} +0 -0
  3. data/{README.txt → README.rdoc} +3 -2
  4. data/Rakefile +15 -15
  5. data/{Todo.txt → Todo.rdoc} +0 -0
  6. data/VERSION.yml +1 -1
  7. data/lib/buildtasks/manifest.rake +11 -4
  8. data/lib/buildtasks/target.rake +20 -23
  9. data/lib/frameworks/sproutcore/CHANGELOG.md +36 -0
  10. data/lib/frameworks/sproutcore/frameworks/core_foundation/core.js +2 -42
  11. data/lib/frameworks/sproutcore/frameworks/core_foundation/ext/handlebars/bind.js +2 -1
  12. data/lib/frameworks/sproutcore/frameworks/core_foundation/ext/handlebars/collection.js +3 -1
  13. data/lib/frameworks/sproutcore/frameworks/core_foundation/mixins/template_helpers/checkbox_support.js +5 -5
  14. data/lib/frameworks/sproutcore/frameworks/core_foundation/mixins/template_helpers/text_field_support.js +29 -12
  15. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/event.js +4 -4
  16. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/mixins/template_helpers/text_field_support.js +9 -0
  17. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/template/collection.js +110 -0
  18. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/template_collection.js +63 -26
  19. data/lib/frameworks/sproutcore/frameworks/datastore/system/child_array.js +25 -5
  20. data/lib/frameworks/sproutcore/frameworks/datastore/system/record_array.js +3 -3
  21. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/nested_records/nested_record_array.js +26 -3
  22. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/record_array/core_methods.js +74 -53
  23. data/lib/frameworks/sproutcore/frameworks/desktop/panes/alert.js +6 -7
  24. data/lib/frameworks/sproutcore/frameworks/desktop/panes/picker.js +6 -3
  25. data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/alert/ui.js +25 -1
  26. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/tab/methods.js +1 -3
  27. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/tab/ui.js +20 -1
  28. data/lib/frameworks/sproutcore/frameworks/desktop/views/select_field.js +1 -1
  29. data/lib/frameworks/sproutcore/frameworks/desktop/views/tab.js +46 -49
  30. data/lib/frameworks/sproutcore/frameworks/foundation/tests/views/container/ui.js +23 -0
  31. data/lib/frameworks/sproutcore/frameworks/foundation/views/container.js +14 -2
  32. data/lib/frameworks/sproutcore/frameworks/jquery/jquery-buffered.js +2 -76
  33. data/lib/frameworks/sproutcore/frameworks/jquery/jquery.js +3348 -1591
  34. data/lib/frameworks/sproutcore/frameworks/runtime/core.js +25 -5
  35. data/lib/frameworks/sproutcore/frameworks/runtime/system/index_set.js +0 -3
  36. data/lib/frameworks/sproutcore/frameworks/runtime/tests/core/objectForPropertyPath.js +10 -5
  37. data/lib/frameworks/sproutcore/frameworks/runtime/tests/core/requiredObjectForPropertyPath.js +29 -0
  38. data/lib/frameworks/sproutcore/frameworks/runtime/tests/private/observer_queue.js +98 -0
  39. data/lib/frameworks/sproutcore/themes/ace/resources/collection/normal/list_item.css +2 -2
  40. data/lib/frameworks/sproutcore/themes/ace/resources/split/split.css +1 -1
  41. data/lib/gen/language/Buildfile +1 -1
  42. data/lib/sproutcore.rb +1 -14
  43. data/lib/sproutcore/buildfile/string_ext.rb +0 -4
  44. data/lib/sproutcore/helpers/cssmin.rb +44 -59
  45. data/lib/sproutcore/helpers/text_helper.rb +11 -13
  46. data/lib/sproutcore/models/manifest.rb +4 -4
  47. data/lib/sproutcore/models/target.rb +11 -110
  48. data/lib/sproutcore/rack.rb +0 -1
  49. data/lib/sproutcore/rack/dev.rb +0 -1
  50. data/lib/sproutcore/rack/proxy.rb +9 -8
  51. data/lib/sproutcore/rack/service.rb +1 -1
  52. data/lib/sproutcore/render_engines/haml.rb +2 -5
  53. data/lib/sproutcore/tools/build.rb +2 -0
  54. data/lib/sproutcore/tools/docs.rb +7 -36
  55. data/lib/sproutcore/tools/manifest.rb +1 -1
  56. data/spec/buildtasks/target_spec.rb +9 -0
  57. data/spec/fixtures/real_world/frameworks/sproutcore/Buildfile +1 -1
  58. data/sproutcore.gemspec +3 -4
  59. data/vendor/chance/lib/chance/instance.rb +5 -8
  60. metadata +41 -207
  61. data/lib/doc_templates/jsdoc/allclasses.tmpl +0 -17
  62. data/lib/doc_templates/jsdoc/allfiles.tmpl +0 -56
  63. data/lib/doc_templates/jsdoc/class.tmpl +0 -487
  64. data/lib/doc_templates/jsdoc/index.tmpl +0 -38
  65. data/lib/doc_templates/jsdoc/publish.js +0 -170
  66. data/lib/doc_templates/jsdoc/static/default.css +0 -162
  67. data/lib/doc_templates/jsdoc/static/header.html +0 -2
  68. data/lib/doc_templates/jsdoc/static/index.html +0 -19
  69. data/lib/doc_templates/jsdoc/symbol.tmpl +0 -35
  70. data/lib/doc_templates/sproutcore/allclasses.tmpl +0 -0
  71. data/lib/doc_templates/sproutcore/allfiles.tmpl +0 -56
  72. data/lib/doc_templates/sproutcore/class.tmpl +0 -674
  73. data/lib/doc_templates/sproutcore/classes-json.tmpl +0 -55
  74. data/lib/doc_templates/sproutcore/index.tmpl +0 -62
  75. data/lib/doc_templates/sproutcore/publish.js +0 -346
  76. data/lib/doc_templates/sproutcore/static/default.css +0 -258
  77. data/lib/doc_templates/sproutcore/static/header.html +0 -2
  78. data/lib/doc_templates/sproutcore/static/index.html +0 -19
  79. data/lib/doc_templates/sproutcore/symbol.tmpl +0 -35
  80. data/lib/frameworks/sproutcore/frameworks/runtime/tests/private/observer_queue/isObservingSuspended.js +0 -55
  81. data/lib/sproutcore/rack/docs.rb +0 -24
  82. data/spec/fixtures/real_world/frameworks/sproutcore/apps/docs/PLACEHOLDER +0 -0
  83. data/vendor/jsdoc/README.txt +0 -151
  84. data/vendor/jsdoc/app/frame.js +0 -33
  85. data/vendor/jsdoc/app/frame/Chain.js +0 -102
  86. data/vendor/jsdoc/app/frame/Dumper.js +0 -144
  87. data/vendor/jsdoc/app/frame/Hash.js +0 -47
  88. data/vendor/jsdoc/app/frame/Link.js +0 -142
  89. data/vendor/jsdoc/app/frame/Namespace.js +0 -10
  90. data/vendor/jsdoc/app/frame/Opt.js +0 -134
  91. data/vendor/jsdoc/app/frame/Reflection.js +0 -26
  92. data/vendor/jsdoc/app/frame/String.js +0 -93
  93. data/vendor/jsdoc/app/frame/Testrun.js +0 -129
  94. data/vendor/jsdoc/app/handlers/FOODOC.js +0 -26
  95. data/vendor/jsdoc/app/handlers/XMLDOC.js +0 -26
  96. data/vendor/jsdoc/app/handlers/XMLDOC/DomReader.js +0 -159
  97. data/vendor/jsdoc/app/handlers/XMLDOC/XMLDoc.js +0 -16
  98. data/vendor/jsdoc/app/handlers/XMLDOC/XMLParse.js +0 -292
  99. data/vendor/jsdoc/app/lib/JSDOC.js +0 -98
  100. data/vendor/jsdoc/app/lib/JSDOC/DocComment.js +0 -200
  101. data/vendor/jsdoc/app/lib/JSDOC/DocTag.js +0 -294
  102. data/vendor/jsdoc/app/lib/JSDOC/JsDoc.js +0 -162
  103. data/vendor/jsdoc/app/lib/JSDOC/JsPlate.js +0 -100
  104. data/vendor/jsdoc/app/lib/JSDOC/Lang.js +0 -144
  105. data/vendor/jsdoc/app/lib/JSDOC/Parser.js +0 -109
  106. data/vendor/jsdoc/app/lib/JSDOC/PluginManager.js +0 -33
  107. data/vendor/jsdoc/app/lib/JSDOC/Symbol.js +0 -681
  108. data/vendor/jsdoc/app/lib/JSDOC/SymbolSet.js +0 -226
  109. data/vendor/jsdoc/app/lib/JSDOC/TextStream.js +0 -41
  110. data/vendor/jsdoc/app/lib/JSDOC/Token.js +0 -18
  111. data/vendor/jsdoc/app/lib/JSDOC/TokenReader.js +0 -332
  112. data/vendor/jsdoc/app/lib/JSDOC/TokenStream.js +0 -133
  113. data/vendor/jsdoc/app/lib/JSDOC/Util.js +0 -32
  114. data/vendor/jsdoc/app/lib/JSDOC/Walker.js +0 -453
  115. data/vendor/jsdoc/app/main.js +0 -74
  116. data/vendor/jsdoc/app/plugins/commentSrcJson.js +0 -19
  117. data/vendor/jsdoc/app/plugins/frameworkPrototype.js +0 -16
  118. data/vendor/jsdoc/app/plugins/functionCall.js +0 -10
  119. data/vendor/jsdoc/app/plugins/publishSrcHilite.js +0 -62
  120. data/vendor/jsdoc/app/plugins/sproutcoreTags.js +0 -26
  121. data/vendor/jsdoc/app/plugins/symbolLink.js +0 -9
  122. data/vendor/jsdoc/app/plugins/tagParamConfig.js +0 -31
  123. data/vendor/jsdoc/app/plugins/tagSynonyms.js +0 -43
  124. data/vendor/jsdoc/app/run.js +0 -346
  125. data/vendor/jsdoc/app/t/TestDoc.js +0 -144
  126. data/vendor/jsdoc/app/t/runner.js +0 -13
  127. data/vendor/jsdoc/app/test.js +0 -304
  128. data/vendor/jsdoc/app/test/addon.js +0 -24
  129. data/vendor/jsdoc/app/test/anon_inner.js +0 -14
  130. data/vendor/jsdoc/app/test/augments.js +0 -31
  131. data/vendor/jsdoc/app/test/augments2.js +0 -26
  132. data/vendor/jsdoc/app/test/borrows.js +0 -41
  133. data/vendor/jsdoc/app/test/borrows2.js +0 -23
  134. data/vendor/jsdoc/app/test/config.js +0 -22
  135. data/vendor/jsdoc/app/test/constructs.js +0 -18
  136. data/vendor/jsdoc/app/test/encoding.js +0 -10
  137. data/vendor/jsdoc/app/test/encoding_other.js +0 -12
  138. data/vendor/jsdoc/app/test/functions_anon.js +0 -39
  139. data/vendor/jsdoc/app/test/functions_nested.js +0 -33
  140. data/vendor/jsdoc/app/test/global.js +0 -13
  141. data/vendor/jsdoc/app/test/globals.js +0 -25
  142. data/vendor/jsdoc/app/test/ignore.js +0 -10
  143. data/vendor/jsdoc/app/test/inner.js +0 -16
  144. data/vendor/jsdoc/app/test/jsdoc_test.js +0 -477
  145. data/vendor/jsdoc/app/test/lend.js +0 -33
  146. data/vendor/jsdoc/app/test/memberof.js +0 -20
  147. data/vendor/jsdoc/app/test/memberof_constructor.js +0 -15
  148. data/vendor/jsdoc/app/test/name.js +0 -19
  149. data/vendor/jsdoc/app/test/namespace_nested.js +0 -23
  150. data/vendor/jsdoc/app/test/nocode.js +0 -13
  151. data/vendor/jsdoc/app/test/oblit_anon.js +0 -20
  152. data/vendor/jsdoc/app/test/overview.js +0 -20
  153. data/vendor/jsdoc/app/test/param_inline.js +0 -37
  154. data/vendor/jsdoc/app/test/params_optional.js +0 -8
  155. data/vendor/jsdoc/app/test/prototype.js +0 -17
  156. data/vendor/jsdoc/app/test/prototype_nested.js +0 -9
  157. data/vendor/jsdoc/app/test/prototype_oblit.js +0 -13
  158. data/vendor/jsdoc/app/test/prototype_oblit_constructor.js +0 -24
  159. data/vendor/jsdoc/app/test/public.js +0 -10
  160. data/vendor/jsdoc/app/test/shared.js +0 -42
  161. data/vendor/jsdoc/app/test/shared2.js +0 -2
  162. data/vendor/jsdoc/app/test/shortcuts.js +0 -22
  163. data/vendor/jsdoc/app/test/static_this.js +0 -13
  164. data/vendor/jsdoc/app/test/synonyms.js +0 -23
  165. data/vendor/jsdoc/app/test/tosource.js +0 -23
  166. data/vendor/jsdoc/app/test/variable_redefine.js +0 -14
  167. data/vendor/jsdoc/changes.txt +0 -47
  168. data/vendor/jsdoc/conf/sample.conf +0 -31
  169. data/vendor/jsdoc/java/build.xml +0 -36
  170. data/vendor/jsdoc/java/build_1.4.xml +0 -36
  171. data/vendor/jsdoc/java/classes/js.jar +0 -0
  172. data/vendor/jsdoc/java/src/JsDebugRun.java +0 -21
  173. data/vendor/jsdoc/java/src/JsRun.java +0 -21
  174. data/vendor/jsdoc/jsdebug.jar +0 -0
  175. data/vendor/jsdoc/jsrun.jar +0 -0
  176. data/vendor/jsdoc/t/TestDoc.js +0 -144
  177. data/vendor/jsdoc/t/runner.js +0 -13
  178. data/vendor/jsdoc/test.js +0 -304
  179. data/vendor/jsdoc/test/addon.js +0 -24
  180. data/vendor/jsdoc/test/anon_inner.js +0 -14
  181. data/vendor/jsdoc/test/augments.js +0 -31
  182. data/vendor/jsdoc/test/augments2.js +0 -26
  183. data/vendor/jsdoc/test/borrows.js +0 -41
  184. data/vendor/jsdoc/test/borrows2.js +0 -23
  185. data/vendor/jsdoc/test/config.js +0 -22
  186. data/vendor/jsdoc/test/constructs.js +0 -18
  187. data/vendor/jsdoc/test/encoding.js +0 -10
  188. data/vendor/jsdoc/test/encoding_other.js +0 -12
  189. data/vendor/jsdoc/test/functions_anon.js +0 -39
  190. data/vendor/jsdoc/test/functions_nested.js +0 -33
  191. data/vendor/jsdoc/test/global.js +0 -13
  192. data/vendor/jsdoc/test/globals.js +0 -25
  193. data/vendor/jsdoc/test/ignore.js +0 -10
  194. data/vendor/jsdoc/test/inner.js +0 -16
  195. data/vendor/jsdoc/test/jsdoc_test.js +0 -477
  196. data/vendor/jsdoc/test/lend.js +0 -33
  197. data/vendor/jsdoc/test/memberof.js +0 -20
  198. data/vendor/jsdoc/test/memberof_constructor.js +0 -15
  199. data/vendor/jsdoc/test/name.js +0 -19
  200. data/vendor/jsdoc/test/namespace_nested.js +0 -23
  201. data/vendor/jsdoc/test/nocode.js +0 -13
  202. data/vendor/jsdoc/test/oblit_anon.js +0 -20
  203. data/vendor/jsdoc/test/overview.js +0 -20
  204. data/vendor/jsdoc/test/param_inline.js +0 -37
  205. data/vendor/jsdoc/test/params_optional.js +0 -8
  206. data/vendor/jsdoc/test/prototype.js +0 -17
  207. data/vendor/jsdoc/test/prototype_nested.js +0 -9
  208. data/vendor/jsdoc/test/prototype_oblit.js +0 -13
  209. data/vendor/jsdoc/test/prototype_oblit_constructor.js +0 -24
  210. data/vendor/jsdoc/test/public.js +0 -10
  211. data/vendor/jsdoc/test/shared.js +0 -42
  212. data/vendor/jsdoc/test/shared2.js +0 -2
  213. data/vendor/jsdoc/test/shortcuts.js +0 -22
  214. data/vendor/jsdoc/test/static_this.js +0 -13
  215. data/vendor/jsdoc/test/synonyms.js +0 -23
  216. data/vendor/jsdoc/test/tosource.js +0 -23
  217. data/vendor/jsdoc/test/variable_redefine.js +0 -14
@@ -287,7 +287,7 @@ SC.mixin(SC.Event, /** @scope SC.Event */ {
287
287
  // Get the handlers queue for this element/eventType. If the queue does
288
288
  // not exist yet, create it and also setup the shared listener for this
289
289
  // eventType.
290
- var events = SC.data(elem, "events") || SC.data(elem, "events", {}) ,
290
+ var events = SC.data(elem, "sc_events") || SC.data(elem, "sc_events", {}) ,
291
291
  handlers = events[eventType];
292
292
  if (!handlers) {
293
293
  handlers = events[eventType] = {} ;
@@ -351,7 +351,7 @@ SC.mixin(SC.Event, /** @scope SC.Event */ {
351
351
  // around, causing it to be cloned in the process
352
352
  if (SC.browser.msie && elem.setInterval) elem = window;
353
353
 
354
- var handlers, key, events = SC.data(elem, "events") ;
354
+ var handlers, key, events = SC.data(elem, "sc_events") ;
355
355
  if (!events) return this ; // nothing to do if no events are registered
356
356
 
357
357
  // if no type is provided, remove all types for this element.
@@ -396,7 +396,7 @@ SC.mixin(SC.Event, /** @scope SC.Event */ {
396
396
  key = null ;
397
397
  for(key in events) break;
398
398
  if(!key) {
399
- SC.removeData(elem, "events") ;
399
+ SC.removeData(elem, "sc_events") ;
400
400
  delete this._elements[SC.guidFor(elem)]; // important to avoid leaks
401
401
  }
402
402
 
@@ -546,7 +546,7 @@ SC.mixin(SC.Event, /** @scope SC.Event */ {
546
546
  args[0] = event = SC.Event.normalizeEvent(event || window.event);
547
547
 
548
548
  // get the handlers for this event type
549
- handlers = (SC.data(this, "events") || {})[event.type];
549
+ handlers = (SC.data(this, "sc_events") || {})[event.type];
550
550
  if (!handlers) return NO ; // nothing to do
551
551
 
552
552
  // invoke all handlers
@@ -190,4 +190,13 @@
190
190
  SC.RootResponder.responder.keyup(new SC.Event({ type: 'keyup', keyCode: 27 }));
191
191
  equals(cancelCalled, 1, "calls cancel after pressing escape key");
192
192
  });
193
+
194
+ test("creates textarea tag if isMultiline", function() {
195
+ var view = SC.TextField.create({
196
+ isMultiline: YES
197
+ });
198
+ SC.run(function() { pane.appendChild(view); });
199
+ equals(view.$('textarea').length, 1, "view creates textarea tag instead of input");
200
+ });
201
+
193
202
  })();
@@ -272,3 +272,113 @@ test("should allow changing content property to be null", function() {
272
272
  view.set('content', null);
273
273
  equals(view.$('li').length, 0, "should not create any li elements");
274
274
  });
275
+
276
+ test("collection view within a collection view with default content should render content once", function() {
277
+ TemplateTests.InnerCollectionView = SC.TemplateCollectionView.extend();
278
+
279
+ TemplateTests.OuterItemView = SC.TemplateView.extend({
280
+ template: SC.Handlebars.compile('{{#collection "TemplateTests.InnerCollectionView" content=content.things}} {{content}} {{/collection}}')
281
+ });
282
+
283
+ TemplateTests.OuterCollectionView = SC.TemplateCollectionView.extend({
284
+ content: [
285
+ SC.Object.create({things: ['1', '2', '3']}),
286
+ SC.Object.create({things: ['4', '5']}),
287
+ SC.Object.create({things: ['6']})
288
+ ],
289
+ itemView: TemplateTests.OuterItemView
290
+ });
291
+
292
+ var view = SC.TemplateView.create({
293
+ template: SC.Handlebars.compile('{{collection "TemplateTests.OuterCollectionView"}}')
294
+ });
295
+
296
+ view.createLayer();
297
+
298
+ equals(view.$('ul ul:eq(0) li').length, 3, 'first nested collection view should have 3 list items');
299
+ equals(view.$('ul ul:eq(1) li').length, 2, 'second nested collection view should have 2 list items');
300
+ equals(view.$('ul ul:eq(2) li').length, 1, 'third nested collection view should have 1 list items');
301
+ });
302
+
303
+ test("collection view within a collection view should have the right childViews", function() {
304
+ TemplateTests.InnerCollectionView = SC.TemplateCollectionView.extend();
305
+
306
+ TemplateTests.OuterItemView = SC.TemplateView.extend({
307
+ template: SC.Handlebars.compile('{{#collection "TemplateTests.InnerCollectionView" content=content.things}} {{content}} {{/collection}}')
308
+ });
309
+
310
+ TemplateTests.OuterCollectionView = SC.TemplateCollectionView.extend({
311
+ content: [
312
+ SC.Object.create({things: ['1', '2', '3']}),
313
+ SC.Object.create({things: ['4', '5']}),
314
+ SC.Object.create({things: ['6']})
315
+ ],
316
+ itemView: TemplateTests.OuterItemView
317
+ });
318
+
319
+ var view = SC.TemplateView.create({
320
+ template: SC.Handlebars.compile('{{collection "TemplateTests.OuterCollectionView"}}')
321
+ });
322
+
323
+ view.createLayer();
324
+
325
+ var outer = view.childViews[0];
326
+ var firstInner = outer.childViews[0].childViews[0];
327
+ var secondInner = outer.childViews[1].childViews[0];
328
+ var thirdInner = outer.childViews[2].childViews[0];
329
+
330
+ ok(outer.kindOf(TemplateTests.OuterCollectionView), 'first child view should be instance of outer collection view');
331
+ ok(firstInner.kindOf(TemplateTests.InnerCollectionView), 'first child view of outer should be instance of inner');
332
+ ok(secondInner.kindOf(TemplateTests.InnerCollectionView), 'second child view of outer should be instance of inner');
333
+ ok(thirdInner.kindOf(TemplateTests.InnerCollectionView), 'third child view of outer should be instance of inner');
334
+ });
335
+
336
+ test("should render inverse template when its present and there is no content", function() {
337
+ TemplateTests.CollectionTestView = SC.TemplateCollectionView.create({
338
+ content: [],
339
+ inverseTemplate: SC.Handlebars.compile('<h1>inverse<h1>')
340
+ });
341
+
342
+ var view = SC.TemplateView.create({
343
+ template: SC.Handlebars.compile('{{collection "TemplateTests.CollectionTestView"}}')
344
+ });
345
+
346
+ view.createLayer();
347
+
348
+ equals(view.$('h1').text(), 'inverse', 'collection view with no content and inverse template should render inverse template')
349
+ });
350
+
351
+ test("should render inverse template name when its present and there is no content", function() {
352
+ TemplateTests.CollectionTestView = SC.TemplateCollectionView.create({
353
+ content: [],
354
+ inverseTemplateName: 'inverse_template',
355
+
356
+ templates: SC.Object.create({
357
+ inverse_template: function(dataSource) {
358
+ return "<h1>inverse template from file</h1>";
359
+ }
360
+ })
361
+ });
362
+
363
+ var view = SC.TemplateView.create({
364
+ template: SC.Handlebars.compile('{{collection "TemplateTests.CollectionTestView"}}')
365
+ });
366
+
367
+ view.createLayer();
368
+
369
+ equals(view.$('h1').text(), 'inverse template from file', 'collection view with no content and inverse template name should render template')
370
+ });
371
+
372
+ test("#collection helper should allow relative paths for the collection view class", function() {
373
+ var view = SC.TemplateView.create({
374
+ template: SC.Handlebars.compile('{{#collection "myCollectionView"}}{{content}}{{/collection}}'),
375
+ myCollectionView: SC.TemplateCollectionView.create({
376
+ content: ['foo', 'bar', 'baz']
377
+ })
378
+ });
379
+
380
+ SC.run(function() { view.createLayer(); });
381
+
382
+ equals(view.$('li').length, 3, '#collection should find relative collection view path');
383
+ });
384
+
@@ -30,6 +30,12 @@ SC.TemplateCollectionView = SC.TemplateView.extend(
30
30
  // In case a default content was set, trigger the child view creation
31
31
  // as soon as the empty layer was created
32
32
  didCreateLayer: function() {
33
+ // FIXME: didCreateLayer gets called multiple times when template collection
34
+ // views are nested - this is a hack to avoid rendering the content more
35
+ // than once.
36
+ if (this._sctcv_layerCreated) { return; }
37
+ this._sctcv_layerCreated = true;
38
+
33
39
  var content = this.get('content');
34
40
  if(content) {
35
41
  this.arrayContentDidChange(0, 0, content.get('length'));
@@ -64,6 +70,37 @@ SC.TemplateCollectionView = SC.TemplateView.extend(
64
70
  */
65
71
  itemViewTemplateName: null,
66
72
 
73
+ /**
74
+ A template to render when there is no content or the content length is 0.
75
+ */
76
+ inverseTemplate: function(key, value) {
77
+ if (value !== undefined) {
78
+ return value;
79
+ }
80
+
81
+ var templateName = this.get('inverseTemplateName'),
82
+ template = this.get('templates').get(templateName);
83
+
84
+ if (!template) {
85
+ //@if(debug)
86
+ if (templateName) {
87
+ SC.Logger.warn('%@ - Unable to find template "%@".'.fmt(this, templateName));
88
+ }
89
+ //@endif
90
+
91
+ return function() { return ''; };
92
+ }
93
+
94
+ return template;
95
+ }.property('inverseTemplateName').cacheable(),
96
+
97
+ /**
98
+ The name of a template to lookup if no inverse template is provided.
99
+
100
+ @property {String}
101
+ */
102
+ inverseTemplateName: null,
103
+
67
104
  itemContext: null,
68
105
 
69
106
  itemViewClass: function() {
@@ -207,42 +244,42 @@ SC.TemplateCollectionView = SC.TemplateView.extend(
207
244
  delete itemOptions['class'];
208
245
  delete itemOptions.classBinding;
209
246
 
210
- for (idx = 0; idx < len; idx++) {
211
- item = addedObjects.objectAt(idx);
212
- view = this.createChildView(itemViewClass.extend(itemOptions, {
213
- content: item,
214
- render: renderFunc,
215
- tagName: itemViewClass.prototype.tagName || this.get('itemTagName')
216
- }));
217
-
218
- var contextProperty = view.get('contextProperty');
219
- if (contextProperty) {
220
- view.set('context', view.get(contextProperty));
221
- }
222
-
223
- itemElem = view.createLayer().$();
224
- if (!insertAtElement) {
225
- elem.append(itemElem);
226
- } else {
227
- itemElem.insertAfter(insertAtElement);
228
- }
229
- insertAtElement = itemElem;
230
-
231
- addedViews.push(view);
247
+ for (idx = 0; idx < len; idx++) {
248
+ item = addedObjects.objectAt(idx);
249
+ childView = this.createChildView(itemViewClass.extend(itemOptions, {
250
+ content: item,
251
+ render: renderFunc,
252
+ tagName: itemViewClass.prototype.tagName || this.get('itemTagName')
253
+ }));
254
+
255
+ var contextProperty = childView.get('contextProperty');
256
+ if (contextProperty) {
257
+ childView.set('context', childView.get(contextProperty));
258
+ }
259
+
260
+ itemElem = childView.createLayer().$();
261
+ if (!insertAtElement) {
262
+ elem.append(itemElem);
263
+ } else {
264
+ itemElem.insertAfter(insertAtElement);
232
265
  }
266
+ insertAtElement = itemElem;
267
+
268
+ addedViews.push(childView);
269
+ }
233
270
 
234
271
  childViews.replace(start, 0, addedViews);
235
272
  }
236
273
 
237
274
  var inverseTemplate = this.get('inverseTemplate');
238
275
  if (childViews.get('length') === 0 && inverseTemplate) {
239
- view = this.createChildView(SC.TemplateView.extend({
276
+ childView = this.createChildView(SC.TemplateView.extend({
240
277
  template: inverseTemplate,
241
278
  content: this
242
279
  }));
243
- this.set('emptyView', view);
244
- view.createLayer().$().appendTo(elem);
245
- this.childViews = [view];
280
+ this.set('emptyView', childView);
281
+ childView.createLayer().$().appendTo(elem);
282
+ this.childViews = [childView];
246
283
  }
247
284
 
248
285
  // Because the layer has been modified, we need to invalidate the frame
@@ -172,7 +172,11 @@ SC.ChildArray = SC.Object.extend(SC.Enumerable, SC.Array,
172
172
  newRecs = this._processRecordsToHashes(recs);
173
173
  children.replace(idx, amt, newRecs);
174
174
  // notify that the record did change...
175
- if (newRecs !== this._prevChildren) this.recordPropertyDidChange();
175
+ if (newRecs !== this._prevChildren){
176
+ this._performRecordPropertyChange(null, false);
177
+ this.arrayContentWillChange(idx, amt, len);
178
+ this._childrenContentDidChange(idx, amt, len);
179
+ }
176
180
  record.recordDidChange(pname);
177
181
 
178
182
  return this;
@@ -219,10 +223,25 @@ SC.ChildArray = SC.Object.extend(SC.Enumerable, SC.Array,
219
223
  @returns {SC.ChildArray} itself.
220
224
  */
221
225
  recordPropertyDidChange: function(keys) {
226
+ this._performRecordPropertyChange(keys, true);
227
+ return this;
228
+ },
229
+
230
+ /** @private
231
+ Invoked when the object is changed from the parent or an outside source
232
+
233
+ will cause the entire array to reset
234
+
235
+ @param {SC.Array} keys optional
236
+ @param {Boolean} doReset optional
237
+ @returns {SC.ChildArray} itself.
238
+ */
239
+ _performRecordPropertyChange: function(keys, doReset){
222
240
  if (keys && !keys.contains(this.get('propertyName'))) return this;
223
241
 
224
242
  var children = this.get('readOnlyChildren'), oldLen = 0, newLen = 0;
225
243
  var prev = this._prevChildren, f = this._childrenContentDidChange;
244
+ doReset = SC.none(doReset) ? true : doReset;
226
245
 
227
246
  if (children === prev) return this; // nothing to do
228
247
 
@@ -245,11 +264,12 @@ SC.ChildArray = SC.Object.extend(SC.Enumerable, SC.Array,
245
264
 
246
265
  newLen = children.get('length');
247
266
  }
248
-
249
-
250
- this.arrayContentWillChange(0, oldLen, newLen);
251
267
  this._prevChildren = children;
252
- this._childrenContentDidChange(0, oldLen, newLen);
268
+
269
+ if (doReset){
270
+ this.arrayContentWillChange(0, oldLen, newLen);
271
+ this._childrenContentDidChange(0, oldLen, newLen);
272
+ }
253
273
 
254
274
  return this;
255
275
  },
@@ -316,11 +316,11 @@ SC.RecordArray = SC.Object.extend(SC.Enumerable, SC.Array,
316
316
 
317
317
  @returns {SC.RecordArray}
318
318
  */
319
- find: function(query, target) {
319
+ find: function(original, query, target) {
320
320
  if (query && query.isQuery) {
321
321
  return this.get('store').find(query.queryWithScope(this));
322
- } else return sc_super();
323
- },
322
+ } else return original.apply(this, SC.$A(arguments).slice(1));
323
+ }.enhance(),
324
324
 
325
325
  /**
326
326
  Call whenever you want to refresh the results of this query. This will
@@ -378,7 +378,30 @@ test("pushObject should trigger an arrayContentDidChange with only 1 added item"
378
378
  testParent.get('elements').pushObject({});
379
379
 
380
380
  equals(didChangeCalls.length, 1, 'didChange should only be called once');
381
- equals(didChangeCalls[0][0], 0, 'didChange should be called with a start index of 0 because we can\'t be sure about the order from the server');
382
- equals(didChangeCalls[0][1], 4, 'didChange should be called with a removed count of 4');
383
- equals(didChangeCalls[0][2], 5, 'didChange should be called with an added count of 5 because the items could have changed order on the server');
381
+ equals(didChangeCalls[0][0], 4, 'didChange should be called with a start index of 4');
382
+ equals(didChangeCalls[0][1], 0, 'didChange should be called with a removed count of 0');
383
+ equals(didChangeCalls[0][2], 1, 'didChange should be called with an added count of 1');
384
+ });
385
+
386
+ test("replace should trigger an arrayContentDidChange with only 1 added item", function() {
387
+ var didChangeCalls = [], target;
388
+
389
+ target = SC.Object.create({
390
+ willChange: function() {},
391
+ didChange: function() {
392
+ didChangeCalls.push(arguments);
393
+ }
394
+ });
395
+
396
+ testParent.get('elements').addArrayObservers({
397
+ target: target,
398
+ willChange: 'willChange',
399
+ didChange: 'didChange'
400
+ });
401
+ testParent.get('elements').replace(3, 1, [{}]);
402
+
403
+ equals(didChangeCalls.length, 1, 'didChange should only be called once');
404
+ equals(didChangeCalls[0][0], 3, 'didChange should be called with a start index of 3');
405
+ equals(didChangeCalls[0][1], 1, 'didChange should be called with a removed count of 1');
406
+ equals(didChangeCalls[0][2], 1, 'didChange should be called with an added count of 1');
384
407
  });
@@ -6,22 +6,28 @@
6
6
  /*globals module ok equals same test MyApp */
7
7
 
8
8
  // test core array-mapping methods for RecordArray
9
- var store, storeKey, json, rec, storeKeys, recs;
9
+ var store, storeKey, json, rec, storeKey2, json2, rec2, storeKeys, recs;
10
10
  module("SC.RecordArray core methods", {
11
11
  setup: function() {
12
12
  // setup dummy store
13
13
  store = SC.Store.create();
14
+
14
15
  storeKey = SC.Record.storeKeyFor('foo');
15
- json = { guid: "foo", foo: "bar" };
16
- store.writeDataHash(storeKey, json, SC.Record.READY_CLEAN);
17
-
18
-
19
- // get record
16
+ json = { guid: "foo", foo: "bar" };
17
+ store.writeDataHash(storeKey, json, SC.Record.READY_CLEAN);
18
+
19
+ storeKey2 = SC.Record.storeKeyFor('baz');
20
+ json2 = { guid: "baz", baz: "bash" };
21
+ store.writeDataHash(storeKey2, json2, SC.Record.READY_CLEAN);
22
+
23
+ // get records
20
24
  rec = store.materializeRecord(storeKey);
21
- equals(rec.get('foo'), 'bar', 'record should have json');
22
-
25
+ equals(rec.get('foo'), 'bar', 'precond - record should have json');
26
+ rec2 = store.materializeRecord(storeKey2);
27
+ equals(rec2.get('baz'), 'bash', 'precond - record 2 should have json');
28
+
23
29
  // get record array.
24
- storeKeys = [storeKey];
30
+ storeKeys = [storeKey, storeKey2];
25
31
  recs = SC.RecordArray.create({ store: store, storeKeys: storeKeys });
26
32
  }
27
33
  });
@@ -32,25 +38,25 @@ test("initial status", function() {
32
38
 
33
39
  // ..........................................................
34
40
  // LENGTH
35
- //
41
+ //
36
42
 
37
43
  test("should pass through length", function() {
38
- equals(recs.get('length'), storeKeys.length, 'rec should pass through length');
44
+ equals(recs.get('length'), storeKeys.length, 'rec should pass through length');
39
45
  });
40
46
 
41
47
  test("changing storeKeys length should change length of rec array also", function() {
42
48
 
43
49
  var oldlen = recs.get('length');
44
-
50
+
45
51
  storeKeys.pushObject(SC.Store.generateStoreKey()); // change length
46
-
52
+
47
53
  ok(storeKeys.length > oldlen, 'precond - storeKeys.length should have changed');
48
- equals(recs.get('length'), storeKeys.length, 'rec should pass through length');
54
+ equals(recs.get('length'), storeKeys.length, 'rec should pass through length');
49
55
  });
50
56
 
51
57
  // ..........................................................
52
58
  // objectAt
53
- //
59
+ //
54
60
 
55
61
  test("should materialize record for object", function() {
56
62
  equals(storeKeys[0], storeKey, 'precond - storeKeys[0] should be storeKey');
@@ -63,67 +69,70 @@ test("reading past end of array length should return undefined", function() {
63
69
 
64
70
  test("modifying the underlying storeKey should change the returned materialized record", function() {
65
71
  // read record once to make it materialized
66
- equals(recs.objectAt(0), rec, 'recs.objectAt(0) should materialize record');
67
-
72
+ equals(recs.objectAt(0), rec, 'recs.objectAt(0) should materialize record');
73
+
68
74
  // create a new record.
69
75
  SC.RunLoop.begin();
70
- var rec2 = store.createRecord(SC.Record, { foo: "rec2" });
76
+ var rec3 = store.createRecord(SC.Record, { foo: "rec3" });
71
77
  SC.RunLoop.end();
72
78
 
73
- var storeKey2 = rec2.get('storeKey');
74
-
79
+ var storeKey3 = rec3.get('storeKey');
80
+
75
81
  // add to beginning of storeKey array
76
- storeKeys.unshiftObject(storeKey2);
77
- equals(recs.get('length'), 2, 'should now have length of 2');
78
- equals(recs.objectAt(0), rec2, 'objectAt(0) should return new record');
79
- equals(recs.objectAt(1), rec, 'objectAt(1) should return old record');
82
+ storeKeys.unshiftObject(storeKey3);
83
+ equals(recs.get('length'), 3, 'should now have length of 3');
84
+ equals(recs.objectAt(0), rec3, 'objectAt(0) should return new record');
85
+ equals(recs.objectAt(1), rec, 'objectAt(1) should return old record 1');
86
+ equals(recs.objectAt(2), rec2, 'objectAt(2) should return old record 2');
80
87
  });
81
88
 
82
89
  test("reading a record not loaded in store should trigger retrieveRecord", function() {
83
90
  var callCount = 0;
84
91
 
85
- // patch up store to record a call and to make it look like data is not
92
+ // patch up store to record a call and to make it look like data is not
86
93
  // loaded.
87
94
  store.removeDataHash(storeKey, SC.Record.EMPTY);
88
95
  store.retrieveRecord = function() { callCount++; };
89
-
96
+
90
97
  equals(store.peekStatus(storeKeys.objectAt(0)), SC.Record.EMPTY, 'precond - storeKey must not be loaded');
91
-
98
+
92
99
  var rec = recs.objectAt(0);
93
100
  equals(callCount, 1, 'store.retrieveRecord() should have been called');
94
101
  });
95
102
 
96
103
  // ..........................................................
97
104
  // replace()
98
- //
105
+ //
99
106
 
100
107
  test("adding a record to the record array should pass through storeKeys", function() {
101
108
  // read record once to make it materialized
102
- equals(recs.objectAt(0), rec, 'recs.objectAt(0) should materialize record');
103
-
109
+ equals(recs.objectAt(0), rec, 'recs.objectAt(0) should materialize record');
110
+
104
111
  // create a new record.
105
112
  SC.RunLoop.begin();
106
- var rec2 = store.createRecord(SC.Record, { foo: "rec2" });
113
+ var rec3 = store.createRecord(SC.Record, { foo: "rec3" });
107
114
  SC.RunLoop.end();
108
-
109
- var storeKey2 = rec2.get('storeKey');
110
-
115
+
116
+ var storeKey3 = rec3.get('storeKey');
117
+
111
118
  // add record to beginning of record array
112
- recs.unshiftObject(rec2);
113
-
119
+ recs.unshiftObject(rec3);
120
+
114
121
  // verify record array
115
- equals(recs.get('length'), 2, 'should now have length of 2');
116
- equals(recs.objectAt(0), rec2, 'recs.objectAt(0) should return new record');
117
- equals(recs.objectAt(1), rec, 'recs.objectAt(1) should return old record');
118
-
122
+ equals(recs.get('length'), 3, 'should now have length of 3');
123
+ equals(recs.objectAt(0), rec3, 'recs.objectAt(0) should return new record');
124
+ equals(recs.objectAt(1), rec, 'recs.objectAt(1) should return old record 1');
125
+ equals(recs.objectAt(2), rec2, 'recs.objectAt(2) should return old record 2');
126
+
119
127
  // verify storeKeys
120
- equals(storeKeys.objectAt(0), storeKey2, 'storeKeys[0] should return new storeKey');
121
- equals(storeKeys.objectAt(1), storeKey, 'storeKeys[1] should return old storeKey');
128
+ equals(storeKeys.objectAt(0), storeKey3, 'storeKeys[0] should return new storeKey');
129
+ equals(storeKeys.objectAt(1), storeKey, 'storeKeys[1] should return old storeKey 1');
130
+ equals(storeKeys.objectAt(2), storeKey2, 'storeKeys[2] should return old storeKey 2');
122
131
  });
123
132
 
124
133
  // ..........................................................
125
134
  // Property Observing
126
- //
135
+ //
127
136
 
128
137
  test("changing the underlying storeKeys should notify observers of records", function() {
129
138
 
@@ -132,8 +141,8 @@ test("changing the underlying storeKeys should notify observers of records", fun
132
141
  cnt: 0,
133
142
  observer: function() { this.cnt++; }
134
143
  });
135
- recs.addObserver('[]', obj, obj.observer);
136
-
144
+ recs.addObserver('[]', obj, obj.observer);
145
+
137
146
  // now modify storeKeys
138
147
  storeKeys.pushObject(SC.Store.generateStoreKey());
139
148
  equals(obj.cnt, 1, 'observer should have fired after changing storeKeys');
@@ -145,7 +154,7 @@ test("swapping storeKey array should change recordArray and observers", function
145
154
  SC.RunLoop.begin();
146
155
  var rec2 = store.createRecord(SC.Record, { foo: "rec2" });
147
156
  SC.RunLoop.end();
148
-
157
+
149
158
  var storeKey2 = rec2.get('storeKey');
150
159
  var storeKeys2 = [storeKey2];
151
160
 
@@ -154,24 +163,36 @@ test("swapping storeKey array should change recordArray and observers", function
154
163
  cnt: 0,
155
164
  observer: function() { this.cnt++; }
156
165
  });
157
- recs.addObserver('[]', obj, obj.observer);
158
-
166
+ recs.addObserver('[]', obj, obj.observer);
167
+
159
168
  // read record once to make it materialized
160
- equals(recs.objectAt(0), rec, 'recs.objectAt(0) should materialize record');
161
-
169
+ equals(recs.objectAt(0), rec, 'recs.objectAt(0) should materialize record');
170
+
162
171
  // now swap storeKeys
163
172
  obj.cnt = 0 ;
164
173
  recs.set('storeKeys', storeKeys2);
165
-
174
+
166
175
  // verify observer fired and record changed
167
176
  equals(obj.cnt, 1, 'observer should have fired after swap');
168
177
  equals(recs.objectAt(0), rec2, 'recs.objectAt(0) should return new rec');
169
-
178
+
170
179
  // modify storeKey2, make sure observer fires and content changes
171
180
  obj.cnt = 0;
172
181
  storeKeys2.unshiftObject(storeKey);
173
182
  equals(obj.cnt, 1, 'observer should have fired after edit');
174
183
  equals(recs.get('length'), 2, 'should reflect new length');
175
- equals(recs.objectAt(0), rec, 'recs.objectAt(0) should return pushed rec');
184
+ equals(recs.objectAt(0), rec, 'recs.objectAt(0) should return pushed rec');
185
+
186
+ });
187
+
188
+ test("find works with query", function(){
189
+ var filtered = recs.find(SC.Query.create({ conditions: "foo = 'bar'" }));
190
+
191
+ equals(filtered.get('length'), 1);
192
+ equals(filtered.objectAt(0), rec);
193
+ });
176
194
 
195
+ test("find works as enumerable", function(){
196
+ var filtered = recs.find(function(r){ return r.get('foo') === 'bar'; });
197
+ equals(filtered, rec);
177
198
  });