sproutcore 1.11.0.rc3 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +6 -14
- data/CHANGELOG +5 -0
- data/VERSION.yml +1 -1
- data/lib/frameworks/sproutcore/Buildfile +3 -2
- data/lib/frameworks/sproutcore/CHANGELOG.md +59 -10
- data/lib/frameworks/sproutcore/apps/showcase/resources/main_page.js +1 -0
- data/lib/frameworks/sproutcore/apps/showcase/resources/stylesheet.css +9 -4
- data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/manipulation.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/event.js +0 -10
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/locale.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/root_responder.js +10 -45
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/selection_set.js +3 -3
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/touch.js +76 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/{touch.js → touch_test.js} +64 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/pane/append_remove.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/pane/design_mode_test.js +61 -24
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/createChildViews.js +1 -2
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/destroy.js +0 -3
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/{layoutStyle.js → layout_style_test.js} +4 -4
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layout_test.js +602 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/viewDidResize.js +0 -23
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view.js +18 -17
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/animation.js +5 -5
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/design_mode.js +64 -24
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/layout.js +904 -871
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/layout_style.js +1 -3
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/statechart.js +40 -24
- data/lib/frameworks/sproutcore/frameworks/datastore/data_sources/fixtures.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/datastore/models/record.js +5 -5
- data/lib/frameworks/sproutcore/frameworks/datastore/system/nested_store.js +14 -14
- data/lib/frameworks/sproutcore/frameworks/datastore/system/query.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/datastore/system/record_array.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/datastore/system/store.js +36 -33
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/record/writeAttribute.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/autonomous_dataSourceCallbacks.js +6 -6
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/commitChangesFromNestedStore.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/commitRecord.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/dataSourceCallbacks.js +7 -7
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/destroyRecord.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/recordDidChange.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/retrieveRecord.js +4 -4
- data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/core/system/datetime.js +11 -11
- data/lib/frameworks/sproutcore/frameworks/designer/coders/object.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/desktop/panes/menu.js +30 -1
- data/lib/frameworks/sproutcore/frameworks/desktop/panes/picker.js +12 -1
- data/lib/frameworks/sproutcore/frameworks/desktop/views/menu_scroll.js +5 -3
- data/lib/frameworks/sproutcore/frameworks/desktop/views/menu_scroller_view.js +0 -36
- data/lib/frameworks/sproutcore/frameworks/desktop/views/scroll_view.js +3 -3
- data/lib/frameworks/sproutcore/frameworks/desktop/views/segmented.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/desktop/views/static_content.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/foundation/gestures/pinch_gesture.js +286 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/gestures/swipe_gesture.js +449 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/gestures/tap_gesture.js +259 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/mixins/gesturable.js +218 -30
- data/lib/frameworks/sproutcore/frameworks/foundation/system/gesture.js +259 -158
- data/lib/frameworks/sproutcore/frameworks/foundation/system/string.js +58 -50
- data/lib/frameworks/sproutcore/frameworks/foundation/system/utils/string_measurement.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/foundation/tests/gestures/pinch_gesture_test.js +321 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/tests/gestures/swipe_gesture_test.js +154 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/tests/gestures/tap_gesture_test.js +55 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/gesturable_test.js +233 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/staticLayout.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/foundation/tests/system/gesture_test.js +254 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/views/container.js +1 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/views/text_field.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/legacy/object_keys_polyfill.js +51 -0
- data/lib/frameworks/sproutcore/frameworks/{core_foundation/system/req_anim_frame.js → legacy/request_animation_frame_polyfill.js} +10 -3
- data/lib/frameworks/sproutcore/frameworks/media/views/audio.js +19 -25
- data/lib/frameworks/sproutcore/frameworks/media/views/controls.js +7 -7
- data/lib/frameworks/sproutcore/frameworks/media/views/mini_controls.js +3 -3
- data/lib/frameworks/sproutcore/frameworks/media/views/simple_controls.js +9 -9
- data/lib/frameworks/sproutcore/frameworks/runtime/core.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/insertAt.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/removeAt.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/runtime/ext/array.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/runtime/mixins/array.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/runtime/mixins/freezable.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/runtime/mixins/observable.js +66 -5
- data/lib/frameworks/sproutcore/frameworks/runtime/mixins/tree.js +44 -0
- data/lib/frameworks/sproutcore/frameworks/runtime/private/observer_queue.js +4 -1
- data/lib/frameworks/sproutcore/frameworks/runtime/system/binding.js +0 -25
- data/lib/frameworks/sproutcore/frameworks/runtime/system/enumerator.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/runtime/system/error.js +67 -15
- data/lib/frameworks/sproutcore/frameworks/runtime/system/index_set.js +6 -11
- data/lib/frameworks/sproutcore/frameworks/runtime/system/set.js +6 -6
- data/lib/frameworks/sproutcore/frameworks/runtime/system/string.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/runtime/tests/mixins/observable/{observable.js → observable_test.js} +110 -16
- data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/error.js +21 -0
- data/lib/frameworks/sproutcore/frameworks/statechart/system/statechart.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/template_view/ext/handlebars.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/testing/system/plan.js +1 -1
- data/lib/sproutcore/render_engines/haml.rb +1 -1
- metadata +610 -604
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layout.js +0 -210
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layoutDidChange.js +0 -275
- data/lib/frameworks/sproutcore/frameworks/foundation/gestures/pinch.js +0 -119
- data/lib/frameworks/sproutcore/frameworks/foundation/gestures/swipe.js +0 -234
- data/lib/frameworks/sproutcore/frameworks/foundation/gestures/tap.js +0 -157
@@ -55,29 +55,6 @@ test("parentViewDidResize should only be called when the parent's layout propert
|
|
55
55
|
// equals(callCount, 2, 'parentViewDidResize should invoke twice');
|
56
56
|
});
|
57
57
|
|
58
|
-
/**
|
59
|
-
When a view's layout changes, _checkForResize determines whether the size has changed using a comparison of the previously
|
60
|
-
cached layout and the new (current) layout. If it seems that the view has resized, it calls `viewDidResize`. Previously
|
61
|
-
it would call viewDidResize and then update the _previousLayout cache afterward. This meant that any adjustments that
|
62
|
-
were triggered by viewDidResize (which would in turn call _checkForResize) would compare the new layout against the
|
63
|
-
previous previous layout, instead of just the previous layout.
|
64
|
-
|
65
|
-
Long story short, to ensure that _checkForResize is checking the current layout against the *last* layout, it's important
|
66
|
-
that the last layout, _previousLayout, is updated *before* continuing on.
|
67
|
-
*/
|
68
|
-
test("SC.View.prototype._checkForResize() updates the _previousLayout cache before calling viewDidResize", function () {
|
69
|
-
var view1 = SC.View.create({
|
70
|
-
layout: { width: 200, height: 200 },
|
71
|
-
viewDidResize: function () {
|
72
|
-
ok(this._previousLayout !== originalPreviousLayout, "The previous layout should not be the same anymore.");
|
73
|
-
}
|
74
|
-
}),
|
75
|
-
originalPreviousLayout;
|
76
|
-
|
77
|
-
originalPreviousLayout = view1.get('layout');
|
78
|
-
SC.run(function () { view1.adjust({ width: 100 }); });
|
79
|
-
});
|
80
|
-
|
81
58
|
test("The view's frame should only notify changes when its layout changes if the effective size or position actually change.", function () {
|
82
59
|
var view2 = SC.View.create({
|
83
60
|
frameCallCount: 0,
|
@@ -99,6 +99,14 @@ SC.CoreView.reopen(
|
|
99
99
|
*/
|
100
100
|
createdByParent: false,
|
101
101
|
|
102
|
+
/** @deprecated Version 1.11.0 Please use parentView instead. */
|
103
|
+
owner: function () {
|
104
|
+
//@if(debug)
|
105
|
+
SC.warn("Developer Warning: The `owner` property of SC.View has been deprecated in favor of the `parentView`, which is the same value. Please use `parentView`.");
|
106
|
+
//@endif
|
107
|
+
return this.get('parentView');
|
108
|
+
}.property('parentView').cacheable(),
|
109
|
+
|
102
110
|
/**
|
103
111
|
The current pane.
|
104
112
|
|
@@ -1104,7 +1112,7 @@ SC.CoreView.reopen(
|
|
1104
1112
|
This method is invoked whenever the clippingFrame changes, notifying
|
1105
1113
|
each child view that its clippingFrame has also changed.
|
1106
1114
|
*/
|
1107
|
-
|
1115
|
+
_sc_clippingFrameDidChange: function () {
|
1108
1116
|
this.notifyPropertyChange('clippingFrame');
|
1109
1117
|
},
|
1110
1118
|
|
@@ -1320,8 +1328,6 @@ SC.CoreView.reopen(
|
|
1320
1328
|
// Orphan the view if adopted.
|
1321
1329
|
this._doOrphan();
|
1322
1330
|
|
1323
|
-
// TODO: Deprecate owner in this sense.
|
1324
|
-
this.set('owner', null);
|
1325
1331
|
delete this.page;
|
1326
1332
|
},
|
1327
1333
|
|
@@ -1414,8 +1420,8 @@ SC.CoreView.reopen(
|
|
1414
1420
|
// clone the hash that was given so we do not pollute it if it's being reused
|
1415
1421
|
else { attrs = SC.clone(attrs); }
|
1416
1422
|
|
1417
|
-
// Assign the
|
1418
|
-
attrs.
|
1423
|
+
// Assign the parentView & page to ourself.
|
1424
|
+
attrs.parentView = this;
|
1419
1425
|
if (!attrs.page) { attrs.page = this.page; }
|
1420
1426
|
|
1421
1427
|
// Track that we created this view.
|
@@ -1430,12 +1436,11 @@ SC.CoreView.reopen(
|
|
1430
1436
|
} else {
|
1431
1437
|
view = view.create(attrs);
|
1432
1438
|
}
|
1433
|
-
// Assign the parentView
|
1439
|
+
// Assign the parentView if the view is an instance.
|
1434
1440
|
// TODO: This should not be accepting view instances, for the purpose of lazy code elsewhere in the framework.
|
1435
1441
|
// We should ensure users of `createChildViews` are using appendChild and other manipulation methods.
|
1436
1442
|
} else {
|
1437
1443
|
view.set('parentView', this);
|
1438
|
-
view.set('owner', this);
|
1439
1444
|
view._adopted();
|
1440
1445
|
|
1441
1446
|
if (!view.get('page')) { view.set('page', this.page); }
|
@@ -2292,8 +2297,8 @@ SC.View = SC.CoreView.extend(/** @scope SC.View.prototype */{
|
|
2292
2297
|
// current frame (see original computeFrameWithParentFrame in views/view.js)
|
2293
2298
|
if (this.get('useStaticLayout')) {
|
2294
2299
|
f = sc_super();
|
2295
|
-
f = f ? this.
|
2296
|
-
f = f ? this.
|
2300
|
+
f = f ? this._sc_adjustForBorder(f, layout) : null;
|
2301
|
+
f = f ? this._sc_adjustForScale(f, layout) : null;
|
2297
2302
|
return f;
|
2298
2303
|
}
|
2299
2304
|
|
@@ -2311,15 +2316,11 @@ SC.View = SC.CoreView.extend(/** @scope SC.View.prototype */{
|
|
2311
2316
|
lcY = layout.centerY;
|
2312
2317
|
|
2313
2318
|
if (lW === AUTO) {
|
2314
|
-
|
2315
|
-
SC.Logger.error(error.toString());
|
2316
|
-
throw error;
|
2319
|
+
SC.throw(("%@.layout() cannot use width:auto if staticLayout is disabled").fmt(this), "%@".fmt(this), -1);
|
2317
2320
|
}
|
2318
2321
|
|
2319
2322
|
if (lH === AUTO) {
|
2320
|
-
|
2321
|
-
SC.Logger.error(error.toString());
|
2322
|
-
throw error;
|
2323
|
+
SC.throw(("%@.layout() cannot use height:auto if staticLayout is disabled").fmt(this), "%@".fmt(this), -1);
|
2323
2324
|
}
|
2324
2325
|
|
2325
2326
|
if (!pdim) { pdim = this.computeParentDimensions(layout); }
|
@@ -2440,7 +2441,7 @@ SC.View = SC.CoreView.extend(/** @scope SC.View.prototype */{
|
|
2440
2441
|
// Okay we have all our numbers. Let's adjust them for things.
|
2441
2442
|
|
2442
2443
|
// First, adjust for border.
|
2443
|
-
f = this.
|
2444
|
+
f = this._sc_adjustForBorder(f, layout);
|
2444
2445
|
|
2445
2446
|
// Make sure the width/height fix their min/max (note the inlining of SC.none for performance)...
|
2446
2447
|
/*jshint eqnull:true */
|
@@ -2450,7 +2451,7 @@ SC.View = SC.CoreView.extend(/** @scope SC.View.prototype */{
|
|
2450
2451
|
if ((layout.minWidth != null) && (f.width < layout.minWidth)) f.width = layout.minWidth;
|
2451
2452
|
|
2452
2453
|
// Finally, adjust for scale.
|
2453
|
-
f = this.
|
2454
|
+
f = this._sc_adjustForScale(f, layout);
|
2454
2455
|
|
2455
2456
|
return f;
|
2456
2457
|
},
|
@@ -405,11 +405,6 @@ SC.View.reopen(
|
|
405
405
|
|
406
406
|
// Always run the animation asynchronously so that the original layout is guaranteed to be applied to the DOM.
|
407
407
|
this.invokeNext('_animate');
|
408
|
-
|
409
|
-
// Route.
|
410
|
-
if (this.get('viewState') === SC.CoreView.ATTACHED_SHOWN) {
|
411
|
-
this.set('viewState', SC.CoreView.ATTACHED_SHOWN_ANIMATING);
|
412
|
-
}
|
413
408
|
} else if (!optionsDidChange) {
|
414
409
|
this.invokeNext(function () {
|
415
410
|
this.runAnimationCallback(options, null, false);
|
@@ -433,6 +428,11 @@ SC.View.reopen(
|
|
433
428
|
|
434
429
|
// Apply the animation layout.
|
435
430
|
this.set('layout', animationLayout);
|
431
|
+
|
432
|
+
// Route.
|
433
|
+
if (this.get('viewState') === SC.CoreView.ATTACHED_SHOWN) {
|
434
|
+
this.set('viewState', SC.CoreView.ATTACHED_SHOWN_ANIMATING);
|
435
|
+
}
|
436
436
|
}
|
437
437
|
},
|
438
438
|
|
@@ -67,6 +67,65 @@ SC.View.reopen(
|
|
67
67
|
}
|
68
68
|
},
|
69
69
|
|
70
|
+
_sc_assignProperty: function (key, value) {
|
71
|
+
if (key === 'layout') {
|
72
|
+
var newExplicitLayout = this._sc_computeExplicitLayout(value), // Convert the layout to an explicit layout.
|
73
|
+
layoutDiff = {},
|
74
|
+
explicitLayout = this.get('explicitLayout');
|
75
|
+
for (var layoutKey in newExplicitLayout) {
|
76
|
+
var currentValue = explicitLayout[layoutKey];
|
77
|
+
|
78
|
+
layoutDiff[layoutKey] = currentValue === undefined ? null : currentValue;
|
79
|
+
|
80
|
+
if (layoutKey === 'centerX') {
|
81
|
+
layoutDiff.left = explicitLayout.left;
|
82
|
+
layoutDiff.right = explicitLayout.right;
|
83
|
+
}
|
84
|
+
|
85
|
+
if (layoutKey === 'centerY') {
|
86
|
+
layoutDiff.top = explicitLayout.top;
|
87
|
+
layoutDiff.bottom = explicitLayout.bottom;
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
this._originalProperties.layout = layoutDiff;
|
92
|
+
} else {
|
93
|
+
// Get the original value of the property for reset.
|
94
|
+
this._originalProperties[key] = this.get(key);
|
95
|
+
}
|
96
|
+
|
97
|
+
// Apply the override.
|
98
|
+
if (key === 'layout') {
|
99
|
+
//@if(debug)
|
100
|
+
if (SC.LOG_DESIGN_MODE || this.SC_LOG_DESIGN_MODE) {
|
101
|
+
SC.Logger.log(' - Adjusting %@: %@ (cached as %@)'.fmt(key, SC.inspect(value), SC.inspect(this._originalProperties[key])));
|
102
|
+
}
|
103
|
+
//@endif
|
104
|
+
this.adjust(value);
|
105
|
+
} else {
|
106
|
+
//@if(debug)
|
107
|
+
if (SC.LOG_DESIGN_MODE || this.SC_LOG_DESIGN_MODE) {
|
108
|
+
SC.Logger.log(' - Setting %@: %@ (cached as %@)'.fmt(key, SC.inspect(value), SC.inspect(this._originalProperties[key])));
|
109
|
+
}
|
110
|
+
//@endif
|
111
|
+
this.set(key,value);
|
112
|
+
}
|
113
|
+
},
|
114
|
+
|
115
|
+
_sc_revertProperty: function (key, oldValue) {
|
116
|
+
//@if(debug)
|
117
|
+
if (SC.LOG_DESIGN_MODE || this.SC_LOG_DESIGN_MODE) {
|
118
|
+
SC.Logger.log(' - Resetting %@ to %@'.fmt(key, SC.inspect(oldValue)));
|
119
|
+
}
|
120
|
+
//@endif
|
121
|
+
|
122
|
+
if (key === 'layout') {
|
123
|
+
this.adjust(oldValue);
|
124
|
+
} else {
|
125
|
+
this.set(key, oldValue);
|
126
|
+
}
|
127
|
+
},
|
128
|
+
|
70
129
|
/**
|
71
130
|
Updates the design mode for this view.
|
72
131
|
|
@@ -114,18 +173,13 @@ SC.View.reopen(
|
|
114
173
|
prevProperties = this._originalProperties;
|
115
174
|
if (prevProperties) {
|
116
175
|
//@if(debug)
|
117
|
-
if (SC.LOG_DESIGN_MODE) {
|
118
|
-
SC.Logger.log('%@ — Removing previous design property overrides
|
176
|
+
if (SC.LOG_DESIGN_MODE || this.SC_LOG_DESIGN_MODE) {
|
177
|
+
SC.Logger.log('%@ — Removing previous design property overrides set by "%@":'.fmt(this, lastDesignMode));
|
119
178
|
}
|
120
179
|
//@endif
|
121
180
|
|
122
181
|
for (key in prevProperties) {
|
123
|
-
|
124
|
-
if (SC.LOG_DESIGN_MODE) {
|
125
|
-
SC.Logger.log(' - Resetting %@ to %@'.fmt(key, prevProperties[key]));
|
126
|
-
}
|
127
|
-
//@endif
|
128
|
-
this.set(key, prevProperties[key]);
|
182
|
+
this._sc_revertProperty(key, prevProperties[key]);
|
129
183
|
}
|
130
184
|
|
131
185
|
// Remove the cache.
|
@@ -138,7 +192,7 @@ SC.View.reopen(
|
|
138
192
|
newProperties = SC.merge(modeAdjust[size], modeAdjust[designMode]);
|
139
193
|
|
140
194
|
//@if(debug)
|
141
|
-
if (SC.LOG_DESIGN_MODE) {
|
195
|
+
if (SC.LOG_DESIGN_MODE || this.SC_LOG_DESIGN_MODE) {
|
142
196
|
SC.Logger.log('%@ — Applying design properties for "%@":'.fmt(this, designMode));
|
143
197
|
}
|
144
198
|
//@endif
|
@@ -146,21 +200,7 @@ SC.View.reopen(
|
|
146
200
|
// Cache the original properties for reset.
|
147
201
|
this._originalProperties = {};
|
148
202
|
for (key in newProperties) {
|
149
|
-
|
150
|
-
this._originalProperties[key] = this.get(key);
|
151
|
-
|
152
|
-
//@if(debug)
|
153
|
-
if (SC.LOG_DESIGN_MODE) {
|
154
|
-
SC.Logger.log(' - Setting %@: %@'.fmt(key, newProperties[key]));
|
155
|
-
}
|
156
|
-
//@endif
|
157
|
-
|
158
|
-
// Apply the override.
|
159
|
-
if (key === 'layout') {
|
160
|
-
this.adjust(newProperties[key]);
|
161
|
-
} else {
|
162
|
-
this.set(key, newProperties[key]);
|
163
|
-
}
|
203
|
+
this._sc_assignProperty(key, newProperties[key]);
|
164
204
|
}
|
165
205
|
}
|
166
206
|
}
|
@@ -36,10 +36,12 @@ SC._SCALE_VALUE_REGEX = /^\d+(,\d+){0,2}$/;
|
|
36
36
|
SC.View.reopen(
|
37
37
|
/** @scope SC.View.prototype */ {
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
39
|
+
// ------------------------------------------------------------------------
|
40
|
+
// Properties
|
41
|
+
//
|
42
|
+
|
43
|
+
/* @private Internal variable used to check for layout changes that resize. */
|
44
|
+
_sc_previousLayout: null,
|
43
45
|
|
44
46
|
/**
|
45
47
|
The view's background color. Only recommended for use during prototyping and in views
|
@@ -55,190 +57,261 @@ SC.View.reopen(
|
|
55
57
|
*/
|
56
58
|
backgroundColor: null,
|
57
59
|
|
58
|
-
/* @private Internal variable used to check for layout changes that resize. */
|
59
|
-
_previousLayout: null,
|
60
|
-
|
61
60
|
/**
|
62
|
-
|
63
|
-
|
64
|
-
@type Boolean
|
65
|
-
@default NO
|
61
|
+
The frame of the view including the borders and scale
|
66
62
|
*/
|
67
|
-
|
63
|
+
borderFrame: function () {
|
64
|
+
var frame = this.get('frame'),
|
65
|
+
ret = null;
|
68
66
|
|
69
|
-
|
70
|
-
|
71
|
-
|
67
|
+
if (frame) {
|
68
|
+
/*jshint eqnull:true */
|
69
|
+
var layout = this.get('layout'),
|
70
|
+
defaultValue = layout.border == null ? 0 : layout.border,
|
71
|
+
borderTop = this._sc_explicitValueFor(layout.borderTop, defaultValue),
|
72
|
+
borderRight = this._sc_explicitValueFor(layout.borderRight, defaultValue),
|
73
|
+
borderBottom = this._sc_explicitValueFor(layout.borderBottom, defaultValue),
|
74
|
+
borderLeft = this._sc_explicitValueFor(layout.borderLeft, defaultValue);
|
72
75
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
76
|
+
ret = {
|
77
|
+
x: frame.x,
|
78
|
+
y: frame.y,
|
79
|
+
width: frame.width,
|
80
|
+
height: frame.height
|
81
|
+
};
|
79
82
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
throw new Error("SC.View layout property set to invalid value, %@: %@.".fmt(property, layoutValue));
|
99
|
-
}
|
83
|
+
var scale = frame.scale;
|
84
|
+
/*jshint eqnull:true*/
|
85
|
+
if (scale != null) {
|
86
|
+
var scaledBorderTop = borderTop * scale,
|
87
|
+
scaledBorderRight = borderRight * scale,
|
88
|
+
scaledBorderBottom = borderBottom * scale,
|
89
|
+
scaledBorderLeft = borderLeft * scale;
|
90
|
+
|
91
|
+
ret.scale = scale;
|
92
|
+
ret.x -= scaledBorderLeft;
|
93
|
+
ret.y -= scaledBorderTop;
|
94
|
+
ret.width += scaledBorderLeft + scaledBorderRight;
|
95
|
+
ret.height += scaledBorderTop + scaledBorderBottom;
|
96
|
+
} else {
|
97
|
+
ret.x -= borderLeft;
|
98
|
+
ret.y -= borderTop;
|
99
|
+
ret.width += borderLeft + borderRight;
|
100
|
+
ret.height += borderTop + borderBottom;
|
100
101
|
}
|
101
|
-
break;
|
102
|
-
}
|
103
|
-
//@endif
|
104
102
|
|
105
|
-
|
106
|
-
|
107
|
-
|
103
|
+
if (frame.transformOriginX != null) {
|
104
|
+
ret.transformOriginX = frame.transformOriginX;
|
105
|
+
}
|
108
106
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
var layoutChange = false;
|
113
|
-
if (typeof this.layout === "function" && this._kvo_dependents) {
|
114
|
-
var dependents = this._kvo_dependents[key];
|
115
|
-
if (dependents && dependents.indexOf('layout') !== -1) { layoutChange = true; }
|
107
|
+
if (frame.transformOriginY != null) {
|
108
|
+
ret.transformOriginY = frame.transformOriginY;
|
109
|
+
}
|
116
110
|
}
|
117
111
|
|
118
|
-
|
119
|
-
|
120
|
-
}
|
112
|
+
return ret;
|
113
|
+
}.property('frame').cacheable(),
|
121
114
|
|
122
|
-
// Resume notification as usual.
|
123
|
-
sc_super();
|
124
|
-
},
|
125
115
|
|
126
|
-
/**
|
127
|
-
|
128
|
-
|
116
|
+
/**
|
117
|
+
This this property to YES whenever the view needs to layout its child
|
118
|
+
views. Normally this property is set automatically whenever the layout
|
119
|
+
property for a child view changes.
|
129
120
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
if (animateLayout) {
|
134
|
-
if (newValue === null) {
|
135
|
-
delete animateLayout[key];
|
136
|
-
} else {
|
137
|
-
animateLayout[key] = newValue;
|
138
|
-
}
|
121
|
+
@type Boolean
|
122
|
+
*/
|
123
|
+
childViewsNeedLayout: NO,
|
139
124
|
|
140
|
-
|
141
|
-
|
142
|
-
delete this._pendingAnimations[key];
|
143
|
-
}
|
125
|
+
/**
|
126
|
+
The child view layout plugin to use when laying out child views.
|
144
127
|
|
145
|
-
|
128
|
+
You can set this property to a child layout plugin object to
|
129
|
+
automatically set and adjust the layouts of this view's child views
|
130
|
+
according to some specific layout style. For instance, SproutCore includes
|
131
|
+
two such plugins, SC.View.VERTICAL_STACK and SC.View.HORIZONTAL_STACK.
|
146
132
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
if (!newLayout) newLayout = SC.clone(this.get('layout'));
|
133
|
+
SC.View.VERTICAL_STACK will arrange child views in order in a vertical
|
134
|
+
stack, which only requires that the height of each child view be specified.
|
135
|
+
Likewise, SC.View.HORIZONTAL_STACK does the same in the horizontal
|
136
|
+
direction, which requires that the width of each child view be specified.
|
152
137
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
}
|
138
|
+
Where child layout plugins are extremely useful, besides simplifying
|
139
|
+
the amount of layout code you need to write, is that they can update the
|
140
|
+
layouts automatically as things change. For more details and examples,
|
141
|
+
please see the documentation for SC.View.VERTICAL_STACK and
|
142
|
+
SC.View.HORIZONTAL_STACK.
|
159
143
|
|
160
|
-
|
161
|
-
|
144
|
+
To define your own child view layout plugin, simply create an object that
|
145
|
+
conforms to the SC.ChildViewLayoutProtocol protocol.
|
146
|
+
|
147
|
+
**Note** This should only be set once and is not bindable.
|
148
|
+
|
149
|
+
@type Object
|
150
|
+
@default null
|
151
|
+
*/
|
152
|
+
childViewLayout: null,
|
162
153
|
|
163
154
|
/**
|
164
|
-
|
165
|
-
you pass and set it again. It is more convenient than having to do this
|
166
|
-
yourself sometimes.
|
155
|
+
The options for the given child view layout plugin.
|
167
156
|
|
168
|
-
|
169
|
-
|
157
|
+
These options are specific to the current child layout plugin being used and
|
158
|
+
are used to modify the applied layouts. For example, SC.View.VERTICAL_STACK
|
159
|
+
accepts options like:
|
170
160
|
|
171
|
-
|
172
|
-
|
161
|
+
childViewLayoutOptions: {
|
162
|
+
paddingAfter: 20,
|
163
|
+
paddingBefore: 20,
|
164
|
+
spacing: 10
|
165
|
+
}
|
173
166
|
|
174
|
-
|
175
|
-
|
176
|
-
|
167
|
+
To determine what options may be used for a given plugin and to see what the
|
168
|
+
default options are, please refer to the documentation for the child layout
|
169
|
+
plugin being used.
|
170
|
+
|
171
|
+
@type Object
|
172
|
+
@default null
|
177
173
|
*/
|
178
|
-
|
179
|
-
if (key === undefined) { return this; } // FAST PATH! Nothing to do.
|
174
|
+
childViewLayoutOptions: null,
|
180
175
|
|
176
|
+
/** @private The explicit layout of the view, computed from the layout using the explicit position. */
|
177
|
+
explicitLayout: function () {
|
181
178
|
var layout = this.get('layout'),
|
182
|
-
|
183
|
-
|
184
|
-
// Normalize arguments.
|
185
|
-
if (SC.typeOf(key) === SC.T_STRING) {
|
186
|
-
newLayout = this._sc_applyAdjustment(key, value, layout);
|
187
|
-
} else {
|
188
|
-
for (var aKey in key) {
|
189
|
-
if (!key.hasOwnProperty(aKey)) { continue; }
|
179
|
+
ret = null;
|
190
180
|
|
191
|
-
|
192
|
-
|
181
|
+
if (layout) {
|
182
|
+
ret = this._sc_computeExplicitLayout(layout);
|
193
183
|
}
|
194
184
|
|
195
|
-
|
196
|
-
|
197
|
-
var transitionAdjust = this.get('transitionAdjust');
|
185
|
+
return ret;
|
186
|
+
}.property('layout').cacheable(),
|
198
187
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
this.set('layout', newLayout);
|
204
|
-
}
|
205
|
-
}
|
188
|
+
/**
|
189
|
+
Walks like a duck. Is `true` to indicate that a view has layout support.
|
190
|
+
*/
|
191
|
+
hasLayout: true,
|
206
192
|
|
207
|
-
|
208
|
-
|
193
|
+
/**
|
194
|
+
Whether the view and its child views should be monitored for changes that
|
195
|
+
affect the current child view layout.
|
209
196
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
197
|
+
When `true` and using a childViewLayout plugin, the view and its child views
|
198
|
+
will be observed for any changes that would affect the layout of all the
|
199
|
+
child views. For example, if `isChildViewLayout` is true and using
|
200
|
+
SC.View.VERTICAL_STACK, if any child view's height or visibility changes
|
201
|
+
all of the child views will be re-adjusted.
|
214
202
|
|
215
|
-
|
216
|
-
|
217
|
-
},
|
203
|
+
If you only want to automatically layout the child views once, you can
|
204
|
+
set this to `false` to improve performance.
|
218
205
|
|
219
|
-
|
220
|
-
|
206
|
+
@type Boolean
|
207
|
+
@default true
|
208
|
+
*/
|
209
|
+
isChildViewLayoutLive: true,
|
221
210
|
|
222
211
|
/**
|
223
|
-
|
224
|
-
|
225
|
-
|
212
|
+
Returns whether the height is 'fixed' or not. A fixed height is defined on the layout
|
213
|
+
as an integer number of pixels. Fixed widths are therefore unaffected by changes
|
214
|
+
to their parent view's height.
|
226
215
|
|
227
|
-
|
216
|
+
@field
|
217
|
+
@returns {Boolean} YES if fixed, NO otherwise
|
218
|
+
@test in layout
|
219
|
+
*/
|
220
|
+
isFixedHeight: function() {
|
221
|
+
var layout = this.get('layout');
|
228
222
|
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
223
|
+
// Height is fixed if it has a height and it isn't SC.LAYOUT_AUTO or a percent.
|
224
|
+
return (layout.height !== undefined) &&
|
225
|
+
!SC.isPercentage(layout.height) &&
|
226
|
+
(layout.height !== SC.LAYOUT_AUTO);
|
227
|
+
}.property('layout').cacheable(),
|
228
|
+
|
229
|
+
/**
|
230
|
+
Returns whether the layout is 'fixed' or not. A fixed layout means a
|
231
|
+
fixed left & top position and fixed width & height. Fixed layouts are
|
232
|
+
therefore unaffected by changes to their parent view's layout.
|
233
|
+
|
234
|
+
@returns {Boolean} YES if fixed, NO otherwise
|
235
|
+
@test in layoutStyle
|
236
|
+
*/
|
237
|
+
isFixedLayout: function () {
|
238
|
+
return this.get('isFixedPosition') && this.get('isFixedSize');
|
239
|
+
}.property('isFixedPosition', 'isFixedSize').cacheable(),
|
240
|
+
|
241
|
+
/**
|
242
|
+
Returns whether the position is 'fixed' or not. A fixed position means a
|
243
|
+
fixed left & top position within its parent's frame. Fixed positions are
|
244
|
+
therefore unaffected by changes to their parent view's size.
|
245
|
+
|
246
|
+
@field
|
247
|
+
@returns {Boolean} YES if fixed, NO otherwise
|
248
|
+
@test in layoutStyle
|
249
|
+
*/
|
250
|
+
isFixedPosition: function () {
|
251
|
+
var explicitLayout = this.get('explicitLayout'),
|
252
|
+
left = explicitLayout.left,
|
253
|
+
top = explicitLayout.top,
|
254
|
+
hasFixedLeft,
|
255
|
+
hasFixedTop;
|
256
|
+
|
257
|
+
// Position is fixed if it has left + top, but not as percentages and not as SC.LAYOUT_AUTO.
|
258
|
+
hasFixedLeft = left !== undefined && !SC.isPercentage(left) && left !== SC.LAYOUT_AUTO;
|
259
|
+
hasFixedTop = top !== undefined && !SC.isPercentage(top) && top !== SC.LAYOUT_AUTO;
|
260
|
+
|
261
|
+
return hasFixedLeft && hasFixedTop;
|
262
|
+
}.property('explicitLayout').cacheable(),
|
263
|
+
|
264
|
+
/**
|
265
|
+
Returns whether the size is 'fixed' or not. A fixed size means a fixed
|
266
|
+
width and height. Fixed sizes are therefore unaffected by changes to their
|
267
|
+
parent view's size.
|
268
|
+
|
269
|
+
@field
|
270
|
+
@returns {Boolean} YES if fixed, NO otherwise
|
271
|
+
@test in layout
|
272
|
+
*/
|
273
|
+
isFixedSize: function () {
|
274
|
+
return this.get('isFixedHeight') && this.get('isFixedWidth');
|
275
|
+
}.property('isFixedWidth', 'isFixedHeight').cacheable(),
|
276
|
+
|
277
|
+
/**
|
278
|
+
Returns whether the width is 'fixed' or not. A fixed width is defined on the layout
|
279
|
+
as an integer number of pixels. Fixed widths are therefore unaffected by changes
|
280
|
+
to their parent view's width.
|
281
|
+
|
282
|
+
@field
|
283
|
+
@returns {Boolean} YES if fixed, NO otherwise
|
284
|
+
@test in layout
|
285
|
+
*/
|
286
|
+
isFixedWidth: function() {
|
287
|
+
var layout = this.get('layout');
|
288
|
+
|
289
|
+
// Width is fixed if it has a width and it isn't SC.LAYOUT_AUTO or a percent.
|
290
|
+
return (layout.width !== undefined) &&
|
291
|
+
!SC.isPercentage(layout.width) &&
|
292
|
+
(layout.width !== SC.LAYOUT_AUTO);
|
293
|
+
}.property('layout').cacheable(),
|
294
|
+
|
295
|
+
/**
|
296
|
+
Set the layout to a hash of layout properties to describe in detail how your view
|
297
|
+
should be positioned on screen. Like most application development environments,
|
298
|
+
your views are laid out absolutely, relative to their parent view.
|
299
|
+
|
300
|
+
You can define your layout using combinations of the following positional properties:
|
301
|
+
|
302
|
+
- left
|
303
|
+
- top
|
304
|
+
- right
|
305
|
+
- bottom
|
306
|
+
- height
|
307
|
+
- width
|
308
|
+
- centerX: offset from center, horizontally
|
309
|
+
- centerY: offset from center, vertically
|
310
|
+
- minWidth
|
311
|
+
- minHeight
|
312
|
+
- maxWidth
|
313
|
+
- maxHeight
|
314
|
+
- scale: once positioned, scales the view in place.
|
242
315
|
- transformOriginX, transformOriginY: defines the point (as a decimal percentage) around which
|
243
316
|
your view will scale. (Also impacts rotation; see below.)
|
244
317
|
|
@@ -286,269 +359,395 @@ SC.View.reopen(
|
|
286
359
|
*/
|
287
360
|
layout: { top: 0, left: 0, bottom: 0, right: 0 },
|
288
361
|
|
289
|
-
/**
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
362
|
+
/**
|
363
|
+
The view responsible for laying out this view. The default version
|
364
|
+
returns the current parent view.
|
365
|
+
*/
|
366
|
+
layoutView: function () {
|
367
|
+
return this.get('parentView');
|
368
|
+
}.property('parentView').cacheable(),
|
294
369
|
|
295
|
-
|
296
|
-
|
370
|
+
/**
|
371
|
+
The transition plugin to use when this view is moved or resized by adjusting
|
372
|
+
its layout.
|
297
373
|
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
delete ret.bottom;
|
374
|
+
SC.CoreView uses a pluggable transition architecture where the transition
|
375
|
+
setup, execution and cleanup can be handled by a plugin. This allows you
|
376
|
+
to create complex transition animations and share them across all your views
|
377
|
+
with only a single line of code.
|
303
378
|
|
304
|
-
|
305
|
-
|
306
|
-
if (explicitPosition.right != null) { ret.right = explicitPosition.right; }
|
307
|
-
if (explicitPosition.top != null) { ret.top = explicitPosition.top; }
|
308
|
-
if (explicitPosition.bottom != null) { ret.bottom = explicitPosition.bottom; }
|
309
|
-
if (explicitPosition.centerX != null) { ret.centerX = explicitPosition.centerX; }
|
310
|
-
if (explicitPosition.centerY != null) { ret.centerY = explicitPosition.centerY; }
|
311
|
-
|
312
|
-
// BORDERS
|
313
|
-
// Apply border first, so that the more specific borderX values will override it next.
|
314
|
-
var border = layout.border;
|
315
|
-
if (border != null) {
|
316
|
-
ret.borderTop = border;
|
317
|
-
ret.borderRight = border;
|
318
|
-
ret.borderBottom = border;
|
319
|
-
ret.borderLeft = border;
|
320
|
-
delete ret.border;
|
321
|
-
}
|
379
|
+
There are a number of pre-built transition adjust plugins available in
|
380
|
+
the SproutCore foundation framework:
|
322
381
|
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
382
|
+
SC.View.SMOOTH_ADJUST
|
383
|
+
SC.View.BOUNCE_ADJUST
|
384
|
+
SC.View.SPRING_ADJUST
|
385
|
+
|
386
|
+
To create a custom transition plugin simply create a regular JavaScript
|
387
|
+
object that conforms to the SC.ViewTransitionProtocol protocol.
|
388
|
+
|
389
|
+
NOTE: When creating custom transition adjust plugins, be aware that SC.View
|
390
|
+
will not call the `setup` method of the plugin, only the `run` method.
|
391
|
+
|
392
|
+
@type Object (SC.ViewTransitionProtocol)
|
393
|
+
@default null
|
394
|
+
@since Version 1.10
|
395
|
+
*/
|
396
|
+
transitionAdjust: null,
|
397
|
+
|
398
|
+
/**
|
399
|
+
The options for the given `transitionAdjust` plugin.
|
400
|
+
|
401
|
+
These options are specific to the current transition plugin used and are
|
402
|
+
used to modify the transition animation. To determine what options
|
403
|
+
may be used for a given plugin and to see what the default options are,
|
404
|
+
see the documentation for the transition plugin being used.
|
405
|
+
|
406
|
+
Most transitions will accept a duration and timing option, but may
|
407
|
+
also use other options. For example, SC.View.BOUNCE_ADJUST accepts options
|
408
|
+
like:
|
409
|
+
|
410
|
+
transitionAdjustOptions: {
|
411
|
+
bounciness: 0.5, // how much the adjustment should bounce back each time
|
412
|
+
bounces: 4, // the number of bounces
|
413
|
+
duration: 0.25,
|
414
|
+
delay: 1
|
415
|
+
}
|
416
|
+
|
417
|
+
@type Object
|
418
|
+
@default null
|
419
|
+
@since Version 1.10
|
420
|
+
*/
|
421
|
+
transitionAdjustOptions: null,
|
422
|
+
|
423
|
+
/**
|
424
|
+
Activates use of brower's static layout. To activate, set this property to YES.
|
425
|
+
|
426
|
+
@type Boolean
|
427
|
+
@default NO
|
428
|
+
*/
|
429
|
+
useStaticLayout: NO,
|
430
|
+
|
431
|
+
// ------------------------------------------------------------------------
|
432
|
+
// Methods
|
433
|
+
//
|
434
|
+
|
435
|
+
/** @private */
|
436
|
+
_sc_adjustForBorder: function (frame, layout) {
|
437
|
+
/*jshint eqnull:true */
|
438
|
+
var defaultValue = layout.border == null ? 0 : layout.border,
|
439
|
+
borderTop = this._sc_explicitValueFor(layout.borderTop, defaultValue),
|
440
|
+
borderLeft = this._sc_explicitValueFor(layout.borderLeft, defaultValue),
|
441
|
+
borderBottom = this._sc_explicitValueFor(layout.borderBottom, defaultValue),
|
442
|
+
borderRight = this._sc_explicitValueFor(layout.borderRight, defaultValue);
|
443
|
+
|
444
|
+
frame.x += borderLeft; // The border on the left pushes the frame to the right
|
445
|
+
frame.y += borderTop; // The border on the top pushes the frame down
|
446
|
+
frame.width -= (borderLeft + borderRight); // Border takes up space
|
447
|
+
frame.height -= (borderTop + borderBottom); // Border takes up space
|
448
|
+
|
449
|
+
return frame;
|
450
|
+
},
|
451
|
+
|
452
|
+
/** @private */
|
453
|
+
_sc_adjustForScale: function (frame, layout) {
|
454
|
+
|
455
|
+
// Scale not supported on this platform, ignore the layout values.
|
456
|
+
if (!SC.platform.supportsCSSTransforms) {
|
457
|
+
frame.scale = 1;
|
458
|
+
frame.transformOriginX = frame.transformOriginY = 0.5;
|
459
|
+
|
460
|
+
// Use scale.
|
461
|
+
} else {
|
462
|
+
|
463
|
+
// Get the scale and transform origins, if not provided. (Note inlining of SC.none for performance)
|
464
|
+
/*jshint eqnull:true*/
|
465
|
+
var scale = layout.scale,
|
466
|
+
oX = layout.transformOriginX,
|
467
|
+
oY = layout.transformOriginY;
|
468
|
+
|
469
|
+
// If the scale is set and isn't 1, do some calculations.
|
470
|
+
if (scale != null && scale !== 1) {
|
471
|
+
// Scale the rect.
|
472
|
+
frame = SC.scaleRect(frame, scale, oX, oY);
|
473
|
+
|
474
|
+
// Add the scale and original unscaled height and width.
|
475
|
+
frame.scale = scale;
|
328
476
|
}
|
329
|
-
|
330
|
-
|
477
|
+
|
478
|
+
// If the origin is set and isn't 0.5, include it.
|
479
|
+
if (oX != null && oX !== 0.5) {
|
480
|
+
frame.transformOriginX = oX;
|
331
481
|
}
|
332
|
-
|
333
|
-
|
482
|
+
|
483
|
+
// If the origin is set and isn't 0.5, include it.
|
484
|
+
if (oY != null && oY !== 0.5) {
|
485
|
+
frame.transformOriginY = oY;
|
334
486
|
}
|
335
487
|
}
|
336
488
|
|
337
|
-
|
338
|
-
|
489
|
+
// Make sure width/height are never < 0.
|
490
|
+
if (frame.height < 0) frame.height = 0;
|
491
|
+
if (frame.width < 0) frame.width = 0;
|
339
492
|
|
340
|
-
|
341
|
-
|
342
|
-
var layout = this.get('layout'),
|
343
|
-
ret;
|
493
|
+
return frame;
|
494
|
+
},
|
344
495
|
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
if (hasLeft) {
|
359
|
-
ret.left = layout.left;
|
360
|
-
} else if (!hasCenterX && !(hasWidth && hasRight)) {
|
361
|
-
ret.left = 0;
|
496
|
+
/** @private Apply the adjustment to a clone of the layout (cloned unless newLayout is passed in) */
|
497
|
+
_sc_applyAdjustment: function (key, newValue, layout, newLayout) {
|
498
|
+
var animateLayout = this._animateLayout;
|
499
|
+
|
500
|
+
// If a call to animate occurs in the same run loop, the animation layout
|
501
|
+
// would still be applied in the next run loop, potentially overriding this
|
502
|
+
// adjustment. So we need to cancel the animation layout.
|
503
|
+
if (animateLayout) {
|
504
|
+
if (newValue === null) {
|
505
|
+
delete animateLayout[key];
|
506
|
+
} else {
|
507
|
+
animateLayout[key] = newValue;
|
362
508
|
}
|
363
509
|
|
364
|
-
if (
|
365
|
-
|
366
|
-
|
367
|
-
ret.right = 0;
|
510
|
+
if (this._pendingAnimations && this._pendingAnimations[key]) {
|
511
|
+
// Adjusting a value that was about to be animated cancels the animation.
|
512
|
+
delete this._pendingAnimations[key];
|
368
513
|
}
|
369
514
|
|
370
|
-
|
371
|
-
// Debug-only warning when layout isn't valid.
|
372
|
-
// UNUSED: This is too noisy for certain views that adjust their own layouts based on top of the default layout.
|
373
|
-
// if (hasRight && hasLeft && hasWidth) {
|
374
|
-
// SC.warn("Developer Warning: When setting `width` in the layout, you must only set `left` or `right`, but not both: %@".fmt(this));
|
375
|
-
// }
|
376
|
-
//@endif
|
515
|
+
}
|
377
516
|
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
517
|
+
// Ignore undefined values or values equal to the current value.
|
518
|
+
/*jshint eqeqeq:false*/
|
519
|
+
if (newValue !== undefined && layout[key] != newValue) { // coerced so '100' == 100
|
520
|
+
// Only clone the layout if it is not given.
|
521
|
+
if (!newLayout) newLayout = SC.clone(this.get('layout'));
|
383
522
|
|
384
|
-
if (
|
385
|
-
|
386
|
-
} else
|
387
|
-
|
523
|
+
if (newValue === null) {
|
524
|
+
delete newLayout[key];
|
525
|
+
} else {
|
526
|
+
newLayout[key] = newValue;
|
388
527
|
}
|
528
|
+
}
|
389
529
|
|
390
|
-
|
391
|
-
|
392
|
-
// UNUSED: This is too noisy for certain views that adjust their own layouts based on top of the default layout.
|
393
|
-
// if (hasBottom && hasTop && hasHeight) {
|
394
|
-
// SC.warn("Developer Warning: When setting `height` in the layout, you must only set `top` or `bottom`, but not both: %@".fmt(this));
|
395
|
-
// }
|
396
|
-
//@endif
|
530
|
+
return newLayout;
|
531
|
+
},
|
397
532
|
|
398
|
-
|
399
|
-
|
400
|
-
|
533
|
+
/** @private */
|
534
|
+
_sc_checkForResize: function (previousLayout, currentLayout) {
|
535
|
+
// Did our layout change in a way that could cause us to have changed size? If
|
536
|
+
// not, then there's no need to invalidate the frames of our child views.
|
537
|
+
var didResizeHeight = true,
|
538
|
+
didResizeWidth = true,
|
539
|
+
didResize = true;
|
401
540
|
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
}
|
407
|
-
//@endif
|
408
|
-
}
|
541
|
+
// We test the new layout to see if we believe it will affect the view's frame.
|
542
|
+
// Since all the child view frames may depend on the parent's frame, it's
|
543
|
+
// best only to notify a frame change when it actually happens.
|
544
|
+
/*jshint eqnull:true*/
|
409
545
|
|
410
|
-
|
411
|
-
|
546
|
+
// Simple test: Width is defined and hasn't changed.
|
547
|
+
// Complex test: No defined width, left or right haven't changed.
|
548
|
+
if (previousLayout != null &&
|
549
|
+
((previousLayout.width != null &&
|
550
|
+
previousLayout.width === currentLayout.width) ||
|
551
|
+
(previousLayout.width == null &&
|
552
|
+
currentLayout.width == null &&
|
553
|
+
previousLayout.left === currentLayout.left &&
|
554
|
+
previousLayout.right === currentLayout.right))) {
|
555
|
+
didResizeWidth = false;
|
556
|
+
}
|
412
557
|
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
558
|
+
// Simple test: Height is defined and hasn't changed.
|
559
|
+
// Complex test: No defined height, top or bottom haven't changed.
|
560
|
+
if (!didResizeWidth &&
|
561
|
+
((previousLayout.height != null &&
|
562
|
+
previousLayout.height === currentLayout.height) ||
|
563
|
+
(previousLayout.height == null &&
|
564
|
+
currentLayout.height == null &&
|
565
|
+
previousLayout.top === currentLayout.top &&
|
566
|
+
previousLayout.bottom === currentLayout.bottom))) {
|
567
|
+
didResizeHeight = false;
|
420
568
|
}
|
421
569
|
|
422
|
-
|
423
|
-
|
570
|
+
// Border test: Even if the width & height haven't changed, a change in a border would be a resize.
|
571
|
+
if (!didResizeHeight && !didResizeWidth) {
|
572
|
+
didResize = !(previousLayout.border === currentLayout.border &&
|
573
|
+
previousLayout.borderTop === currentLayout.borderTop &&
|
574
|
+
previousLayout.borderLeft === currentLayout.borderLeft &&
|
575
|
+
previousLayout.borderBottom === currentLayout.borderBottom &&
|
576
|
+
previousLayout.borderRight === currentLayout.borderRight);
|
577
|
+
}
|
424
578
|
|
425
|
-
|
426
|
-
|
427
|
-
fixed left & top position and fixed width & height. Fixed layouts are
|
428
|
-
therefore unaffected by changes to their parent view's layout.
|
579
|
+
return didResize;
|
580
|
+
},
|
429
581
|
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
isFixedLayout: function () {
|
434
|
-
return this.get('isFixedPosition') && this.get('isFixedSize');
|
435
|
-
}.property('isFixedPosition', 'isFixedSize').cacheable(),
|
582
|
+
/** @private Called when the child view layout plugin or options change. */
|
583
|
+
_cvl_childViewLayoutDidChange: function () {
|
584
|
+
this.set('childViewsNeedLayout', true);
|
436
585
|
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
therefore unaffected by changes to their parent view's size.
|
586
|
+
// Filter the input channel.
|
587
|
+
this.invokeOnce(this.layoutChildViewsIfNeeded);
|
588
|
+
},
|
441
589
|
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
isFixedPosition: function () {
|
447
|
-
var explicitPosition = this.get('explicitPosition'),
|
448
|
-
left = explicitPosition.left,
|
449
|
-
top = explicitPosition.top,
|
450
|
-
hasFixedLeft,
|
451
|
-
hasFixedTop;
|
590
|
+
/** @private Called when the child views change. */
|
591
|
+
_cvl_childViewsDidChange: function () {
|
592
|
+
this._cvl_teardownChildViewsLiveLayout();
|
593
|
+
this._cvl_setupChildViewsLiveLayout();
|
452
594
|
|
453
|
-
|
454
|
-
hasFixedLeft = left !== undefined && !SC.isPercentage(left) && left !== SC.LAYOUT_AUTO;
|
455
|
-
hasFixedTop = top !== undefined && !SC.isPercentage(top) && top !== SC.LAYOUT_AUTO;
|
595
|
+
this.set('childViewsNeedLayout', true);
|
456
596
|
|
457
|
-
|
458
|
-
|
597
|
+
// Filter the input channel.
|
598
|
+
this.invokeOnce(this.layoutChildViewsIfNeeded);
|
599
|
+
},
|
459
600
|
|
460
|
-
/**
|
461
|
-
|
462
|
-
|
463
|
-
|
601
|
+
/** @private Add observers to the child views for automatic child view layout. */
|
602
|
+
_cvl_setupChildViewsLiveLayout: function () {
|
603
|
+
var childViewLayout = this.childViewLayout,
|
604
|
+
childViews,
|
605
|
+
childLayoutProperties = childViewLayout.childLayoutProperties || [];
|
464
606
|
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
isFixedSize: function () {
|
470
|
-
return this.get('isFixedHeight') && this.get('isFixedWidth');
|
471
|
-
}.property('isFixedWidth', 'isFixedHeight').cacheable(),
|
607
|
+
// Create a reference to the current child views so that we can clean them if they change.
|
608
|
+
childViews = this._cvl_childViews = this.get('childViews');
|
609
|
+
for (var i = 0, len = childLayoutProperties.length; i < len; i++) {
|
610
|
+
var observedProperty = childLayoutProperties[i];
|
472
611
|
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
612
|
+
for (var j = 0, jlen = childViews.get('length'); j < jlen; j++) {
|
613
|
+
var childView = childViews.objectAt(j);
|
614
|
+
if (!childView.get('useAbsoluteLayout') && !childView.get('useStaticLayout')) {
|
615
|
+
childView.addObserver(observedProperty, this, this._cvl_childViewLayoutDidChange);
|
616
|
+
}
|
617
|
+
}
|
618
|
+
}
|
619
|
+
},
|
477
620
|
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
var layout = this.get('layout');
|
621
|
+
/** @private Remove observers from the child views for automatic child view layout. */
|
622
|
+
_cvl_teardownChildViewsLiveLayout: function () {
|
623
|
+
var childViewLayout = this.childViewLayout,
|
624
|
+
childViews = this._cvl_childViews || [],
|
625
|
+
childLayoutProperties = childViewLayout.childLayoutProperties || [];
|
484
626
|
|
485
|
-
|
486
|
-
|
487
|
-
!SC.isPercentage(layout.height) &&
|
488
|
-
(layout.height !== SC.LAYOUT_AUTO);
|
489
|
-
}.property('layout').cacheable(),
|
627
|
+
for (var i = 0, len = childLayoutProperties.length; i < len; i++) {
|
628
|
+
var observedProperty = childLayoutProperties[i];
|
490
629
|
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
630
|
+
for (var j = 0, jlen = childViews.get('length'); j < jlen; j++) {
|
631
|
+
var childView = childViews.objectAt(j);
|
632
|
+
if (!childView.get('useAbsoluteLayout') && !childView.get('useStaticLayout')) {
|
633
|
+
childView.removeObserver(observedProperty, this, this._cvl_childViewLayoutDidChange);
|
634
|
+
}
|
635
|
+
}
|
636
|
+
}
|
637
|
+
},
|
495
638
|
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
*/
|
500
|
-
isFixedWidth: function() {
|
501
|
-
var layout = this.get('layout');
|
639
|
+
/** @private Computes the explicit layout. */
|
640
|
+
_sc_computeExplicitLayout: function (layout) {
|
641
|
+
var ret = SC.copy(layout);
|
502
642
|
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
643
|
+
/* jshint eqnull:true */
|
644
|
+
var hasBottom = (layout.bottom != null);
|
645
|
+
var hasRight = (layout.right != null);
|
646
|
+
var hasLeft = (layout.left != null);
|
647
|
+
var hasTop = (layout.top != null);
|
648
|
+
var hasCenterX = (layout.centerX != null);
|
649
|
+
var hasCenterY = (layout.centerY != null);
|
650
|
+
var hasHeight = (layout.height != null); // || (layout.maxHeight != null)
|
651
|
+
var hasWidth = (layout.width != null); // || (layout.maxWidth != null)
|
508
652
|
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
653
|
+
/*jshint eqnull:true */
|
654
|
+
// Left + Top take precedence (left & right & width becomes left & width).
|
655
|
+
delete ret.right; // Right will be set if needed below.
|
656
|
+
delete ret.bottom; // Bottom will be set if needed below.
|
513
657
|
|
514
|
-
|
515
|
-
|
516
|
-
|
658
|
+
if (hasLeft) {
|
659
|
+
ret.left = layout.left;
|
660
|
+
} else if (!hasCenterX && !(hasWidth && hasRight)) {
|
661
|
+
ret.left = 0;
|
662
|
+
}
|
517
663
|
|
518
|
-
|
519
|
-
|
664
|
+
if (hasRight && !(hasLeft && hasWidth)) {
|
665
|
+
ret.right = layout.right;
|
666
|
+
} else if (!hasCenterX && !hasWidth) {
|
667
|
+
ret.right = 0;
|
668
|
+
}
|
520
669
|
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
},
|
670
|
+
//@if(debug)
|
671
|
+
// Debug-only warning when layout isn't valid.
|
672
|
+
// UNUSED: This is too noisy for certain views that adjust their own layouts based on top of the default layout.
|
673
|
+
// if (hasRight && hasLeft && hasWidth) {
|
674
|
+
// SC.warn("Developer Warning: When setting `width` in the layout, you must only set `left` or `right`, but not both: %@".fmt(this));
|
675
|
+
// }
|
676
|
+
//@endif
|
529
677
|
|
530
|
-
|
531
|
-
|
532
|
-
|
678
|
+
if (hasTop) {
|
679
|
+
ret.top = layout.top;
|
680
|
+
} else if (!hasCenterY && !(hasHeight && hasBottom)) {
|
681
|
+
ret.top = 0;
|
682
|
+
}
|
533
683
|
|
534
|
-
|
535
|
-
|
536
|
-
|
684
|
+
if (hasBottom && !(hasTop && hasHeight)) {
|
685
|
+
ret.bottom = layout.bottom;
|
686
|
+
} else if (!hasCenterY && !hasHeight) {
|
687
|
+
ret.bottom = 0;
|
688
|
+
}
|
537
689
|
|
538
|
-
|
539
|
-
|
690
|
+
//@if(debug)
|
691
|
+
// Debug-only warning when layout isn't valid.
|
692
|
+
// UNUSED: This is too noisy for certain views that adjust their own layouts based on top of the default layout.
|
693
|
+
// if (hasBottom && hasTop && hasHeight) {
|
694
|
+
// SC.warn("Developer Warning: When setting `height` in the layout, you must only set `top` or `bottom`, but not both: %@".fmt(this));
|
695
|
+
// }
|
696
|
+
//@endif
|
697
|
+
|
698
|
+
// CENTERS
|
699
|
+
if (hasCenterX) {
|
700
|
+
ret.centerX = layout.centerX;
|
701
|
+
|
702
|
+
//@if(debug)
|
703
|
+
// Debug-only warning when layout isn't valid.
|
704
|
+
if (hasCenterX && !hasWidth) {
|
705
|
+
SC.warn("Developer Warning: When setting `centerX` in the layout, you must also define the `width`: %@".fmt(this));
|
706
|
+
}
|
707
|
+
//@endif
|
708
|
+
}
|
709
|
+
|
710
|
+
if (hasCenterY) {
|
711
|
+
ret.centerY = layout.centerY;
|
712
|
+
|
713
|
+
//@if(debug)
|
714
|
+
// Debug-only warning when layout isn't valid.
|
715
|
+
if (hasCenterY && !hasHeight) {
|
716
|
+
SC.warn("Developer Warning: When setting `centerY` in the layout, you must also define the `height`: %@".fmt(this));
|
717
|
+
}
|
718
|
+
//@endif
|
719
|
+
}
|
720
|
+
|
721
|
+
// BORDERS
|
722
|
+
// Apply border first, so that the more specific borderX values will override it next.
|
723
|
+
var border = layout.border;
|
724
|
+
if (border != null) {
|
725
|
+
ret.borderTop = border;
|
726
|
+
ret.borderRight = border;
|
727
|
+
ret.borderBottom = border;
|
728
|
+
ret.borderLeft = border;
|
729
|
+
delete ret.border;
|
730
|
+
}
|
731
|
+
|
732
|
+
// Override generic border with more specific borderX.
|
733
|
+
if (layout.borderTop != null) {
|
734
|
+
ret.borderTop = layout.borderTop;
|
735
|
+
}
|
736
|
+
if (layout.borderRight != null) {
|
737
|
+
ret.borderRight = layout.borderRight;
|
738
|
+
}
|
739
|
+
if (layout.borderBottom != null) {
|
740
|
+
ret.borderBottom = layout.borderBottom;
|
741
|
+
}
|
742
|
+
if (layout.borderLeft != null) {
|
743
|
+
ret.borderLeft = layout.borderLeft;
|
744
|
+
}
|
540
745
|
|
541
|
-
|
542
|
-
@param {SC.View} targetView the target view to convert to
|
543
|
-
@returns {Rect} converted frame
|
544
|
-
@test in converFrames
|
545
|
-
*/
|
546
|
-
convertFrameFromView: function (frame, targetView) {
|
547
|
-
return this._convertFrameFromViewHelper(frame, targetView, this);
|
746
|
+
return ret;
|
548
747
|
},
|
549
748
|
|
550
749
|
/** @private */
|
551
|
-
|
750
|
+
_sc_convertFrameFromViewHelper: function (frame, fromView, targetView) {
|
552
751
|
var myX = frame.x, myY = frame.y, myWidth = frame.width, myHeight = frame.height, view, f;
|
553
752
|
|
554
753
|
// first, walk up from the view of the frame, up to the top level
|
@@ -605,324 +804,150 @@ SC.View.reopen(
|
|
605
804
|
return { x: myX, y: myY, width: myWidth, height: myHeight };
|
606
805
|
},
|
607
806
|
|
608
|
-
/**
|
609
|
-
Attempt to scroll the view to visible. This will walk up the parent
|
610
|
-
view hierarchy looking looking for a scrollable view. It will then
|
611
|
-
call scrollToVisible() on it.
|
612
|
-
|
613
|
-
Returns YES if an actual scroll took place, no otherwise.
|
614
|
-
|
615
|
-
@returns {Boolean}
|
616
|
-
*/
|
617
|
-
scrollToVisible: function () {
|
618
|
-
var pv = this.get('parentView');
|
619
|
-
while (pv && !pv.get('isScrollable')) { pv = pv.get('parentView'); }
|
620
|
-
|
621
|
-
// found view, first make it scroll itself visible then scroll this.
|
622
|
-
if (pv) {
|
623
|
-
pv.scrollToVisible();
|
624
|
-
return pv.scrollToVisible(this);
|
625
|
-
} else {
|
626
|
-
return NO;
|
627
|
-
}
|
628
|
-
},
|
629
|
-
|
630
807
|
/** @private */
|
631
808
|
_sc_explicitValueFor: function (givenValue, impliedValue) {
|
632
809
|
return givenValue === undefined ? impliedValue : givenValue;
|
633
810
|
},
|
634
811
|
|
635
|
-
/** @private */
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
borderTop = this._sc_explicitValueFor(layout.borderTop, defaultValue),
|
640
|
-
borderLeft = this._sc_explicitValueFor(layout.borderLeft, defaultValue),
|
641
|
-
borderBottom = this._sc_explicitValueFor(layout.borderBottom, defaultValue),
|
642
|
-
borderRight = this._sc_explicitValueFor(layout.borderRight, defaultValue);
|
643
|
-
|
644
|
-
frame.x += borderLeft; // The border on the left pushes the frame to the right
|
645
|
-
frame.y += borderTop; // The border on the top pushes the frame down
|
646
|
-
frame.width -= (borderLeft + borderRight); // Border takes up space
|
647
|
-
frame.height -= (borderTop + borderBottom); // Border takes up space
|
648
|
-
|
649
|
-
return frame;
|
650
|
-
},
|
651
|
-
|
652
|
-
/** @private */
|
653
|
-
_adjustForScale: function (frame, layout) {
|
654
|
-
|
655
|
-
// Scale not supported on this platform, ignore the layout values.
|
656
|
-
if (!SC.platform.supportsCSSTransforms) {
|
657
|
-
frame.scale = 1;
|
658
|
-
frame.transformOriginX = frame.transformOriginY = 0.5;
|
659
|
-
|
660
|
-
// Use scale.
|
661
|
-
} else {
|
662
|
-
|
663
|
-
// Get the scale and transform origins, if not provided. (Note inlining of SC.none for performance)
|
664
|
-
/*jshint eqnull:true*/
|
665
|
-
var scale = layout.scale,
|
666
|
-
oX = layout.transformOriginX,
|
667
|
-
oY = layout.transformOriginY;
|
668
|
-
|
669
|
-
// If the scale is set and isn't 1, do some calculations.
|
670
|
-
if (scale != null && scale !== 1) {
|
671
|
-
// Scale the rect.
|
672
|
-
frame = SC.scaleRect(frame, scale, oX, oY);
|
673
|
-
|
674
|
-
// Add the scale and original unscaled height and width.
|
675
|
-
frame.scale = scale;
|
676
|
-
}
|
677
|
-
|
678
|
-
// If the origin is set and isn't 0.5, include it.
|
679
|
-
if (oX != null && oX !== 0.5) {
|
680
|
-
frame.transformOriginX = oX;
|
681
|
-
}
|
682
|
-
|
683
|
-
// If the origin is set and isn't 0.5, include it.
|
684
|
-
if (oY != null && oY !== 0.5) {
|
685
|
-
frame.transformOriginY = oY;
|
686
|
-
}
|
687
|
-
}
|
688
|
-
|
689
|
-
// Make sure width/height are never < 0.
|
690
|
-
if (frame.height < 0) frame.height = 0;
|
691
|
-
if (frame.width < 0) frame.width = 0;
|
812
|
+
/** @private Attempts to run a transition adjust, ensuring any showing transitions are stopped in place. */
|
813
|
+
_sc_transitionAdjust: function (layout) {
|
814
|
+
var transitionAdjust = this.get('transitionAdjust'),
|
815
|
+
options = this.get('transitionAdjustOptions') || {};
|
692
816
|
|
693
|
-
|
817
|
+
// Execute the adjusting transition.
|
818
|
+
transitionAdjust.run(this, options, layout);
|
694
819
|
},
|
695
820
|
|
696
|
-
/**
|
697
|
-
|
698
|
-
var parentView = this.get('parentView'),
|
699
|
-
parentFrame = (parentView) ? parentView.get('frame') : null,
|
700
|
-
ret;
|
821
|
+
/** @private
|
822
|
+
Invoked by other views to notify this view that its frame has changed.
|
701
823
|
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
} else if (frame) {
|
708
|
-
ret = {
|
709
|
-
width: (frame.left || 0) + (frame.width || 0) + (frame.right || 0),
|
710
|
-
height: (frame.top || 0) + (frame.height || 0) + (frame.bottom || 0)
|
711
|
-
};
|
712
|
-
} else {
|
713
|
-
ret = {
|
714
|
-
width: 0,
|
715
|
-
height: 0
|
716
|
-
};
|
717
|
-
}
|
824
|
+
This notifies the view that its frame property has changed,
|
825
|
+
then notifies its child views that their clipping frames may have changed.
|
826
|
+
*/
|
827
|
+
_sc_viewFrameDidChange: function () {
|
828
|
+
this.notifyPropertyChange('frame');
|
718
829
|
|
719
|
-
|
830
|
+
// Notify the children that their clipping frame may have changed. Top-down, because a child's
|
831
|
+
// clippingFrame is dependent on its parent's frame.
|
832
|
+
this._callOnChildViews('_sc_clippingFrameDidChange');
|
720
833
|
},
|
721
834
|
|
722
835
|
/**
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
var frame = this.get('frame'),
|
727
|
-
ret = null;
|
728
|
-
|
729
|
-
if (frame) {
|
730
|
-
var layout = this.get('layout'),
|
731
|
-
defaultValue = layout.border == null ? 0 : layout.border,
|
732
|
-
borderTop = this._sc_explicitValueFor(layout.borderTop, defaultValue),
|
733
|
-
borderRight = this._sc_explicitValueFor(layout.borderRight, defaultValue),
|
734
|
-
borderBottom = this._sc_explicitValueFor(layout.borderBottom, defaultValue),
|
735
|
-
borderLeft = this._sc_explicitValueFor(layout.borderLeft, defaultValue);
|
736
|
-
|
737
|
-
ret = {
|
738
|
-
x: frame.x,
|
739
|
-
y: frame.y,
|
740
|
-
width: frame.width,
|
741
|
-
height: frame.height
|
742
|
-
};
|
743
|
-
|
744
|
-
var scale = frame.scale;
|
745
|
-
/*jshint eqnull:true*/
|
746
|
-
if (scale != null) {
|
747
|
-
var scaledBorderTop = borderTop * scale,
|
748
|
-
scaledBorderRight = borderRight * scale,
|
749
|
-
scaledBorderBottom = borderBottom * scale,
|
750
|
-
scaledBorderLeft = borderLeft * scale;
|
751
|
-
|
752
|
-
ret.scale = scale;
|
753
|
-
ret.x -= scaledBorderLeft;
|
754
|
-
ret.y -= scaledBorderTop;
|
755
|
-
ret.width += scaledBorderLeft + scaledBorderRight;
|
756
|
-
ret.height += scaledBorderTop + scaledBorderBottom;
|
757
|
-
} else {
|
758
|
-
ret.x -= borderLeft;
|
759
|
-
ret.y -= borderTop;
|
760
|
-
ret.width += borderLeft + borderRight;
|
761
|
-
ret.height += borderTop + borderBottom;
|
762
|
-
}
|
763
|
-
|
764
|
-
if (frame.transformOriginX != null) {
|
765
|
-
ret.transformOriginX = frame.transformOriginX;
|
766
|
-
}
|
767
|
-
|
768
|
-
if (frame.transformOriginY != null) {
|
769
|
-
ret.transformOriginY = frame.transformOriginY;
|
770
|
-
}
|
771
|
-
}
|
772
|
-
|
773
|
-
return ret;
|
774
|
-
}.property('frame').cacheable(),
|
836
|
+
This convenience method will take the current layout, apply any changes
|
837
|
+
you pass and set it again. It is more convenient than having to do this
|
838
|
+
yourself sometimes.
|
775
839
|
|
776
|
-
|
777
|
-
|
840
|
+
You can pass just a key/value pair or a hash with several pairs. You can
|
841
|
+
also pass a null value to delete a property.
|
778
842
|
|
779
|
-
|
780
|
-
|
781
|
-
this method, but you may override the viewDidResize() method.
|
843
|
+
This method will avoid actually setting the layout if the value you pass
|
844
|
+
does not edit the layout.
|
782
845
|
|
783
|
-
@param {
|
784
|
-
@
|
785
|
-
@
|
846
|
+
@param {String|Hash} key
|
847
|
+
@param {Object} value
|
848
|
+
@returns {SC.View} receiver
|
786
849
|
*/
|
787
|
-
|
788
|
-
|
789
|
-
var positionMayHaveChanged = !this.get('isFixedPosition');
|
850
|
+
adjust: function (key, value) {
|
851
|
+
if (key === undefined) { return this; } // FAST PATH! Nothing to do.
|
790
852
|
|
791
|
-
|
792
|
-
|
793
|
-
// Figure out whether our height may have changed.
|
794
|
-
parentHeight = parentFrame ? parentFrame.height : 0,
|
795
|
-
parentHeightDidChange = parentHeight !== this._scv_parentHeight,
|
796
|
-
isFixedHeight = this.get('isFixedHeight'),
|
797
|
-
heightMayHaveChanged = isStatic || (parentHeightDidChange && !isFixedHeight),
|
798
|
-
// Figure out whether our width may have changed.
|
799
|
-
parentWidth = parentFrame ? parentFrame.width : 0,
|
800
|
-
parentWidthDidChange = parentWidth !== this._scv_parentWidth,
|
801
|
-
isFixedWidth = this.get('isFixedWidth'),
|
802
|
-
widthMayHaveChanged = isStatic || (parentWidthDidChange && !isFixedWidth);
|
853
|
+
var layout = this.get('layout'),
|
854
|
+
newLayout;
|
803
855
|
|
804
|
-
//
|
805
|
-
|
806
|
-
|
856
|
+
// Normalize arguments.
|
857
|
+
if (SC.typeOf(key) === SC.T_STRING) {
|
858
|
+
newLayout = this._sc_applyAdjustment(key, value, layout);
|
859
|
+
} else {
|
860
|
+
for (var aKey in key) {
|
861
|
+
if (!key.hasOwnProperty(aKey)) { continue; }
|
807
862
|
|
808
|
-
|
809
|
-
|
810
|
-
this.viewDidResize();
|
811
|
-
}
|
812
|
-
// If our size didn't change but our position did, our frame will change, but it won't impact our child
|
813
|
-
// views' frames. (Note that the _viewFrameDidChange call is made by viewDidResize above.)
|
814
|
-
else if (positionMayHaveChanged) {
|
815
|
-
this._viewFrameDidChange();
|
863
|
+
newLayout = this._sc_applyAdjustment(aKey, key[aKey], layout, newLayout);
|
864
|
+
}
|
816
865
|
}
|
817
|
-
},
|
818
|
-
|
819
|
-
/**
|
820
|
-
This method is invoked on your view when the view resizes due to a layout
|
821
|
-
change or potentially due to the parent view resizing (if your view’s size
|
822
|
-
depends on the size of your parent view). You can override this method
|
823
|
-
to implement your own layout if you like, such as performing a grid
|
824
|
-
layout.
|
825
866
|
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
@returns {void}
|
830
|
-
*/
|
831
|
-
viewDidResize: function () {
|
832
|
-
this._viewFrameDidChange();
|
867
|
+
// now set adjusted layout
|
868
|
+
if (newLayout) {
|
869
|
+
var transitionAdjust = this.get('transitionAdjust');
|
833
870
|
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
view.tryToPerform('parentViewDidResize', frame);
|
871
|
+
if (this.get('viewState') & SC.CoreView.IS_SHOWN && transitionAdjust) {
|
872
|
+
// Run the adjust transition.
|
873
|
+
this._sc_transitionAdjust(newLayout);
|
874
|
+
} else {
|
875
|
+
this.set('layout', newLayout);
|
876
|
+
}
|
841
877
|
}
|
878
|
+
|
879
|
+
return this;
|
842
880
|
},
|
843
881
|
|
844
|
-
/**
|
845
|
-
|
882
|
+
/** */
|
883
|
+
computeParentDimensions: function (frame) {
|
884
|
+
var parentView = this.get('parentView'),
|
885
|
+
parentFrame = (parentView) ? parentView.get('frame') : null,
|
886
|
+
ret;
|
846
887
|
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
888
|
+
if (parentFrame) {
|
889
|
+
ret = {
|
890
|
+
width: parentFrame.width,
|
891
|
+
height: parentFrame.height
|
892
|
+
};
|
893
|
+
} else if (frame) {
|
894
|
+
ret = {
|
895
|
+
width: (frame.left || 0) + (frame.width || 0) + (frame.right || 0),
|
896
|
+
height: (frame.top || 0) + (frame.height || 0) + (frame.bottom || 0)
|
897
|
+
};
|
898
|
+
} else {
|
899
|
+
ret = {
|
900
|
+
width: 0,
|
901
|
+
height: 0
|
902
|
+
};
|
903
|
+
}
|
852
904
|
|
853
|
-
|
854
|
-
// clippingFrame is dependent on its parent's frame.
|
855
|
-
this._callOnChildViews('_sc_view_clippingFrameDidChange');
|
905
|
+
return ret;
|
856
906
|
},
|
857
907
|
|
858
|
-
// Implementation note: As a general rule, paired method calls, such as
|
859
|
-
// beginLiveResize/endLiveResize that are called recursively on the tree
|
860
|
-
// should reverse the order when doing the final half of the call. This
|
861
|
-
// ensures that the calls are propertly nested for any cleanup routines.
|
862
|
-
//
|
863
|
-
// -> View A.beginXXX()
|
864
|
-
// -> View B.beginXXX()
|
865
|
-
// -> View C.beginXXX()
|
866
|
-
// -> View D.beginXXX()
|
867
|
-
//
|
868
|
-
// ...later on, endXXX methods are called in reverse order of beginXXX...
|
869
|
-
//
|
870
|
-
// <- View D.endXXX()
|
871
|
-
// <- View C.endXXX()
|
872
|
-
// <- View B.endXXX()
|
873
|
-
// <- View A.endXXX()
|
874
|
-
//
|
875
|
-
// See the two methods below for an example implementation.
|
876
|
-
|
877
908
|
/**
|
878
|
-
|
879
|
-
|
880
|
-
|
909
|
+
Converts a frame from the receiver's offset to the target offset. Both
|
910
|
+
the receiver and the target must belong to the same pane. If you pass
|
911
|
+
null, the conversion will be to the pane level.
|
881
912
|
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
beginLiveResize: function () {
|
886
|
-
// call before children have been notified...
|
887
|
-
if (this.willBeginLiveResize) this.willBeginLiveResize();
|
913
|
+
Note that the context of a view's frame is the view's parent frame. In
|
914
|
+
other words, if you want to convert the frame of your view to the global
|
915
|
+
frame, then you should do:
|
888
916
|
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
}
|
895
|
-
|
917
|
+
var pv = this.get('parentView'), frame = this.get('frame');
|
918
|
+
var newFrame = pv ? pv.convertFrameToView(frame, null) : frame;
|
919
|
+
|
920
|
+
@param {Rect} frame the source frame
|
921
|
+
@param {SC.View} targetView the target view to convert to
|
922
|
+
@returns {Rect} converted frame
|
923
|
+
@test in convertFrames
|
924
|
+
*/
|
925
|
+
convertFrameToView: function (frame, targetView) {
|
926
|
+
return this._sc_convertFrameFromViewHelper(frame, this, targetView);
|
896
927
|
},
|
897
928
|
|
898
929
|
/**
|
899
|
-
|
900
|
-
|
901
|
-
that the live resize has ended.
|
930
|
+
Converts a frame offset in the coordinates of another view system to the
|
931
|
+
receiver's view.
|
902
932
|
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
endLiveResize: function () {
|
907
|
-
// notify children in *reverse* order
|
908
|
-
var ary = this.get('childViews'), len = ary.length, idx, view;
|
909
|
-
for (idx = len - 1; idx >= 0; --idx) { // loop backwards
|
910
|
-
view = ary[idx];
|
911
|
-
if (view.endLiveResize) view.endLiveResize();
|
912
|
-
}
|
933
|
+
Note that the convext of a view's frame is relative to the view's
|
934
|
+
parentFrame. For example, if you want to convert the frame of view that
|
935
|
+
belongs to another view to the receiver's frame you would do:
|
913
936
|
|
914
|
-
|
915
|
-
|
916
|
-
return this;
|
917
|
-
},
|
937
|
+
var frame = view.get('frame');
|
938
|
+
var newFrame = this.convertFrameFromView(frame, view.get('parentView'));
|
918
939
|
|
919
|
-
|
920
|
-
|
921
|
-
returns
|
940
|
+
@param {Rect} frame the source frame
|
941
|
+
@param {SC.View} targetView the target view to convert to
|
942
|
+
@returns {Rect} converted frame
|
943
|
+
@test in converFrames
|
922
944
|
*/
|
923
|
-
|
924
|
-
return this.
|
925
|
-
}
|
945
|
+
convertFrameFromView: function (frame, targetView) {
|
946
|
+
return this._sc_convertFrameFromViewHelper(frame, targetView, this);
|
947
|
+
},
|
948
|
+
|
949
|
+
/** @private */
|
950
|
+
didTransitionAdjust: function () {},
|
926
951
|
|
927
952
|
/**
|
928
953
|
This method is called whenever a property changes that invalidates the
|
@@ -949,8 +974,21 @@ SC.View.reopen(
|
|
949
974
|
}
|
950
975
|
|
951
976
|
// Optimize notifications depending on if we resized or just moved.
|
952
|
-
this.
|
977
|
+
var didResize = this._sc_checkForResize(this._sc_previousLayout, currentLayout);
|
978
|
+
|
979
|
+
// Cache the last layout to fine-tune notifications when the layout changes.
|
980
|
+
// NOTE: Do this before continuing so that any adjustments that occur in viewDidResize or from
|
981
|
+
// _sc_viewFrameDidChange (say to the position after a resize), don't result in _sc_checkForResize
|
982
|
+
// running against the old _sc_previousLayout.
|
983
|
+
this._sc_previousLayout = currentLayout;
|
953
984
|
|
985
|
+
if (didResize) {
|
986
|
+
this.viewDidResize();
|
987
|
+
} else {
|
988
|
+
// Even if we didn't resize, our frame sould have changed.
|
989
|
+
// TODO: consider checking for position changes by testing the resulting frame against the cached frame. This is difficult to do.
|
990
|
+
this._sc_viewFrameDidChange();
|
991
|
+
}
|
954
992
|
|
955
993
|
// Notify layoutView/parentView, unless we are transitioning.
|
956
994
|
var layoutView = this.get('layoutView');
|
@@ -969,54 +1007,6 @@ SC.View.reopen(
|
|
969
1007
|
return this;
|
970
1008
|
},
|
971
1009
|
|
972
|
-
/** @private */
|
973
|
-
_checkForResize: function () {
|
974
|
-
// Did our layout change in a way that could cause us to have changed size? If
|
975
|
-
// not, then there's no need to invalidate the frames of our child views.
|
976
|
-
var previousLayout = this._previousLayout,
|
977
|
-
currentLayout = this.get('layout'),
|
978
|
-
didResize = true;
|
979
|
-
|
980
|
-
// We test the new layout to see if we believe it will affect the view's frame.
|
981
|
-
// Since all the child view frames may depend on the parent's frame, it's
|
982
|
-
// best only to notify a frame change when it actually happens.
|
983
|
-
/*jshint eqnull:true*/
|
984
|
-
if (previousLayout &&
|
985
|
-
previousLayout.width != null &&
|
986
|
-
previousLayout.height != null &&
|
987
|
-
previousLayout.width === currentLayout.width &&
|
988
|
-
previousLayout.height === currentLayout.height &&
|
989
|
-
previousLayout.border === currentLayout.border &&
|
990
|
-
previousLayout.borderTop === currentLayout.borderTop &&
|
991
|
-
previousLayout.borderLeft === currentLayout.borderLeft &&
|
992
|
-
previousLayout.borderBottom === currentLayout.borderBottom &&
|
993
|
-
previousLayout.borderRight === currentLayout.borderRight) {
|
994
|
-
didResize = false;
|
995
|
-
}
|
996
|
-
|
997
|
-
// Cache the last layout to fine-tune notifications when the layout changes.
|
998
|
-
// NOTE: Do this before continuing so that any adjustments that occur in viewDidResize or from _viewFrameDidChange
|
999
|
-
// (say to the position after a resize), don't result in _checkForResize running against the old _previousLayout.
|
1000
|
-
this._previousLayout = currentLayout;
|
1001
|
-
|
1002
|
-
if (didResize) {
|
1003
|
-
this.viewDidResize();
|
1004
|
-
} else {
|
1005
|
-
// Even if we didn't resize, our frame may have changed
|
1006
|
-
// TODO: consider checking for position changes by testing the resulting frame against the cached frame. This is difficult to do.
|
1007
|
-
this._viewFrameDidChange();
|
1008
|
-
}
|
1009
|
-
},
|
1010
|
-
|
1011
|
-
/**
|
1012
|
-
This this property to YES whenever the view needs to layout its child
|
1013
|
-
views. Normally this property is set automatically whenever the layout
|
1014
|
-
property for a child view changes.
|
1015
|
-
|
1016
|
-
@type Boolean
|
1017
|
-
*/
|
1018
|
-
childViewsNeedLayout: NO,
|
1019
|
-
|
1020
1010
|
/**
|
1021
1011
|
One of two methods that are invoked whenever one of your childViews
|
1022
1012
|
layout changes. This method is invoked every time a child view's layout
|
@@ -1093,65 +1083,225 @@ SC.View.reopen(
|
|
1093
1083
|
set[i].updateLayout(force);
|
1094
1084
|
}
|
1095
1085
|
|
1096
|
-
set.clear(); // reset & reuse
|
1086
|
+
set.clear(); // reset & reuse
|
1087
|
+
}
|
1088
|
+
},
|
1089
|
+
|
1090
|
+
/**
|
1091
|
+
This method may be called on your view whenever the parent view resizes.
|
1092
|
+
|
1093
|
+
The default version of this method will reset the frame and then call
|
1094
|
+
viewDidResize() if its size may have changed. You will not usually override
|
1095
|
+
this method, but you may override the viewDidResize() method.
|
1096
|
+
|
1097
|
+
@param {Frame} parentFrame the parent view's current frame.
|
1098
|
+
@returns {void}
|
1099
|
+
@test in viewDidResize
|
1100
|
+
*/
|
1101
|
+
parentViewDidResize: function (parentFrame) {
|
1102
|
+
// Determine if our position may have changed.
|
1103
|
+
var positionMayHaveChanged = !this.get('isFixedPosition');
|
1104
|
+
|
1105
|
+
// Figure out if our size may have changed.
|
1106
|
+
var isStatic = this.get('useStaticLayout'),
|
1107
|
+
// Figure out whether our height may have changed.
|
1108
|
+
parentHeight = parentFrame ? parentFrame.height : 0,
|
1109
|
+
parentHeightDidChange = parentHeight !== this._scv_parentHeight,
|
1110
|
+
isFixedHeight = this.get('isFixedHeight'),
|
1111
|
+
heightMayHaveChanged = isStatic || (parentHeightDidChange && !isFixedHeight),
|
1112
|
+
// Figure out whether our width may have changed.
|
1113
|
+
parentWidth = parentFrame ? parentFrame.width : 0,
|
1114
|
+
parentWidthDidChange = parentWidth !== this._scv_parentWidth,
|
1115
|
+
isFixedWidth = this.get('isFixedWidth'),
|
1116
|
+
widthMayHaveChanged = isStatic || (parentWidthDidChange && !isFixedWidth);
|
1117
|
+
|
1118
|
+
// Update the cached parent frame.
|
1119
|
+
this._scv_parentHeight = parentHeight;
|
1120
|
+
this._scv_parentWidth = parentWidth;
|
1121
|
+
|
1122
|
+
// If our height or width changed, our resulting frame change may impact our child views.
|
1123
|
+
if (heightMayHaveChanged || widthMayHaveChanged) {
|
1124
|
+
this.viewDidResize();
|
1125
|
+
}
|
1126
|
+
// If our size didn't change but our position did, our frame will change, but it won't impact our child
|
1127
|
+
// views' frames. (Note that the _sc_viewFrameDidChange call is made by viewDidResize above.)
|
1128
|
+
else if (positionMayHaveChanged) {
|
1129
|
+
this._sc_viewFrameDidChange();
|
1130
|
+
}
|
1131
|
+
},
|
1132
|
+
|
1133
|
+
/**
|
1134
|
+
The 'frame' property depends on the 'layout' property as well as the
|
1135
|
+
parent view's frame. In order to properly invalidate any cached values,
|
1136
|
+
we need to invalidate the cache whenever 'layout' changes. However,
|
1137
|
+
observing 'layout' does not guarantee that; the observer might not be run
|
1138
|
+
before all other observers.
|
1139
|
+
|
1140
|
+
In order to avoid any window of opportunity where the cached frame could
|
1141
|
+
be invalid, we need to force layoutDidChange() to immediately run
|
1142
|
+
whenever 'layout' is set.
|
1143
|
+
*/
|
1144
|
+
propertyDidChange: function (key, value, _keepCache) {
|
1145
|
+
//@if(debug)
|
1146
|
+
// Debug mode only property validation.
|
1147
|
+
if (key === 'layout') {
|
1148
|
+
// If a layout value is accidentally set to NaN, this can result in infinite loops. Help the
|
1149
|
+
// developer out by failing early so that they can follow the stack trace to the problem.
|
1150
|
+
for (var property in value) {
|
1151
|
+
if (!value.hasOwnProperty(property)) { continue; }
|
1152
|
+
|
1153
|
+
var layoutValue = value[property];
|
1154
|
+
if (isNaN(layoutValue) && (layoutValue !== SC.LAYOUT_AUTO) &&
|
1155
|
+
!SC._ROTATION_VALUE_REGEX.exec(layoutValue) && !SC._SCALE_VALUE_REGEX.exec(layoutValue)) {
|
1156
|
+
throw new Error("SC.View layout property set to invalid value, %@: %@.".fmt(property, layoutValue));
|
1157
|
+
}
|
1158
|
+
}
|
1159
|
+
}
|
1160
|
+
//@endif
|
1161
|
+
|
1162
|
+
// To allow layout to be a computed property, we check if any property has
|
1163
|
+
// changed and if layout is dependent on the property.
|
1164
|
+
var layoutChange = false;
|
1165
|
+
if (typeof this.layout === "function" && this._kvo_dependents) {
|
1166
|
+
var dependents = this._kvo_dependents[key];
|
1167
|
+
if (dependents && dependents.indexOf('layout') !== -1) { layoutChange = true; }
|
1168
|
+
}
|
1169
|
+
|
1170
|
+
// If the key is 'layout', we need to call layoutDidChange() immediately
|
1171
|
+
// so that if the frame has changed any cached values (for both this view
|
1172
|
+
// and any child views) can be appropriately invalidated.
|
1173
|
+
if (key === 'layout' || layoutChange) {
|
1174
|
+
this.layoutDidChange();
|
1175
|
+
}
|
1176
|
+
|
1177
|
+
// Resume notification as usual.
|
1178
|
+
return sc_super();
|
1179
|
+
},
|
1180
|
+
|
1181
|
+
/**
|
1182
|
+
*/
|
1183
|
+
// propertyWillChange: function (key) {
|
1184
|
+
// // To allow layout to be a computed property, we check if any property has
|
1185
|
+
// // changed and if layout is dependent on the property.
|
1186
|
+
// var layoutChange = false;
|
1187
|
+
// if (typeof this.layout === "function" && this._kvo_dependents) {
|
1188
|
+
// var dependents = this._kvo_dependents[key];
|
1189
|
+
// if (dependents && dependents.indexOf('layout') !== -1) { layoutChange = true; }
|
1190
|
+
// }
|
1191
|
+
|
1192
|
+
// if (key === 'layout' || layoutChange) {
|
1193
|
+
// this._sc_previousLayout = this.get('layout');
|
1194
|
+
// }
|
1195
|
+
|
1196
|
+
// return sc_super();
|
1197
|
+
// },
|
1198
|
+
|
1199
|
+
/**
|
1200
|
+
Attempt to scroll the view to visible. This will walk up the parent
|
1201
|
+
view hierarchy looking looking for a scrollable view. It will then
|
1202
|
+
call scrollToVisible() on it.
|
1203
|
+
|
1204
|
+
Returns YES if an actual scroll took place, no otherwise.
|
1205
|
+
|
1206
|
+
@returns {Boolean}
|
1207
|
+
*/
|
1208
|
+
scrollToVisible: function () {
|
1209
|
+
var pv = this.get('parentView');
|
1210
|
+
while (pv && !pv.get('isScrollable')) { pv = pv.get('parentView'); }
|
1211
|
+
|
1212
|
+
// found view, first make it scroll itself visible then scroll this.
|
1213
|
+
if (pv) {
|
1214
|
+
pv.scrollToVisible();
|
1215
|
+
return pv.scrollToVisible(this);
|
1216
|
+
} else {
|
1217
|
+
return NO;
|
1097
1218
|
}
|
1098
1219
|
},
|
1099
1220
|
|
1100
|
-
/**
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
},
|
1221
|
+
/**
|
1222
|
+
This method is invoked on your view when the view resizes due to a layout
|
1223
|
+
change or potentially due to the parent view resizing (if your view’s size
|
1224
|
+
depends on the size of your parent view). You can override this method
|
1225
|
+
to implement your own layout if you like, such as performing a grid
|
1226
|
+
layout.
|
1107
1227
|
|
1108
|
-
|
1109
|
-
|
1110
|
-
this._cvl_teardownChildViewsLiveLayout();
|
1111
|
-
this._cvl_setupChildViewsLiveLayout();
|
1228
|
+
The default implementation simply notifies about the change to 'frame' and
|
1229
|
+
then calls parentViewDidResize on all of your children.
|
1112
1230
|
|
1113
|
-
|
1231
|
+
@returns {void}
|
1232
|
+
*/
|
1233
|
+
viewDidResize: function () {
|
1234
|
+
this._sc_viewFrameDidChange();
|
1114
1235
|
|
1115
|
-
//
|
1116
|
-
this.
|
1236
|
+
// Also notify our children.
|
1237
|
+
var cv = this.childViews,
|
1238
|
+
frame = this.get('frame'),
|
1239
|
+
len, idx, view;
|
1240
|
+
for (idx = 0; idx < (len = cv.length); ++idx) {
|
1241
|
+
view = cv[idx];
|
1242
|
+
view.tryToPerform('parentViewDidResize', frame);
|
1243
|
+
}
|
1117
1244
|
},
|
1118
1245
|
|
1119
|
-
|
1120
|
-
|
1121
|
-
|
1122
|
-
|
1123
|
-
|
1246
|
+
// Implementation note: As a general rule, paired method calls, such as
|
1247
|
+
// beginLiveResize/endLiveResize that are called recursively on the tree
|
1248
|
+
// should reverse the order when doing the final half of the call. This
|
1249
|
+
// ensures that the calls are propertly nested for any cleanup routines.
|
1250
|
+
//
|
1251
|
+
// -> View A.beginXXX()
|
1252
|
+
// -> View B.beginXXX()
|
1253
|
+
// -> View C.beginXXX()
|
1254
|
+
// -> View D.beginXXX()
|
1255
|
+
//
|
1256
|
+
// ...later on, endXXX methods are called in reverse order of beginXXX...
|
1257
|
+
//
|
1258
|
+
// <- View D.endXXX()
|
1259
|
+
// <- View C.endXXX()
|
1260
|
+
// <- View B.endXXX()
|
1261
|
+
// <- View A.endXXX()
|
1262
|
+
//
|
1263
|
+
// See the two methods below for an example implementation.
|
1124
1264
|
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1265
|
+
/**
|
1266
|
+
Call this method when you plan to begin a live resize. This will
|
1267
|
+
notify the receiver view and any of its children that are interested
|
1268
|
+
that the resize is about to begin.
|
1129
1269
|
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1270
|
+
@returns {SC.View} receiver
|
1271
|
+
@test in viewDidResize
|
1272
|
+
*/
|
1273
|
+
beginLiveResize: function () {
|
1274
|
+
// call before children have been notified...
|
1275
|
+
if (this.willBeginLiveResize) this.willBeginLiveResize();
|
1276
|
+
|
1277
|
+
// notify children in order
|
1278
|
+
var ary = this.get('childViews'), len = ary.length, idx, view;
|
1279
|
+
for (idx = 0; idx < len; ++idx) {
|
1280
|
+
view = ary[idx];
|
1281
|
+
if (view.beginLiveResize) view.beginLiveResize();
|
1136
1282
|
}
|
1283
|
+
return this;
|
1137
1284
|
},
|
1138
1285
|
|
1139
|
-
/**
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
childLayoutProperties = childViewLayout.childLayoutProperties || [];
|
1144
|
-
|
1145
|
-
for (var i = 0, len = childLayoutProperties.length; i < len; i++) {
|
1146
|
-
var observedProperty = childLayoutProperties[i];
|
1286
|
+
/**
|
1287
|
+
Call this method when you are finished with a live resize. This will
|
1288
|
+
notify the receiver view and any of its children that are interested
|
1289
|
+
that the live resize has ended.
|
1147
1290
|
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1153
|
-
|
1291
|
+
@returns {SC.View} receiver
|
1292
|
+
@test in viewDidResize
|
1293
|
+
*/
|
1294
|
+
endLiveResize: function () {
|
1295
|
+
// notify children in *reverse* order
|
1296
|
+
var ary = this.get('childViews'), len = ary.length, idx, view;
|
1297
|
+
for (idx = len - 1; idx >= 0; --idx) { // loop backwards
|
1298
|
+
view = ary[idx];
|
1299
|
+
if (view.endLiveResize) view.endLiveResize();
|
1154
1300
|
}
|
1301
|
+
|
1302
|
+
// call *after* all children have been notified...
|
1303
|
+
if (this.didEndLiveResize) this.didEndLiveResize();
|
1304
|
+
return this;
|
1155
1305
|
},
|
1156
1306
|
|
1157
1307
|
/**
|
@@ -1187,79 +1337,6 @@ SC.View.reopen(
|
|
1187
1337
|
context.setStyle(this.get('layoutStyle'));
|
1188
1338
|
},
|
1189
1339
|
|
1190
|
-
// ------------------------------------------------------------------------
|
1191
|
-
// Child View Layouts
|
1192
|
-
//
|
1193
|
-
|
1194
|
-
/**
|
1195
|
-
The child view layout plugin to use when laying out child views.
|
1196
|
-
|
1197
|
-
You can set this property to a child layout plugin object to
|
1198
|
-
automatically set and adjust the layouts of this view's child views
|
1199
|
-
according to some specific layout style. For instance, SproutCore includes
|
1200
|
-
two such plugins, SC.View.VERTICAL_STACK and SC.View.HORIZONTAL_STACK.
|
1201
|
-
|
1202
|
-
SC.View.VERTICAL_STACK will arrange child views in order in a vertical
|
1203
|
-
stack, which only requires that the height of each child view be specified.
|
1204
|
-
Likewise, SC.View.HORIZONTAL_STACK does the same in the horizontal
|
1205
|
-
direction, which requires that the width of each child view be specified.
|
1206
|
-
|
1207
|
-
Where child layout plugins are extremely useful, besides simplifying
|
1208
|
-
the amount of layout code you need to write, is that they can update the
|
1209
|
-
layouts automatically as things change. For more details and examples,
|
1210
|
-
please see the documentation for SC.View.VERTICAL_STACK and
|
1211
|
-
SC.View.HORIZONTAL_STACK.
|
1212
|
-
|
1213
|
-
To define your own child view layout plugin, simply create an object that
|
1214
|
-
conforms to the SC.ChildViewLayoutProtocol protocol.
|
1215
|
-
|
1216
|
-
**Note** This should only be set once and is not bindable.
|
1217
|
-
|
1218
|
-
@type Object
|
1219
|
-
@default null
|
1220
|
-
*/
|
1221
|
-
childViewLayout: null,
|
1222
|
-
|
1223
|
-
/**
|
1224
|
-
The options for the given child view layout plugin.
|
1225
|
-
|
1226
|
-
These options are specific to the current child layout plugin being used and
|
1227
|
-
are used to modify the applied layouts. For example, SC.View.VERTICAL_STACK
|
1228
|
-
accepts options like:
|
1229
|
-
|
1230
|
-
childViewLayoutOptions: {
|
1231
|
-
paddingAfter: 20,
|
1232
|
-
paddingBefore: 20,
|
1233
|
-
spacing: 10
|
1234
|
-
}
|
1235
|
-
|
1236
|
-
To determine what options may be used for a given plugin and to see what the
|
1237
|
-
default options are, please refer to the documentation for the child layout
|
1238
|
-
plugin being used.
|
1239
|
-
|
1240
|
-
@type Object
|
1241
|
-
@default null
|
1242
|
-
*/
|
1243
|
-
childViewLayoutOptions: null,
|
1244
|
-
|
1245
|
-
/**
|
1246
|
-
Whether the view and its child views should be monitored for changes that
|
1247
|
-
affect the current child view layout.
|
1248
|
-
|
1249
|
-
When `true` and using a childViewLayout plugin, the view and its child views
|
1250
|
-
will be observed for any changes that would affect the layout of all the
|
1251
|
-
child views. For example, if `isChildViewLayout` is true and using
|
1252
|
-
SC.View.VERTICAL_STACK, if any child view's height or visibility changes
|
1253
|
-
all of the child views will be re-adjusted.
|
1254
|
-
|
1255
|
-
If you only want to automatically layout the child views once, you can
|
1256
|
-
set this to `false` to improve performance.
|
1257
|
-
|
1258
|
-
@type Boolean
|
1259
|
-
@default true
|
1260
|
-
*/
|
1261
|
-
isChildViewLayoutLive: true,
|
1262
|
-
|
1263
1340
|
// ------------------------------------------------------------------------
|
1264
1341
|
// Statechart
|
1265
1342
|
//
|
@@ -1313,21 +1390,33 @@ SC.View.reopen(
|
|
1313
1390
|
if (this.didAppendToDocument) { this.didAppendToDocument(); }
|
1314
1391
|
},
|
1315
1392
|
|
1316
|
-
/** @private Override: The 'adopted' event (uses
|
1393
|
+
/** @private Override: The 'adopted' event (uses isFixedSize so our childViews are notified if our frame changes). */
|
1317
1394
|
_adopted: function (beforeView) {
|
1318
|
-
//
|
1319
|
-
this.
|
1395
|
+
// If our size depends on our parent, it will have changed on adoption.
|
1396
|
+
var isFixedSize = this.get('isFixedSize');
|
1397
|
+
if (isFixedSize) {
|
1398
|
+
// Even if our size is fixed, our frame may have changed (in particular if the anchor is not top/left)
|
1399
|
+
this._sc_viewFrameDidChange();
|
1400
|
+
} else {
|
1401
|
+
this.viewDidResize();
|
1402
|
+
}
|
1320
1403
|
|
1321
1404
|
sc_super();
|
1322
1405
|
},
|
1323
1406
|
|
1324
|
-
/** @private Extension: The 'orphaned' event. */
|
1407
|
+
/** @private Extension: The 'orphaned' event (uses isFixedSize so our childViews are notified if our frame changes). */
|
1325
1408
|
_orphaned: function () {
|
1326
1409
|
sc_super();
|
1327
1410
|
|
1328
1411
|
if (!this.isDestroyed) {
|
1329
|
-
//
|
1330
|
-
this.
|
1412
|
+
// If our size depends on our parent, it will have changed on orphaning.
|
1413
|
+
var isFixedSize = this.get('isFixedSize');
|
1414
|
+
if (isFixedSize) {
|
1415
|
+
// Even if our size is fixed, our frame may have changed (in particular if the anchor is not top/left)
|
1416
|
+
this._sc_viewFrameDidChange();
|
1417
|
+
} else {
|
1418
|
+
this.viewDidResize();
|
1419
|
+
}
|
1331
1420
|
}
|
1332
1421
|
},
|
1333
1422
|
|
@@ -1344,64 +1433,7 @@ SC.View.reopen(
|
|
1344
1433
|
_updatedLayout: function () {
|
1345
1434
|
// Notify.
|
1346
1435
|
this.didRenderAnimations();
|
1347
|
-
}
|
1348
|
-
|
1349
|
-
// ------------------------------------------------------------------------
|
1350
|
-
// Transitions
|
1351
|
-
//
|
1352
|
-
|
1353
|
-
/**
|
1354
|
-
The transition plugin to use when this view is moved or resized by adjusting
|
1355
|
-
its layout.
|
1356
|
-
|
1357
|
-
SC.CoreView uses a pluggable transition architecture where the transition
|
1358
|
-
setup, execution and cleanup can be handled by a plugin. This allows you
|
1359
|
-
to create complex transition animations and share them across all your views
|
1360
|
-
with only a single line of code.
|
1361
|
-
|
1362
|
-
There are a number of pre-built transition adjust plugins available in
|
1363
|
-
the SproutCore foundation framework:
|
1364
|
-
|
1365
|
-
SC.View.SMOOTH_ADJUST
|
1366
|
-
SC.View.BOUNCE_ADJUST
|
1367
|
-
SC.View.SPRING_ADJUST
|
1368
|
-
|
1369
|
-
To create a custom transition plugin simply create a regular JavaScript
|
1370
|
-
object that conforms to the SC.ViewTransitionProtocol protocol.
|
1371
|
-
|
1372
|
-
NOTE: When creating custom transition adjust plugins, be aware that SC.View
|
1373
|
-
will not call the `setup` method of the plugin, only the `run` method.
|
1374
|
-
|
1375
|
-
@type Object (SC.ViewTransitionProtocol)
|
1376
|
-
@default null
|
1377
|
-
@since Version 1.10
|
1378
|
-
*/
|
1379
|
-
transitionAdjust: null,
|
1380
|
-
|
1381
|
-
/**
|
1382
|
-
The options for the given `transitionAdjust` plugin.
|
1383
|
-
|
1384
|
-
These options are specific to the current transition plugin used and are
|
1385
|
-
used to modify the transition animation. To determine what options
|
1386
|
-
may be used for a given plugin and to see what the default options are,
|
1387
|
-
see the documentation for the transition plugin being used.
|
1388
|
-
|
1389
|
-
Most transitions will accept a duration and timing option, but may
|
1390
|
-
also use other options. For example, SC.View.BOUNCE_ADJUST accepts options
|
1391
|
-
like:
|
1392
|
-
|
1393
|
-
transitionAdjustOptions: {
|
1394
|
-
bounciness: 0.5, // how much the adjustment should bounce back each time
|
1395
|
-
bounces: 4, // the number of bounces
|
1396
|
-
duration: 0.25,
|
1397
|
-
delay: 1
|
1398
|
-
}
|
1399
|
-
|
1400
|
-
@type Object
|
1401
|
-
@default null
|
1402
|
-
@since Version 1.10
|
1403
|
-
*/
|
1404
|
-
transitionAdjustOptions: null
|
1436
|
+
}
|
1405
1437
|
|
1406
1438
|
});
|
1407
1439
|
|
@@ -1561,4 +1593,5 @@ SC.View.mixin(
|
|
1561
1593
|
convertLayoutToCustomLayout: function (layout, layoutParams, parentFrame) {
|
1562
1594
|
// TODO: [EG] Create Top/Left/Width/Height to a Custom Layout conversion
|
1563
1595
|
}
|
1596
|
+
|
1564
1597
|
});
|