sproutcore 1.6.0.1-java → 1.7.1.beta-java

Sign up to get free protection for your applications and to get access to all the features.
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.js +158 -1
  33. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/keyboard.js +26 -1
  34. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/layout_style.js +14 -8
  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.rb +30 -5
  95. data/lib/sproutcore/builders.rb +1 -0
  96. data/lib/sproutcore/builders/chance_file.rb +9 -16
  97. data/lib/sproutcore/builders/html.rb +2 -1
  98. data/lib/sproutcore/builders/minify.rb +4 -35
  99. data/lib/sproutcore/builders/module.rb +38 -1
  100. data/lib/sproutcore/builders/split.rb +63 -0
  101. data/lib/sproutcore/builders/strings.rb +7 -1
  102. data/lib/sproutcore/helpers.rb +1 -1
  103. data/lib/sproutcore/helpers/css_split.rb +190 -0
  104. data/lib/sproutcore/helpers/entry_sorter.rb +2 -0
  105. data/lib/sproutcore/helpers/minifier.rb +40 -16
  106. data/lib/sproutcore/helpers/static_helper.rb +35 -17
  107. data/lib/sproutcore/models/manifest.rb +26 -0
  108. data/lib/sproutcore/models/target.rb +12 -1
  109. data/lib/sproutcore/rack.rb +1 -0
  110. data/lib/sproutcore/rack/proxy.rb +244 -225
  111. data/lib/sproutcore/rack/restrict_ip.rb +67 -0
  112. data/lib/sproutcore/rack/service.rb +8 -2
  113. data/lib/sproutcore/tools.rb +102 -46
  114. data/lib/sproutcore/tools/build.rb +91 -43
  115. data/lib/sproutcore/tools/gen.rb +2 -3
  116. data/lib/sproutcore/tools/manifest.rb +22 -16
  117. data/lib/sproutcore/tools/server.rb +21 -0
  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.rb +25 -6
  134. data/vendor/chance/lib/chance/factory.rb +45 -0
  135. data/vendor/chance/lib/chance/instance.rb +173 -28
  136. data/vendor/chance/lib/chance/instance/data_url.rb +0 -29
  137. data/vendor/chance/lib/chance/instance/slicing.rb +57 -4
  138. data/vendor/chance/lib/chance/instance/spriting.rb +112 -21
  139. data/vendor/chance/lib/chance/parser.rb +80 -52
  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 +84 -25
@@ -10,9 +10,15 @@
10
10
 
11
11
  /*globals module test ok same equals */
12
12
 
13
+
13
14
  /* These unit tests verify: layout(), frame(), styleLayout() and clippingFrame(). */
14
15
  (function() {
15
- var parent, child;
16
+ var parent, child, frameKeys, layoutKeys;
17
+
18
+ frameKeys = 'x y width height'.w();
19
+ layoutKeys = ['width','height','top','bottom','marginLeft','marginTop','left','right','zIndex',
20
+ 'minWidth','maxWidth','minHeight','maxHeight','borderTopWidth','borderBottomWidth',
21
+ 'borderLeftWidth','borderRightWidth'];
16
22
 
17
23
  /*
18
24
  helper method to test the layout of a view. Applies the passed layout to a
@@ -31,19 +37,16 @@
31
37
  @returns {void}
32
38
  */
33
39
  function performLayoutTest(layout, no_f, no_s, with_f, with_s, isFixedShouldBe) {
34
- // make sure we add null properties and convert numbers to 'XXpx' to style layout.
35
- var layoutKeys = ('width height top bottom marginLeft marginTop left right zIndex minWidth maxWidth minHeight maxHeight ' +
36
- 'borderTopWidth borderBottomWidth borderLeftWidth borderRightWidth').w();
37
40
  if (SC.platform.supportsCSSTransforms) { layoutKeys.push('transform'); }
38
41
 
39
- var frameKeys = 'x y width height'.w();
40
-
42
+ // make sure we add null properties and convert numbers to 'XXpx' to style layout.
41
43
  layoutKeys.forEach(function(key) {
42
44
  if (no_s[key]===undefined) { no_s[key] = null; }
43
45
  if (with_s[key]===undefined) { with_s[key] = null; }
44
46
 
47
+
45
48
  if (typeof no_s[key] === 'number') { no_s[key] = no_s[key].toString() + 'px'; }
46
- if (typeof with_s[key] === 'number') { with_s[key] = no_s[key].toString() + 'px'; }
49
+ if (typeof with_s[key] === 'number') { with_s[key] = with_s[key].toString() + 'px'; }
47
50
  });
48
51
 
49
52
  // set layout
@@ -85,9 +88,13 @@
85
88
  });
86
89
 
87
90
  if (with_f !== undefined) {
88
- frameKeys.forEach(function(key){
89
- equals(frame[key], with_f[key], "FRAME W/ PARENT %@".fmt(key));
90
- });
91
+ if (frame && with_f) {
92
+ frameKeys.forEach(function(key){
93
+ equals(frame[key], with_f[key], "FRAME W/ PARENT %@".fmt(key));
94
+ });
95
+ } else {
96
+ equals(frame, with_f, "FRAME W/ PARENT");
97
+ }
91
98
  }
92
99
 
93
100
  // check if isFixedLayout is correct
@@ -723,7 +730,32 @@
723
730
  test("for proper null variables");
724
731
  // nothing should get passed through as undefined, instead we want null in certain cases
725
732
 
733
+ module('STATIC LAYOUT VARIATIONS', commonSetup);
734
+
735
+ test("no layout", function() {
736
+
737
+ var no_f = null,
738
+ no_s = {},
739
+ with_f = null,
740
+ with_s = {};
741
+
742
+ child.set('useStaticLayout', true);
743
+
744
+ performLayoutTest(SC.View.prototype.layout, no_f, no_s, with_f, with_s, NO);
745
+ });
746
+
747
+ test("with layout", function() {
748
+
749
+ var layout = { top: 10, left: 10, width: 50, height: 50 },
750
+ no_f = null,
751
+ no_s = { top: 10, left: 10, width: 50, height: 50 },
752
+ with_f = null,
753
+ with_s = { top: 10, left: 10, width: 50, height: 50 };
726
754
 
755
+ child.set('useStaticLayout', true);
756
+
757
+ performLayoutTest(layout, no_f, no_s, with_f, with_s, YES);
758
+ });
727
759
 
728
760
  // test("frame size shifts with top/left/bottom/right", function(){
729
761
  // var error=null;
@@ -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
@@ -51,7 +51,32 @@ SC.View.reopen(
51
51
  @param {SC.Responder} responder
52
52
  */
53
53
  didBecomeKeyResponderFrom: function(responder) {
54
- this.$().focus();
54
+
55
+ // Hack!!!
56
+ // If we try to execute the focus code right now, the iPad will take this as an opportunity to break
57
+ // execution of the current Run Loop (if that Run Loop was started by a timer expiring) to execute
58
+ // any touch event code that is waiting at this time.
59
+ //
60
+ // This becomes a problem in particular for ScrollView's that use a timer to pass touches to their content,
61
+ // because the touchend event can come in while the timer code is executing and pause here to complete
62
+ // the touchend code and then continue the timer code afterward. However, the timer code's
63
+ // execution context will then be out-of-date and will cause a crash in RootResponder's assignTouch().
64
+ //
65
+ // To verify this, use the branch sproutcore/timer_touch_debug in any SproutCore project. Then visit
66
+ // the app launcher http://my.local.machine.ip:4020 on an iPad 1 and simply press one of the app's
67
+ // in the list. The app should crash on the first touch (depending slightly on the speed at which you
68
+ // touch the selection; presses will crash it, taps generally won't). It should occur on the first
69
+ // touch or else try reloading the app until you get the proper touch speed figured out.
70
+ //
71
+ // Using the debug branch, when it crashes, notice how the console statements aren't in order according
72
+ // to the timestamps and notice how there is a big gap in timestamps around this.$().focus() where the
73
+ // touchend block of code runs.
74
+ //
75
+ // -Tyler Keating : tyler@sproutcore.com
76
+
77
+ this.invokeLater(function() {
78
+ this.$().focus();
79
+ });
55
80
  },
56
81
 
57
82
  /**
@@ -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
  }
@@ -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
  }) ;
@@ -12,33 +12,33 @@ sc_require('models/record');
12
12
  A RecordAttribute describes a single attribute on a record. It is used to
13
13
  generate computed properties on records that can automatically convert data
14
14
  types and verify data.
15
-
16
- When defining an attribute on an SC.Record, you can configure it this way:
17
-
18
- title: SC.Record.attr(String, {
15
+
16
+ When defining an attribute on an SC.Record, you can configure it this way:
17
+
18
+ title: SC.Record.attr(String, {
19
19
  defaultValue: 'Untitled',
20
20
  isRequired: YES|NO
21
21
  })
22
-
23
- In addition to having predefined transform types, there is also a way to
22
+
23
+ In addition to having predefined transform types, there is also a way to
24
24
  set a computed relationship on an attribute. A typical example of this would
25
- be if you have record with a parentGuid attribute, but are not able to
25
+ be if you have record with a parentGuid attribute, but are not able to
26
26
  determine which record type to map to before looking at the guid (or any
27
- other attributes). To set up such a computed property, you can attach a
27
+ other attributes). To set up such a computed property, you can attach a
28
28
  function in the attribute definition of the SC.Record subclass:
29
-
29
+
30
30
  relatedToComputed: SC.Record.toOne(function() {
31
31
  return (this.readAttribute('relatedToComputed').indexOf("foo")==0) ? MyApp.Foo : MyApp.Bar;
32
32
  })
33
-
34
- Notice that we are not using .get() to avoid another transform which would
33
+
34
+ Notice that we are not using .get() to avoid another transform which would
35
35
  trigger an infinite loop.
36
-
36
+
37
37
  You usually will not work with RecordAttribute objects directly, though you
38
38
  may extend the class in any way that you like to create a custom attribute.
39
39
 
40
40
  A number of default RecordAttribute types are defined on the SC.Record.
41
-
41
+
42
42
  @extends SC.Object
43
43
  @see SC.Record
44
44
  @see SC.ManyAttribute
@@ -60,75 +60,75 @@ SC.RecordAttribute = SC.Object.extend(
60
60
  value will be substituted instead. Note that `defaultValue`s are not
61
61
  converted, so the value should be in the output type expected by the
62
62
  attribute.
63
-
63
+
64
64
  If you use a `defaultValue` function, the arguments given to it are the
65
65
  record instance and the key.
66
-
66
+
67
67
  @type Object|function
68
68
  @default null
69
69
  */
70
70
  defaultValue: null,
71
-
71
+
72
72
  /**
73
73
  The attribute type. Must be either an object class or a property path
74
- naming a class. The built in handler allows all native types to pass
74
+ naming a class. The built in handler allows all native types to pass
75
75
  through, converts records to ids and dates to UTF strings.
76
-
76
+
77
77
  If you use the `attr()` helper method to create a RecordAttribute instance,
78
78
  it will set this property to the first parameter you pass.
79
-
79
+
80
80
  @type Object|String
81
81
  @default String
82
82
  */
83
83
  type: String,
84
-
84
+
85
85
  /**
86
86
  The underlying attribute key name this attribute should manage. If this
87
87
  property is left empty, then the key will be whatever property name this
88
88
  attribute assigned to on the record. If you need to provide some kind
89
89
  of alternate mapping, this provides you a way to override it.
90
-
90
+
91
91
  @type String
92
92
  @default null
93
93
  */
94
94
  key: null,
95
-
95
+
96
96
  /**
97
97
  If `YES`, then the attribute is required and will fail validation unless
98
98
  the property is set to a non-null or undefined value.
99
-
99
+
100
100
  @type Boolean
101
101
  @default NO
102
102
  */
103
103
  isRequired: NO,
104
-
104
+
105
105
  /**
106
106
  If `NO` then attempts to edit the attribute will be ignored.
107
-
107
+
108
108
  @type Boolean
109
109
  @default YES
110
110
  */
111
- isEditable: YES,
112
-
111
+ isEditable: YES,
112
+
113
113
  /**
114
- If set when using the Date format, expect the ISO8601 date format.
114
+ If set when using the Date format, expect the ISO8601 date format.
115
115
  This is the default.
116
-
116
+
117
117
  @type Boolean
118
118
  @default YES
119
119
  */
120
120
  useIsoDate: YES,
121
-
121
+
122
122
  /**
123
123
  Can only be used for toOne or toMany relationship attributes. If YES,
124
124
  this flag will ensure that any related objects will also be marked
125
- dirty when this record dirtied.
126
-
127
- Useful when you might have multiple related objects that you want to
125
+ dirty when this record dirtied.
126
+
127
+ Useful when you might have multiple related objects that you want to
128
128
  consider in an 'aggregated' state. For instance, by changing a child
129
- object (image) you might also want to automatically mark the parent
129
+ object (image) you might also want to automatically mark the parent
130
130
  (album) dirty as well.
131
-
131
+
132
132
  @type Boolean
133
133
  @default NO
134
134
  */
@@ -154,16 +154,16 @@ SC.RecordAttribute = SC.Object.extend(
154
154
  @default NO
155
155
  */
156
156
  lazilyInstantiate: NO,
157
-
157
+
158
158
  // ..........................................................
159
159
  // HELPER PROPERTIES
160
- //
161
-
160
+ //
161
+
162
162
  /**
163
163
  Returns the type, resolved to a class. If the type property is a regular
164
- class, returns the type unchanged. Otherwise attempts to lookup the
164
+ class, returns the type unchanged. Otherwise attempts to lookup the
165
165
  type as a property path.
166
-
166
+
167
167
  @property
168
168
  @type Object
169
169
  @default String
@@ -173,12 +173,12 @@ SC.RecordAttribute = SC.Object.extend(
173
173
  if (SC.typeOf(ret) === SC.T_STRING) ret = SC.requiredObjectForPropertyPath(ret);
174
174
  return ret ;
175
175
  }.property('type').cacheable(),
176
-
176
+
177
177
  /**
178
178
  Finds the transform handler. Attempts to find a transform that you
179
179
  registered using registerTransform for this attribute's type, otherwise
180
180
  defaults to using the default transform for String.
181
-
181
+
182
182
  @property
183
183
  @type Transform
184
184
  */
@@ -186,7 +186,7 @@ SC.RecordAttribute = SC.Object.extend(
186
186
  var klass = this.get('typeClass') || String,
187
187
  transforms = SC.RecordAttribute.transforms,
188
188
  ret ;
189
-
189
+
190
190
  // walk up class hierarchy looking for a transform handler
191
191
  while(klass && !(ret = transforms[SC.guidFor(klass)])) {
192
192
  // check if super has create property to detect SC.Object's
@@ -194,20 +194,20 @@ SC.RecordAttribute = SC.Object.extend(
194
194
  // otherwise return the function transform handler
195
195
  else klass = SC.T_FUNCTION ;
196
196
  }
197
-
197
+
198
198
  return ret ;
199
199
  }.property('typeClass').cacheable(),
200
-
200
+
201
201
  // ..........................................................
202
202
  // LOW-LEVEL METHODS
203
- //
204
-
205
- /**
206
- Converts the passed value into the core attribute value. This will apply
203
+ //
204
+
205
+ /**
206
+ Converts the passed value into the core attribute value. This will apply
207
207
  any format transforms. You can install standard transforms by adding to
208
- the `SC.RecordAttribute.transforms` hash. See
208
+ the `SC.RecordAttribute.transforms` hash. See
209
209
  SC.RecordAttribute.registerTransform() for more.
210
-
210
+
211
211
  @param {SC.Record} record The record instance
212
212
  @param {String} key The key used to access this attribute on the record
213
213
  @param {Object} value The property value before being transformed
@@ -217,10 +217,10 @@ SC.RecordAttribute = SC.Object.extend(
217
217
  var transform = this.get('transform'),
218
218
  type = this.get('typeClass'),
219
219
  children;
220
-
220
+
221
221
  if (transform && transform.to) {
222
222
  value = transform.to(value, this, type, record, key) ;
223
-
223
+
224
224
  // if the transform needs to do something when its children change, we need to set up an observer for it
225
225
  if(!SC.none(value) && (children = transform.observesChildren)) {
226
226
  var i, len = children.length,
@@ -229,27 +229,27 @@ SC.RecordAttribute = SC.Object.extend(
229
229
  record: record,
230
230
  key: key
231
231
  };
232
-
232
+
233
233
  for(i = 0; i < len; i++) value.addObserver(children[i], this, this._SCRA_childObserver, context);
234
234
  }
235
235
  }
236
-
236
+
237
237
  return value ;
238
238
  },
239
-
239
+
240
240
  /**
241
241
  @private
242
-
242
+
243
243
  Shared observer used by any attribute whose transform creates a seperate
244
244
  object that needs to write back to the datahash when it changes. For
245
245
  example, when enumerable content changes on a `SC.Set` attribute, it
246
246
  writes back automatically instead of forcing you to call `.set` manually.
247
-
247
+
248
248
  This functionality can be used by setting an array named
249
249
  observesChildren on your transform containing the names of keys to
250
250
  observe. When one of them triggers it will call childDidChange on your
251
251
  transform with the same arguments as to and from.
252
-
252
+
253
253
  @param {Object} obj The transformed value that is being observed
254
254
  @param {String} key The key used to access this attribute on the record
255
255
  @param {Object} prev Previous value (not used)
@@ -258,15 +258,15 @@ SC.RecordAttribute = SC.Object.extend(
258
258
  _SCRA_childObserver: function(obj, key, prev, context) {
259
259
  // write the new value back to the record
260
260
  this.call(context.record, context.key, obj);
261
-
261
+
262
262
  // mark the attribute as dirty
263
263
  context.record.notifyPropertyChange(context.key);
264
264
  },
265
265
 
266
- /**
267
- Converts the passed value from the core attribute value. This will apply
266
+ /**
267
+ Converts the passed value from the core attribute value. This will apply
268
268
  any format transforms. You can install standard transforms by adding to
269
- the `SC.RecordAttribute.transforms` hash. See
269
+ the `SC.RecordAttribute.transforms` hash. See
270
270
  `SC.RecordAttribute.registerTransform()` for more.
271
271
 
272
272
  @param {SC.Record} record The record instance
@@ -277,7 +277,7 @@ SC.RecordAttribute = SC.Object.extend(
277
277
  fromType: function(record, key, value) {
278
278
  var transform = this.get('transform'),
279
279
  type = this.get('typeClass');
280
-
280
+
281
281
  if (transform && transform.from) {
282
282
  value = transform.from(value, this, type, record, key);
283
283
  }
@@ -289,7 +289,7 @@ SC.RecordAttribute = SC.Object.extend(
289
289
  parent record, since `SC.RecordAttribute` uses `isProperty` to masquerade
290
290
  as a computed property. Get expects a property be a function, thus we
291
291
  need to implement call.
292
-
292
+
293
293
  @param {SC.Record} record The record instance
294
294
  @param {String} key The key used to access this attribute on the record
295
295
  @param {Object} value The property value if called as a setter
@@ -297,13 +297,13 @@ SC.RecordAttribute = SC.Object.extend(
297
297
  */
298
298
  call: function(record, key, value) {
299
299
  var attrKey = this.get('key') || key, nvalue;
300
-
300
+
301
301
  if ((value !== undefined) && this.get('isEditable')) {
302
- // careful: don't overwrite value here. we want the return value to
302
+ // careful: don't overwrite value here. we want the return value to
303
303
  // cache.
304
304
  nvalue = this.fromType(record, key, value) ; // convert to attribute.
305
- record.writeAttribute(attrKey, nvalue);
306
- }
305
+ record.writeAttribute(attrKey, nvalue);
306
+ }
307
307
 
308
308
  nvalue = value = record.readAttribute(attrKey);
309
309
  if (SC.none(value) && (value = this.get('defaultValue'))) {
@@ -315,40 +315,40 @@ SC.RecordAttribute = SC.Object.extend(
315
315
  }
316
316
  }
317
317
  } else value = this.toType(record, key, value);
318
-
318
+
319
319
  return value ;
320
320
  },
321
321
 
322
322
  // ..........................................................
323
323
  // INTERNAL SUPPORT
324
- //
325
-
324
+ //
325
+
326
326
  /** @private - Make this look like a property so that `get()` will call it. */
327
327
  isProperty: YES,
328
-
328
+
329
329
  /** @private - Make this look cacheable */
330
330
  isCacheable: YES,
331
-
331
+
332
332
  /** @private - needed for KVO `property()` support */
333
333
  dependentKeys: [],
334
-
334
+
335
335
  /** @private */
336
336
  init: function() {
337
337
  sc_super();
338
338
  // setup some internal properties needed for KVO - faking 'cacheable'
339
- this.cacheKey = "__cache__" + SC.guidFor(this) ;
340
- this.lastSetValueKey = "__lastValue__" + SC.guidFor(this) ;
339
+ this.cacheKey = "__cache__recattr__" + SC.guidFor(this) ;
340
+ this.lastSetValueKey = "__lastValue__recattr__" + SC.guidFor(this) ;
341
341
  }
342
342
  }) ;
343
343
 
344
344
  // ..........................................................
345
345
  // CLASS METHODS
346
- //
346
+ //
347
347
 
348
348
  SC.RecordAttribute.mixin(
349
349
  /** @scope SC.RecordAttribute.prototype */{
350
350
  /**
351
- The default method used to create a record attribute instance. Unlike
351
+ The default method used to create a record attribute instance. Unlike
352
352
  `create()`, takes an `attributeType` as the first parameter which will be
353
353
  set on the attribute itself. You can pass a string naming a class or a
354
354
  class itself.
@@ -365,7 +365,7 @@ SC.RecordAttribute.mixin(
365
365
  },
366
366
 
367
367
  /** @private
368
- Hash of registered transforms by class guid.
368
+ Hash of registered transforms by class guid.
369
369
  */
370
370
  transforms: {},
371
371
 
@@ -373,13 +373,13 @@ SC.RecordAttribute.mixin(
373
373
  Call to register a transform handler for a specific type of object. The
374
374
  object you pass can be of any type as long as it responds to the following
375
375
  methods
376
-
376
+
377
377
  - `to(value, attr, klass, record, key)` converts the passed value
378
378
  (which will be of the class expected by the attribute) into the
379
379
  underlying attribute value
380
380
  - `from(value, attr, klass, record, key)` converts the underyling
381
381
  attribute value into a value of the class
382
-
382
+
383
383
  You can also provide an array of keys to observer on the return value.
384
384
  When any of these change, your from method will be called to write the
385
385
  changed object back to the record. For example:
@@ -409,7 +409,7 @@ SC.RecordAttribute.mixin(
409
409
 
410
410
  // ..........................................................
411
411
  // STANDARD ATTRIBUTE TRANSFORMS
412
- //
412
+ //
413
413
 
414
414
  // Object, String, Number just pass through.
415
415
 
@@ -431,8 +431,8 @@ SC.RecordAttribute.registerTransform(Number, {
431
431
 
432
432
  /** @private - generic converter for Strings */
433
433
  SC.RecordAttribute.registerTransform(String, {
434
- /** @private -
435
- convert an arbitrary object value to a String
434
+ /** @private -
435
+ convert an arbitrary object value to a String
436
436
  allow null through as that will be checked separately
437
437
  */
438
438
  to: function(obj) {
@@ -453,7 +453,7 @@ SC.RecordAttribute.registerTransform(Array, {
453
453
  }
454
454
  return obj;
455
455
  },
456
-
456
+
457
457
  observesChildren: ['[]']
458
458
  });
459
459
 
@@ -477,7 +477,7 @@ SC.RecordAttribute.registerTransform(SC.Record, {
477
477
  if (SC.none(id) || (id==="")) return null;
478
478
  else return store.find(recordType, id);
479
479
  },
480
-
480
+
481
481
  /** @private - convert a record instance to a record id */
482
482
  from: function(record) { return record ? record.get('id') : null; }
483
483
  });
@@ -491,7 +491,7 @@ SC.RecordAttribute.registerTransform(SC.T_FUNCTION, {
491
491
  var store = parentRecord.get('store');
492
492
  return store.find(recordType, id);
493
493
  },
494
-
494
+
495
495
  /** @private - convert a record instance to a record id */
496
496
  from: function(record) { return record.get('id'); }
497
497
  });
@@ -508,7 +508,7 @@ SC.RecordAttribute.registerTransform(Date, {
508
508
 
509
509
  var ret ;
510
510
  str = str.toString() || '';
511
-
511
+
512
512
  if (attr.get('useIsoDate')) {
513
513
  var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
514
514
  "(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\\.([0-9]+))?)?" +
@@ -531,34 +531,34 @@ SC.RecordAttribute.registerTransform(Date, {
531
531
 
532
532
  offset -= date.getTimezoneOffset();
533
533
  time = (Number(date) + (offset * 60 * 1000));
534
-
534
+
535
535
  ret = new Date();
536
536
  ret.setTime(Number(time));
537
537
  } else ret = new Date(Date.parse(str));
538
538
  return ret ;
539
539
  },
540
-
540
+
541
541
  _dates: {},
542
-
542
+
543
543
  /** @private - pad with leading zeroes */
544
- _zeropad: function(num) {
545
- return ((num<0) ? '-' : '') + ((num<10) ? '0' : '') + Math.abs(num);
544
+ _zeropad: function(num) {
545
+ return ((num<0) ? '-' : '') + ((num<10) ? '0' : '') + Math.abs(num);
546
546
  },
547
-
547
+
548
548
  /** @private - convert a date to a string */
549
- from: function(date) {
549
+ from: function(date) {
550
550
 
551
551
  if (SC.none(date)) { return null; }
552
552
 
553
553
  var ret = this._dates[date.getTime()];
554
- if (ret) return ret ;
555
-
554
+ if (ret) return ret ;
555
+
556
556
  // figure timezone
557
557
  var zp = this._zeropad,
558
558
  tz = 0-date.getTimezoneOffset()/60;
559
-
559
+
560
560
  tz = (tz === 0) ? 'Z' : '%@:00'.fmt(zp(tz));
561
-
561
+
562
562
  this._dates[date.getTime()] = ret = "%@-%@-%@T%@:%@:%@%@".fmt(
563
563
  zp(date.getFullYear()),
564
564
  zp(date.getMonth()+1),
@@ -567,7 +567,7 @@ SC.RecordAttribute.registerTransform(Date, {
567
567
  zp(date.getMinutes()),
568
568
  zp(date.getSeconds()),
569
569
  tz) ;
570
-
570
+
571
571
  return ret ;
572
572
  }
573
573
  });
@@ -576,18 +576,18 @@ if (SC.DateTime && !SC.RecordAttribute.transforms[SC.guidFor(SC.DateTime)]) {
576
576
  /**
577
577
  Registers a transform to allow `SC.DateTime` to be used as a record
578
578
  attribute, ie `SC.Record.attr(SC.DateTime);`
579
-
579
+
580
580
  Because `SC.RecordAttribute` is in the datastore framework and
581
581
  `SC.DateTime` in the foundation framework, and we don't know which
582
582
  framework is being loaded first, this chunck of code is duplicated in
583
583
  both frameworks.
584
-
584
+
585
585
  IF YOU EDIT THIS CODE MAKE SURE YOU COPY YOUR CHANGES to
586
586
  `record_attribute.js.`
587
587
  */
588
588
 
589
589
  SC.RecordAttribute.registerTransform(SC.DateTime, {
590
-
590
+
591
591
  /** @private
592
592
  Convert a String to a DateTime
593
593
  */
@@ -597,7 +597,7 @@ if (SC.DateTime && !SC.RecordAttribute.transforms[SC.guidFor(SC.DateTime)]) {
597
597
  var format = attr.get('format');
598
598
  return SC.DateTime.parse(str, format ? format : SC.DateTime.recordFormat);
599
599
  },
600
-
600
+
601
601
  /** @private
602
602
  Convert a DateTime to a String
603
603
  */
@@ -607,7 +607,7 @@ if (SC.DateTime && !SC.RecordAttribute.transforms[SC.guidFor(SC.DateTime)]) {
607
607
  return dt.toFormattedString(format ? format : SC.DateTime.recordFormat);
608
608
  }
609
609
  });
610
-
610
+
611
611
  }
612
612
 
613
613
  /**
@@ -617,10 +617,10 @@ SC.RecordAttribute.registerTransform(SC.Set, {
617
617
  to: function(value, attr, type, record, key) {
618
618
  return SC.Set.create(value);
619
619
  },
620
-
620
+
621
621
  from: function(value, attr, type, record, key) {
622
622
  return value.toArray();
623
623
  },
624
-
624
+
625
625
  observesChildren: ['[]']
626
626
  });