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.
- data/CHANGELOG +21 -0
- data/Gemfile +5 -0
- data/Rakefile +26 -13
- data/VERSION.yml +2 -2
- data/lib/Buildfile +43 -4
- data/lib/buildtasks/build.rake +10 -0
- data/lib/buildtasks/helpers/file_rule.rb +22 -0
- data/lib/buildtasks/helpers/file_rule_list.rb +137 -0
- data/lib/buildtasks/manifest.rake +133 -122
- data/lib/frameworks/sproutcore/CHANGELOG.md +69 -2
- data/lib/frameworks/sproutcore/apps/tests/english.lproj/strings.js +1 -0
- data/lib/frameworks/sproutcore/frameworks/bootstrap/system/browser.js +28 -22
- data/lib/frameworks/sproutcore/frameworks/core_foundation/controllers/array.js +9 -5
- data/lib/frameworks/sproutcore/frameworks/core_foundation/controllers/controller.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/controls/button.js +18 -13
- data/lib/frameworks/sproutcore/frameworks/core_foundation/ext/handlebars/bind.js +5 -3
- data/lib/frameworks/sproutcore/frameworks/core_foundation/ext/handlebars/collection.js +2 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/mixins/action_support.js +80 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/mixins/template_helpers/text_field_support.js +84 -116
- data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/pane.js +8 -5
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/event.js +157 -157
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/platform.js +5 -3
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/root_responder.js +6 -6
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/sparse_array.js +10 -7
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/mixins/action_support.js +106 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/template/collection.js +18 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/template/handlebars.js +71 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/attribute_bindings_test.js +38 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/class_name_bindings_test.js +47 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layoutChildViews.js +18 -18
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layoutStyle.js +42 -10
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view.js +158 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/keyboard.js +26 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/layout_style.js +14 -8
- data/lib/frameworks/sproutcore/frameworks/datastore/models/record.js +15 -2
- data/lib/frameworks/sproutcore/frameworks/datastore/models/record_attribute.js +108 -108
- data/lib/frameworks/sproutcore/frameworks/datastore/system/query.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/datastore/system/record_array.js +2 -4
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/record/error_methods.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/single_attribute.js +26 -0
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/query/builders.js +7 -0
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/record_array/error_methods.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/core/system/datetime.js +4 -1
- data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/core/tests/system/datetime.js +6 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/panes/menu.js +26 -5
- data/lib/frameworks/sproutcore/frameworks/desktop/panes/picker.js +97 -96
- data/lib/frameworks/sproutcore/frameworks/desktop/system/drag.js +4 -3
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/menu/ui.js +17 -4
- data/lib/frameworks/sproutcore/frameworks/desktop/views/collection.js +7 -7
- data/lib/frameworks/sproutcore/frameworks/desktop/views/menu_item.js +7 -5
- data/lib/frameworks/sproutcore/frameworks/desktop/views/scroll.js +12 -3
- data/lib/frameworks/sproutcore/frameworks/desktop/views/web.js +23 -14
- data/lib/frameworks/sproutcore/frameworks/experimental/Buildfile +5 -1
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/render_delegates/menu_scroller.js +28 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/tests/menu/scroll.js +235 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/views/menu/scroll.js +363 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/views/menu/scroller.js +250 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/render_delegates/desktop_scroller.js +92 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/render_delegates/native_scroll.js +25 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/render_delegates/scroll.js +33 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/render_delegates/touch_scroller.js +76 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/tests/scroll/integration.js +50 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/tests/scroll/methods.js +143 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/tests/scroll/ui.js +258 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/core_scroll.js +1164 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/core_scroller.js +332 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/desktop/scroll.js +236 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/desktop/scroller.js +347 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/scroll.js +15 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/scroller.js +10 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/touch/scroll.js +804 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/touch/scroller.js +133 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/resources/text_field.css +3 -3
- data/lib/frameworks/sproutcore/frameworks/foundation/validators/number.js +3 -1
- data/lib/frameworks/sproutcore/frameworks/foundation/views/text_field.js +3 -3
- data/lib/frameworks/sproutcore/frameworks/media/views/audio.js +2 -1
- data/lib/frameworks/sproutcore/frameworks/media/views/controls.js +2 -1
- data/lib/frameworks/sproutcore/frameworks/media/views/media_slider.js +2 -4
- data/lib/frameworks/sproutcore/frameworks/media/views/mini_controls.js +2 -4
- data/lib/frameworks/sproutcore/frameworks/media/views/simple_controls.js +2 -4
- data/lib/frameworks/sproutcore/frameworks/media/views/video.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/routing/system/routes.js +29 -3
- data/lib/frameworks/sproutcore/frameworks/runtime/core.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/replace.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/runtime/private/property_chain.js +2 -1
- data/lib/frameworks/sproutcore/frameworks/runtime/system/binding.js +3 -3
- data/lib/frameworks/sproutcore/frameworks/runtime/system/index_set.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/runtime/system/object.js +1 -1
- data/lib/frameworks/sproutcore/themes/ace/resources/collection/normal/list_item.css +2 -2
- data/lib/frameworks/sproutcore/themes/legacy_theme/english.lproj/segmented.css +1 -1
- data/lib/gen/app/templates/apps/@target_name@/Buildfile +3 -5
- data/lib/gen/app/templates/apps/@target_name@/resources/_theme.css +18 -0
- data/lib/gen/project/templates/@filename@/Buildfile +2 -2
- data/lib/sproutcore.rb +30 -5
- data/lib/sproutcore/builders.rb +1 -0
- data/lib/sproutcore/builders/chance_file.rb +9 -16
- data/lib/sproutcore/builders/html.rb +2 -1
- data/lib/sproutcore/builders/minify.rb +4 -35
- data/lib/sproutcore/builders/module.rb +38 -1
- data/lib/sproutcore/builders/split.rb +63 -0
- data/lib/sproutcore/builders/strings.rb +7 -1
- data/lib/sproutcore/helpers.rb +1 -1
- data/lib/sproutcore/helpers/css_split.rb +190 -0
- data/lib/sproutcore/helpers/entry_sorter.rb +2 -0
- data/lib/sproutcore/helpers/minifier.rb +40 -16
- data/lib/sproutcore/helpers/static_helper.rb +35 -17
- data/lib/sproutcore/models/manifest.rb +26 -0
- data/lib/sproutcore/models/target.rb +12 -1
- data/lib/sproutcore/rack.rb +1 -0
- data/lib/sproutcore/rack/proxy.rb +244 -225
- data/lib/sproutcore/rack/restrict_ip.rb +67 -0
- data/lib/sproutcore/rack/service.rb +8 -2
- data/lib/sproutcore/tools.rb +102 -46
- data/lib/sproutcore/tools/build.rb +91 -43
- data/lib/sproutcore/tools/gen.rb +2 -3
- data/lib/sproutcore/tools/manifest.rb +22 -16
- data/lib/sproutcore/tools/server.rb +21 -0
- data/spec/buildtasks/helpers/accept_list +22 -0
- data/spec/buildtasks/helpers/accept_list.rb +128 -0
- data/spec/buildtasks/helpers/list.json +11 -0
- data/spec/buildtasks/manifest/prepare_build_tasks/chance_2x_spec.rb +1 -39
- data/spec/buildtasks/manifest/prepare_build_tasks/chance_spec.rb +0 -38
- data/spec/buildtasks/manifest/prepare_build_tasks/combine_spec.rb +4 -4
- data/spec/buildtasks/manifest/prepare_build_tasks/module_spec.rb +2 -2
- data/spec/buildtasks/manifest/prepare_build_tasks/packed_2x_indirect_spec.rb +7 -16
- data/spec/buildtasks/manifest/prepare_build_tasks/packed_2x_spec.rb +7 -17
- data/spec/buildtasks/manifest/prepare_build_tasks/packed_spec.rb +11 -6
- data/spec/fixtures/builder_tests/Buildfile +2 -1
- data/spec/fixtures/builder_tests/apps/module_test/modules/required_module/core.js +0 -0
- data/spec/lib/builders/module_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- data/sproutcore.gemspec +4 -9
- data/vendor/chance/lib/chance.rb +25 -6
- data/vendor/chance/lib/chance/factory.rb +45 -0
- data/vendor/chance/lib/chance/instance.rb +173 -28
- data/vendor/chance/lib/chance/instance/data_url.rb +0 -29
- data/vendor/chance/lib/chance/instance/slicing.rb +57 -4
- data/vendor/chance/lib/chance/instance/spriting.rb +112 -21
- data/vendor/chance/lib/chance/parser.rb +80 -52
- data/vendor/sproutcore/SCCompiler.jar +0 -0
- data/vendor/sproutcore/lib/args4j-2.0.12.jar +0 -0
- data/vendor/sproutcore/lib/yuicompressor-2.4.2.jar +0 -0
- 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
|
-
|
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] =
|
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
|
-
|
89
|
-
|
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
|
-
|
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 = "
|
340
|
-
this.lastSetValueKey = "
|
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
|
});
|