sproutcore 1.6.0.1 → 1.7.1.beta

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.
Files changed (143) hide show
  1. data/CHANGELOG +21 -0
  2. data/Gemfile +5 -0
  3. data/Rakefile +26 -13
  4. data/VERSION.yml +2 -2
  5. data/lib/Buildfile +43 -4
  6. data/lib/buildtasks/build.rake +10 -0
  7. data/lib/buildtasks/helpers/file_rule.rb +22 -0
  8. data/lib/buildtasks/helpers/file_rule_list.rb +137 -0
  9. data/lib/buildtasks/manifest.rake +133 -122
  10. data/lib/frameworks/sproutcore/CHANGELOG.md +69 -2
  11. data/lib/frameworks/sproutcore/apps/tests/english.lproj/strings.js +1 -0
  12. data/lib/frameworks/sproutcore/frameworks/bootstrap/system/browser.js +28 -22
  13. data/lib/frameworks/sproutcore/frameworks/core_foundation/controllers/array.js +9 -5
  14. data/lib/frameworks/sproutcore/frameworks/core_foundation/controllers/controller.js +1 -1
  15. data/lib/frameworks/sproutcore/frameworks/core_foundation/controls/button.js +18 -13
  16. data/lib/frameworks/sproutcore/frameworks/core_foundation/ext/handlebars/bind.js +5 -3
  17. data/lib/frameworks/sproutcore/frameworks/core_foundation/ext/handlebars/collection.js +2 -0
  18. data/lib/frameworks/sproutcore/frameworks/core_foundation/mixins/action_support.js +80 -0
  19. data/lib/frameworks/sproutcore/frameworks/core_foundation/mixins/template_helpers/text_field_support.js +84 -116
  20. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/pane.js +8 -5
  21. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/event.js +157 -157
  22. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/platform.js +5 -3
  23. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/root_responder.js +6 -6
  24. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/sparse_array.js +10 -7
  25. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/mixins/action_support.js +106 -0
  26. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/template/collection.js +18 -0
  27. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/template/handlebars.js +71 -1
  28. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/attribute_bindings_test.js +38 -0
  29. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/class_name_bindings_test.js +47 -0
  30. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layoutChildViews.js +18 -18
  31. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layoutStyle.js +42 -10
  32. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/keyboard.js +26 -1
  33. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/layout_style.js +14 -8
  34. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view.js +158 -1
  35. data/lib/frameworks/sproutcore/frameworks/datastore/models/record.js +15 -2
  36. data/lib/frameworks/sproutcore/frameworks/datastore/models/record_attribute.js +108 -108
  37. data/lib/frameworks/sproutcore/frameworks/datastore/system/query.js +1 -1
  38. data/lib/frameworks/sproutcore/frameworks/datastore/system/record_array.js +2 -4
  39. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/record/error_methods.js +2 -2
  40. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/single_attribute.js +26 -0
  41. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/query/builders.js +7 -0
  42. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/record_array/error_methods.js +1 -1
  43. data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/core/system/datetime.js +4 -1
  44. data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/core/tests/system/datetime.js +6 -0
  45. data/lib/frameworks/sproutcore/frameworks/desktop/panes/menu.js +26 -5
  46. data/lib/frameworks/sproutcore/frameworks/desktop/panes/picker.js +97 -96
  47. data/lib/frameworks/sproutcore/frameworks/desktop/system/drag.js +4 -3
  48. data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/menu/ui.js +17 -4
  49. data/lib/frameworks/sproutcore/frameworks/desktop/views/collection.js +7 -7
  50. data/lib/frameworks/sproutcore/frameworks/desktop/views/menu_item.js +7 -5
  51. data/lib/frameworks/sproutcore/frameworks/desktop/views/scroll.js +12 -3
  52. data/lib/frameworks/sproutcore/frameworks/desktop/views/web.js +23 -14
  53. data/lib/frameworks/sproutcore/frameworks/experimental/Buildfile +5 -1
  54. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/render_delegates/menu_scroller.js +28 -0
  55. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/tests/menu/scroll.js +235 -0
  56. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/views/menu/scroll.js +363 -0
  57. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/views/menu/scroller.js +250 -0
  58. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/render_delegates/desktop_scroller.js +92 -0
  59. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/render_delegates/native_scroll.js +25 -0
  60. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/render_delegates/scroll.js +33 -0
  61. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/render_delegates/touch_scroller.js +76 -0
  62. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/tests/scroll/integration.js +50 -0
  63. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/tests/scroll/methods.js +143 -0
  64. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/tests/scroll/ui.js +258 -0
  65. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/core_scroll.js +1164 -0
  66. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/core_scroller.js +332 -0
  67. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/desktop/scroll.js +236 -0
  68. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/desktop/scroller.js +347 -0
  69. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/scroll.js +15 -0
  70. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/scroller.js +10 -0
  71. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/touch/scroll.js +804 -0
  72. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/touch/scroller.js +133 -0
  73. data/lib/frameworks/sproutcore/frameworks/foundation/resources/text_field.css +3 -3
  74. data/lib/frameworks/sproutcore/frameworks/foundation/validators/number.js +3 -1
  75. data/lib/frameworks/sproutcore/frameworks/foundation/views/text_field.js +3 -3
  76. data/lib/frameworks/sproutcore/frameworks/media/views/audio.js +2 -1
  77. data/lib/frameworks/sproutcore/frameworks/media/views/controls.js +2 -1
  78. data/lib/frameworks/sproutcore/frameworks/media/views/media_slider.js +2 -4
  79. data/lib/frameworks/sproutcore/frameworks/media/views/mini_controls.js +2 -4
  80. data/lib/frameworks/sproutcore/frameworks/media/views/simple_controls.js +2 -4
  81. data/lib/frameworks/sproutcore/frameworks/media/views/video.js +2 -2
  82. data/lib/frameworks/sproutcore/frameworks/routing/system/routes.js +29 -3
  83. data/lib/frameworks/sproutcore/frameworks/runtime/core.js +2 -2
  84. data/lib/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/replace.js +1 -1
  85. data/lib/frameworks/sproutcore/frameworks/runtime/private/property_chain.js +2 -1
  86. data/lib/frameworks/sproutcore/frameworks/runtime/system/binding.js +3 -3
  87. data/lib/frameworks/sproutcore/frameworks/runtime/system/index_set.js +2 -2
  88. data/lib/frameworks/sproutcore/frameworks/runtime/system/object.js +1 -1
  89. data/lib/frameworks/sproutcore/themes/ace/resources/collection/normal/list_item.css +2 -2
  90. data/lib/frameworks/sproutcore/themes/legacy_theme/english.lproj/segmented.css +1 -1
  91. data/lib/gen/app/templates/apps/@target_name@/Buildfile +3 -5
  92. data/lib/gen/app/templates/apps/@target_name@/resources/_theme.css +18 -0
  93. data/lib/gen/project/templates/@filename@/Buildfile +2 -2
  94. data/lib/sproutcore/builders/chance_file.rb +9 -16
  95. data/lib/sproutcore/builders/html.rb +2 -1
  96. data/lib/sproutcore/builders/minify.rb +4 -35
  97. data/lib/sproutcore/builders/module.rb +38 -1
  98. data/lib/sproutcore/builders/split.rb +63 -0
  99. data/lib/sproutcore/builders/strings.rb +7 -1
  100. data/lib/sproutcore/builders.rb +1 -0
  101. data/lib/sproutcore/helpers/css_split.rb +190 -0
  102. data/lib/sproutcore/helpers/entry_sorter.rb +2 -0
  103. data/lib/sproutcore/helpers/minifier.rb +40 -16
  104. data/lib/sproutcore/helpers/static_helper.rb +35 -17
  105. data/lib/sproutcore/helpers.rb +1 -1
  106. data/lib/sproutcore/models/manifest.rb +26 -0
  107. data/lib/sproutcore/models/target.rb +12 -1
  108. data/lib/sproutcore/rack/proxy.rb +244 -225
  109. data/lib/sproutcore/rack/restrict_ip.rb +67 -0
  110. data/lib/sproutcore/rack/service.rb +8 -2
  111. data/lib/sproutcore/rack.rb +1 -0
  112. data/lib/sproutcore/tools/build.rb +91 -43
  113. data/lib/sproutcore/tools/gen.rb +2 -3
  114. data/lib/sproutcore/tools/manifest.rb +22 -16
  115. data/lib/sproutcore/tools/server.rb +21 -0
  116. data/lib/sproutcore/tools.rb +102 -46
  117. data/lib/sproutcore.rb +30 -5
  118. data/spec/buildtasks/helpers/accept_list +22 -0
  119. data/spec/buildtasks/helpers/accept_list.rb +128 -0
  120. data/spec/buildtasks/helpers/list.json +11 -0
  121. data/spec/buildtasks/manifest/prepare_build_tasks/chance_2x_spec.rb +1 -39
  122. data/spec/buildtasks/manifest/prepare_build_tasks/chance_spec.rb +0 -38
  123. data/spec/buildtasks/manifest/prepare_build_tasks/combine_spec.rb +4 -4
  124. data/spec/buildtasks/manifest/prepare_build_tasks/module_spec.rb +2 -2
  125. data/spec/buildtasks/manifest/prepare_build_tasks/packed_2x_indirect_spec.rb +7 -16
  126. data/spec/buildtasks/manifest/prepare_build_tasks/packed_2x_spec.rb +7 -17
  127. data/spec/buildtasks/manifest/prepare_build_tasks/packed_spec.rb +11 -6
  128. data/spec/fixtures/builder_tests/Buildfile +2 -1
  129. data/spec/fixtures/builder_tests/apps/module_test/modules/required_module/core.js +0 -0
  130. data/spec/lib/builders/module_spec.rb +1 -1
  131. data/spec/spec_helper.rb +1 -0
  132. data/sproutcore.gemspec +4 -9
  133. data/vendor/chance/lib/chance/factory.rb +45 -0
  134. data/vendor/chance/lib/chance/instance/data_url.rb +0 -29
  135. data/vendor/chance/lib/chance/instance/slicing.rb +57 -4
  136. data/vendor/chance/lib/chance/instance/spriting.rb +112 -21
  137. data/vendor/chance/lib/chance/instance.rb +173 -28
  138. data/vendor/chance/lib/chance/parser.rb +80 -52
  139. data/vendor/chance/lib/chance.rb +25 -6
  140. data/vendor/sproutcore/SCCompiler.jar +0 -0
  141. data/vendor/sproutcore/lib/args4j-2.0.12.jar +0 -0
  142. data/vendor/sproutcore/lib/yuicompressor-2.4.2.jar +0 -0
  143. metadata +97 -38
@@ -402,6 +402,7 @@ SC.View.LayoutStyleCalculator = SC.Object.extend({
402
402
 
403
403
  calculate: function() {
404
404
  var layout = this.get('layout'), pdim = null,
405
+ staticLayout = this.get('staticLayout'),
405
406
  translateTop = null,
406
407
  translateLeft = null,
407
408
  turbo = this.get('turbo'),
@@ -413,6 +414,11 @@ SC.View.LayoutStyleCalculator = SC.Object.extend({
413
414
 
414
415
  this._handleMistakes(layout);
415
416
 
417
+ // If the developer sets useStaticLayout and doesn't provide a unique `layout` property, we
418
+ // should not insert the styles "left: 0px; right: 0px; top: 0px; bottom: 0px" as they could
419
+ // conflict with the developer's intention. However, if they do provide a unique `layout`,
420
+ // use it.
421
+ if (staticLayout && layout === SC.View.prototype.layout) return {};
416
422
 
417
423
  // X DIRECTION
418
424
 
@@ -473,21 +479,21 @@ SC.View.LayoutStyleCalculator = SC.Object.extend({
473
479
 
474
480
  if (pendingAnimations) {
475
481
  if (!activeAnimations) activeAnimations = {};
476
-
482
+
477
483
  for (key in pendingAnimations) {
478
484
  if (!pendingAnimations.hasOwnProperty(key)) continue;
479
-
485
+
480
486
  pendingAnimation = pendingAnimations[key];
481
487
  activeAnimation = activeAnimations[key];
482
488
  shouldCancel = NO;
483
-
489
+
484
490
  if (newStyle[key] !== (currentStyle ? currentStyle[key] : null)) shouldCancel = YES;
485
-
491
+
486
492
  // if we have a new animation (an animation property has changed), cancel current
487
493
  if (activeAnimation && (activeAnimation.duration !== pendingAnimation.duration || activeAnimation.timing !== pendingAnimation.timing)) {
488
494
  shouldCancel = YES;
489
495
  }
490
-
496
+
491
497
  if (shouldCancel && activeAnimation) {
492
498
  if (callback = activeAnimation.callback) {
493
499
  if (transformsLength > 0) {
@@ -499,14 +505,14 @@ SC.View.LayoutStyleCalculator = SC.Object.extend({
499
505
  this.runAnimationCallback(callback, null, key, YES);
500
506
  }
501
507
  }
502
-
508
+
503
509
  this.removeAnimationFromLayout(key, YES);
504
510
  }
505
-
511
+
506
512
  activeAnimations[key] = pendingAnimation;
507
513
  }
508
514
  }
509
-
515
+
510
516
  this._activeAnimations = activeAnimations;
511
517
  this._pendingAnimations = null;
512
518
  }
@@ -42,7 +42,7 @@ SC.EMPTY_CHILD_VIEWS_ARRAY.needsClone = YES;
42
42
  SC.CoreView.reopen(
43
43
  /** @scope SC.View.prototype */ {
44
44
 
45
- concatenatedProperties: ['outlets', 'displayProperties', 'classNames', 'renderMixin', 'didCreateLayerMixin', 'willDestroyLayerMixin'],
45
+ concatenatedProperties: ['outlets', 'displayProperties', 'classNames', 'renderMixin', 'didCreateLayerMixin', 'willDestroyLayerMixin', 'classNameBindings', 'attributeBindings'],
46
46
 
47
47
  /**
48
48
  The current pane.
@@ -670,6 +670,11 @@ SC.CoreView.reopen(
670
670
  },
671
671
 
672
672
  applyAttributesToContext: function(context) {
673
+ if (!this.get('layer')) {
674
+ this._applyClassNameBindings();
675
+ this._applyAttributeBindings(context);
676
+ }
677
+
673
678
  context.addClass(this.get('classNames'));
674
679
 
675
680
  if (this.get('isTextSelectable')) { context.addClass('allow-select'); }
@@ -685,6 +690,155 @@ SC.CoreView.reopen(
685
690
  context.attr('role', this.get('ariaRole'));
686
691
  },
687
692
 
693
+ /**
694
+ @private
695
+
696
+ Iterates over the view's `classNameBindings` array, inserts the value
697
+ of the specified property into the `classNames` array, then creates an
698
+ observer to update the view's element if the bound property ever changes
699
+ in the future.
700
+ */
701
+ _applyClassNameBindings: function() {
702
+ var classBindings = this.get('classNameBindings'),
703
+ classNames = this.get('classNames'),
704
+ elem, newClass, dasherizedClass;
705
+
706
+ if (!classBindings) { return; }
707
+
708
+ // Loop through all of the configured bindings. These will be either
709
+ // property names ('isUrgent') or property paths relative to the view
710
+ // ('content.isUrgent')
711
+ classBindings.forEach(function(property) {
712
+
713
+ // Variable in which the old class value is saved. The observer function
714
+ // closes over this variable, so it knows which string to remove when
715
+ // the property changes.
716
+ var oldClass;
717
+
718
+ // Set up an observer on the context. If the property changes, toggle the
719
+ // class name.
720
+ observer = function() {
721
+ // Get the current value of the property
722
+ newClass = this._classStringForProperty(property);
723
+ elem = this.$();
724
+
725
+ // If we had previously added a class to the element, remove it.
726
+ if (oldClass) {
727
+ elem.removeClass(oldClass);
728
+ }
729
+
730
+ // If necessary, add a new class. Make sure we keep track of it so
731
+ // it can be removed in the future.
732
+ if (newClass) {
733
+ elem.addClass(newClass);
734
+ oldClass = newClass;
735
+ } else {
736
+ oldClass = null;
737
+ }
738
+ };
739
+
740
+ this.addObserver(property, this, observer);
741
+
742
+ // Get the class name for the property at its current value
743
+ dasherizedClass = this._classStringForProperty(property);
744
+
745
+ if (dasherizedClass) {
746
+ // Ensure that it gets into the classNames array
747
+ // so it is displayed when we render.
748
+ classNames.push(dasherizedClass);
749
+
750
+ // Save a reference to the class name so we can remove it
751
+ // if the observer fires. Remember that this variable has
752
+ // been closed over by the observer.
753
+ oldClass = dasherizedClass;
754
+ }
755
+ }, this);
756
+ },
757
+
758
+ /**
759
+ Iterates through the view's attribute bindings, sets up observers for each,
760
+ then applies the current value of the attributes to the passed render buffer.
761
+
762
+ @param {SC.RenderBuffer} buffer
763
+ */
764
+ _applyAttributeBindings: function(context) {
765
+ var attributeBindings = this.get('attributeBindings'),
766
+ attributeValue, elem, type;
767
+
768
+ if (!attributeBindings) { return; }
769
+
770
+ attributeBindings.forEach(function(attribute) {
771
+ // Create an observer to add/remove/change the attribute if the
772
+ // JavaScript property changes.
773
+ var observer = function() {
774
+ elem = this.$();
775
+ var currentValue = elem.attr(attribute);
776
+ attributeValue = this.get(attribute);
777
+
778
+ type = typeof attributeValue;
779
+
780
+ if ((type === 'string' || type === 'number') && attributeValue !== currentValue) {
781
+ elem.attr(attribute, attributeValue);
782
+ } else if (attributeValue && type === 'boolean') {
783
+ elem.attr(attribute, attribute);
784
+ } else if (attributeValue === NO) {
785
+ elem.removeAttr(attribute);
786
+ }
787
+ };
788
+
789
+ this.addObserver(attribute, this, observer);
790
+
791
+ // Determine the current value and add it to the render buffer
792
+ // if necessary.
793
+ attributeValue = this.get(attribute);
794
+ type = typeof attributeValue;
795
+
796
+ if (type === 'string' || type === 'number') {
797
+ context.attr(attribute, attributeValue);
798
+ } else if (attributeValue && type === 'boolean') {
799
+ // Apply boolean attributes in the form attribute="attribute"
800
+ context.attr(attribute, attribute);
801
+ }
802
+ }, this);
803
+ },
804
+
805
+ /**
806
+ @private
807
+
808
+ Given a property name, returns a dasherized version of that
809
+ property name if the property evaluates to a non-falsy value.
810
+
811
+ For example, if the view has property `isUrgent` that evaluates to true,
812
+ passing `isUrgent` to this method will return `"is-urgent"`.
813
+ */
814
+ _classStringForProperty: function(property) {
815
+ var split = property.split(':'), className = split[1];
816
+ property = split[0];
817
+
818
+ var val = SC.getPath(this, property);
819
+
820
+ // If value is a Boolean and true, return the dasherized property
821
+ // name.
822
+ if (val === YES) {
823
+ if (className) { return className; }
824
+
825
+ // Normalize property path to be suitable for use
826
+ // as a class name. For exaple, content.foo.barBaz
827
+ // becomes bar-baz.
828
+ return SC.String.dasherize(property.split('.').get('lastObject'));
829
+
830
+ // If the value is not NO, undefined, or null, return the current
831
+ // value of the property.
832
+ } else if (val !== NO && val !== undefined && val !== null) {
833
+ return val;
834
+
835
+ // Nothing to display. Return null so that the old class is removed
836
+ // but no new class is added.
837
+ } else {
838
+ return null;
839
+ }
840
+ },
841
+
688
842
  /**
689
843
  @private
690
844
 
@@ -904,6 +1058,9 @@ SC.CoreView.reopen(
904
1058
  // SC.RootResponder to dispatch incoming events.
905
1059
  SC.View.views[this.get('layerId')] = this;
906
1060
 
1061
+ // setup classNames
1062
+ this.classNames = this.get('classNames').slice();
1063
+
907
1064
  // setup child views. be sure to clone the child views array first
908
1065
  this.childViews = this.get('childViews').slice() ;
909
1066
  this.createChildViews() ; // setup child Views
@@ -729,7 +729,7 @@ SC.Record = SC.Object.extend(
729
729
  @dependsOn status
730
730
  */
731
731
  isError: function() {
732
- return this.get('status') & SC.Record.ERROR;
732
+ return !!(this.get('status') & SC.Record.ERROR);
733
733
  }.property('status').cacheable(),
734
734
 
735
735
  /**
@@ -1336,6 +1336,9 @@ SC.Record.mixin( /** @scope SC.Record */ {
1336
1336
  opts = opts || {};
1337
1337
  var isNested = opts.nested || opts.isNested;
1338
1338
  var attr;
1339
+
1340
+ this._throwUnlessRecordTypeDefined(recordType, 'toMany');
1341
+
1339
1342
  if(isNested){
1340
1343
  attr = SC.ChildrenAttribute.attr(recordType, opts);
1341
1344
  }
@@ -1362,6 +1365,9 @@ SC.Record.mixin( /** @scope SC.Record */ {
1362
1365
  opts = opts || {};
1363
1366
  var isNested = opts.nested || opts.isNested;
1364
1367
  var attr;
1368
+
1369
+ this._throwUnlessRecordTypeDefined(recordType, 'toOne');
1370
+
1365
1371
  if(isNested){
1366
1372
  attr = SC.ChildAttribute.attr(recordType, opts);
1367
1373
  }
@@ -1370,6 +1376,13 @@ SC.Record.mixin( /** @scope SC.Record */ {
1370
1376
  }
1371
1377
  return attr;
1372
1378
  },
1379
+
1380
+ _throwUnlessRecordTypeDefined: function(recordType, relationshipType) {
1381
+ if (!recordType) {
1382
+ throw "Attempted to create " + relationshipType + " attribute with " +
1383
+ "undefined recordType. Did you forget to sc_require a dependency?";
1384
+ }
1385
+ },
1373
1386
 
1374
1387
  /**
1375
1388
  Returns all storeKeys mapped by Id for this record type. This method is
@@ -1439,7 +1452,7 @@ SC.Record.mixin( /** @scope SC.Record */ {
1439
1452
  /** @private - enhance extend to notify SC.Query as well. */
1440
1453
  extend: function() {
1441
1454
  var ret = SC.Object.extend.apply(this, arguments);
1442
- SC.Query._scq_didDefineRecordType(ret);
1455
+ if(SC.Query) SC.Query._scq_didDefineRecordType(ret);
1443
1456
  return ret ;
1444
1457
  }
1445
1458
  }) ;