sproutcore 1.8.1 → 1.8.2.1
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.
- data/VERSION.yml +1 -1
- data/lib/frameworks/sproutcore/CHANGELOG.md +17 -2
- data/lib/frameworks/sproutcore/frameworks/bootstrap/system/loader.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/root_responder.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/root_responder/root_responder.js +23 -0
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/query/compare.js +26 -24
- data/lib/frameworks/sproutcore/frameworks/desktop/mixins/collection_fast_path.js +117 -118
- data/lib/frameworks/sproutcore/frameworks/desktop/panes/alert.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/alert/ui.js +9 -3
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/scroll/ui.js +48 -38
- data/lib/frameworks/sproutcore/frameworks/desktop/views/grid.js +42 -40
- data/lib/frameworks/sproutcore/frameworks/desktop/views/scroller.js +55 -53
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/split_view/mixins/split_child.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/split_view/tests/split_child.js +20 -1
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/split_view/views/split.js +170 -170
- data/lib/frameworks/sproutcore/frameworks/foundation/views/text_field.js +22 -6
- data/lib/frameworks/sproutcore/frameworks/runtime/core.js +1 -1
- data/lib/frameworks/sproutcore/themes/ace/resources/picker/popover/popover.css +5 -9
- metadata +2 -2
@@ -56,24 +56,24 @@ SC.ScrollerView = SC.View.extend(
|
|
56
56
|
@readOnly
|
57
57
|
*/
|
58
58
|
ariaRole: 'scrollbar',
|
59
|
-
|
60
|
-
|
59
|
+
|
60
|
+
|
61
61
|
// ..........................................................
|
62
62
|
// PROPERTIES
|
63
63
|
//
|
64
|
-
|
64
|
+
|
65
65
|
/**
|
66
66
|
If YES, a click on the track will cause the scrollbar to scroll to that position.
|
67
67
|
Otherwise, a click on the track will cause a page down.
|
68
|
-
|
68
|
+
|
69
69
|
In either case, alt-clicks will perform the opposite behavior.
|
70
|
-
|
70
|
+
|
71
71
|
@type Boolean
|
72
72
|
@default NO
|
73
73
|
*/
|
74
74
|
shouldScrollToClick: NO,
|
75
|
-
|
76
|
-
|
75
|
+
|
76
|
+
|
77
77
|
/** @private
|
78
78
|
The in-touch-scroll value.
|
79
79
|
*/
|
@@ -83,7 +83,7 @@ SC.ScrollerView = SC.View.extend(
|
|
83
83
|
The value of the scroller.
|
84
84
|
|
85
85
|
The value represents the position of the scroller's thumb.
|
86
|
-
|
86
|
+
|
87
87
|
@field
|
88
88
|
@type Number
|
89
89
|
@observes maximum
|
@@ -98,7 +98,7 @@ SC.ScrollerView = SC.View.extend(
|
|
98
98
|
val = this._scs_value || minimum; // default value is at top/left
|
99
99
|
return Math.max(Math.min(val, this.get('maximum')), minimum) ;
|
100
100
|
}.property('maximum', 'minimum').cacheable(),
|
101
|
-
|
101
|
+
|
102
102
|
/**
|
103
103
|
@type Number
|
104
104
|
@observes value
|
@@ -173,7 +173,7 @@ SC.ScrollerView = SC.View.extend(
|
|
173
173
|
appear horizontal or vertical. This must be set when the view is created.
|
174
174
|
Changing this once the view has been created will have no effect. Possible
|
175
175
|
values:
|
176
|
-
|
176
|
+
|
177
177
|
- SC.LAYOUT_VERTICAL
|
178
178
|
- SC.LAYOUT_HORIZONTAL
|
179
179
|
|
@@ -196,14 +196,14 @@ SC.ScrollerView = SC.View.extend(
|
|
196
196
|
//
|
197
197
|
|
198
198
|
/**
|
199
|
-
The width (if vertical scroller) or height (if horizontal scroller) of the
|
199
|
+
The width (if vertical scroller) or height (if horizontal scroller) of the
|
200
200
|
scrollbar.
|
201
201
|
|
202
202
|
@type Number
|
203
203
|
@default 14
|
204
204
|
*/
|
205
205
|
scrollbarThickness: 14,
|
206
|
-
|
206
|
+
|
207
207
|
/**
|
208
208
|
The width or height of the cap that encloses the track.
|
209
209
|
|
@@ -239,7 +239,7 @@ SC.ScrollerView = SC.View.extend(
|
|
239
239
|
@default 11
|
240
240
|
*/
|
241
241
|
buttonOverlap: 11,
|
242
|
-
|
242
|
+
|
243
243
|
/**
|
244
244
|
The minimium length that the thumb will be, regardless of how much content
|
245
245
|
is in the scroll view.
|
@@ -265,7 +265,8 @@ SC.ScrollerView = SC.View.extend(
|
|
265
265
|
@private
|
266
266
|
*/
|
267
267
|
render: function(context, firstTime) {
|
268
|
-
var
|
268
|
+
var ariaOrientation = 'vertical',
|
269
|
+
classNames = {},
|
269
270
|
buttons = '',
|
270
271
|
parentView = this.get('parentView'),
|
271
272
|
layoutDirection = this.get('layoutDirection'),
|
@@ -280,6 +281,7 @@ SC.ScrollerView = SC.View.extend(
|
|
280
281
|
break;
|
281
282
|
case SC.LAYOUT_HORIZONTAL:
|
282
283
|
classNames['sc-horizontal'] = YES;
|
284
|
+
ariaOrientation = 'horizontal';
|
283
285
|
break;
|
284
286
|
}
|
285
287
|
|
@@ -304,7 +306,7 @@ SC.ScrollerView = SC.View.extend(
|
|
304
306
|
this.renderThumb(context, layoutDirection, thumbLength, thumbPosition);
|
305
307
|
|
306
308
|
//addressing accessibility
|
307
|
-
context.attr('aria-orientation',
|
309
|
+
context.attr('aria-orientation', ariaOrientation);
|
308
310
|
|
309
311
|
//addressing accessibility
|
310
312
|
context.attr('aria-valuemax', this.get('maximum'));
|
@@ -353,12 +355,12 @@ SC.ScrollerView = SC.View.extend(
|
|
353
355
|
touchScrollDidStart: function(value) {
|
354
356
|
this.set("_touchScrollValue", value);
|
355
357
|
},
|
356
|
-
|
358
|
+
|
357
359
|
/** @private */
|
358
360
|
touchScrollDidEnd: function(value) {
|
359
361
|
this.set("_touchScrollValue", NO);
|
360
362
|
},
|
361
|
-
|
363
|
+
|
362
364
|
/** @private */
|
363
365
|
touchScrollDidChange: function(value) {
|
364
366
|
this.set("_touchScrollValue", value);
|
@@ -367,7 +369,7 @@ SC.ScrollerView = SC.View.extend(
|
|
367
369
|
// ..........................................................
|
368
370
|
// THUMB MANAGEMENT
|
369
371
|
//
|
370
|
-
|
372
|
+
|
371
373
|
/** @private
|
372
374
|
Adjusts the thumb (for backwards-compatibility calls adjustThumbPosition+adjustThumbSize by default)
|
373
375
|
*/
|
@@ -485,7 +487,7 @@ SC.ScrollerView = SC.View.extend(
|
|
485
487
|
thumbLength = this.get('thumbLength'),
|
486
488
|
capLength = this.get('capLength'),
|
487
489
|
capOverlap = this.get('capOverlap'), position;
|
488
|
-
|
490
|
+
|
489
491
|
position = (value/max)*(trackLength-thumbLength);
|
490
492
|
position += capLength - capOverlap; // account for the top/left cap
|
491
493
|
|
@@ -507,7 +509,7 @@ SC.ScrollerView = SC.View.extend(
|
|
507
509
|
// ..........................................................
|
508
510
|
// MOUSE EVENTS
|
509
511
|
//
|
510
|
-
|
512
|
+
|
511
513
|
/** @private
|
512
514
|
Returns the value for a position within the scroller's frame.
|
513
515
|
*/
|
@@ -516,8 +518,8 @@ SC.ScrollerView = SC.View.extend(
|
|
516
518
|
trackLength = this.get('trackLength'),
|
517
519
|
thumbLength = this.get('thumbLength'),
|
518
520
|
capLength = this.get('capLength'),
|
519
|
-
capOverlap = this.get('capOverlap'), value;
|
520
|
-
|
521
|
+
capOverlap = this.get('capOverlap'), value;
|
522
|
+
|
521
523
|
value = pos - (capLength - capOverlap);
|
522
524
|
value = value / (trackLength - thumbLength);
|
523
525
|
value = value * max;
|
@@ -546,7 +548,7 @@ SC.ScrollerView = SC.View.extend(
|
|
546
548
|
*/
|
547
549
|
mouseDown: function(evt) {
|
548
550
|
if (!this.get('isEnabled')) return NO;
|
549
|
-
|
551
|
+
|
550
552
|
// keep note of altIsDown for later.
|
551
553
|
this._altIsDown = evt.altKey;
|
552
554
|
this._shiftIsDown = evt.shiftKey;
|
@@ -591,7 +593,7 @@ SC.ScrollerView = SC.View.extend(
|
|
591
593
|
// User clicked in the track
|
592
594
|
var scrollToClick = this.get("shouldScrollToClick");
|
593
595
|
if (evt.altKey) scrollToClick = !scrollToClick;
|
594
|
-
|
596
|
+
|
595
597
|
var trackLength = this.get('trackLength'),
|
596
598
|
thumbLength = this.get('thumbLength'),
|
597
599
|
frame = this.convertFrameFromView({ x: evt.pageX, y: evt.pageY }),
|
@@ -605,13 +607,13 @@ SC.ScrollerView = SC.View.extend(
|
|
605
607
|
this._mouseDownLocation = mousePosition = frame.x;
|
606
608
|
break;
|
607
609
|
}
|
608
|
-
|
610
|
+
|
609
611
|
if (scrollToClick) {
|
610
612
|
this.set('value', this.valueForPosition(mousePosition - (thumbLength / 2)));
|
611
|
-
|
613
|
+
|
612
614
|
// and start a normal mouse down
|
613
615
|
thumbPosition = this.get('thumbPosition');
|
614
|
-
|
616
|
+
|
615
617
|
this._thumbDragging = YES;
|
616
618
|
this._thumbOffset = {x: frame.x - thumbPosition, y: frame.y - thumbPosition };
|
617
619
|
this._mouseDownLocation = {x:evt.pageX, y:evt.pageY};
|
@@ -628,7 +630,7 @@ SC.ScrollerView = SC.View.extend(
|
|
628
630
|
this.startMouseDownTimer('page');
|
629
631
|
}
|
630
632
|
}
|
631
|
-
|
633
|
+
|
632
634
|
}
|
633
635
|
|
634
636
|
return YES;
|
@@ -669,7 +671,7 @@ SC.ScrollerView = SC.View.extend(
|
|
669
671
|
If the user began the drag on the thumb, we calculate the difference
|
670
672
|
between the mouse position at click and where it is now. We then
|
671
673
|
offset the thumb by that amount, within the bounds of the track.
|
672
|
-
|
674
|
+
|
673
675
|
If the user began scrolling up/down using the buttons, this will track
|
674
676
|
what component they are currently over, changing the scroll direction.
|
675
677
|
|
@@ -686,7 +688,7 @@ SC.ScrollerView = SC.View.extend(
|
|
686
688
|
|
687
689
|
// Only move the thumb if the user clicked on the thumb during mouseDown
|
688
690
|
if (this._thumbDragging) {
|
689
|
-
|
691
|
+
|
690
692
|
switch (this.get('layoutDirection')) {
|
691
693
|
case SC.LAYOUT_VERTICAL:
|
692
694
|
delta = (evt.pageY - this._mouseDownLocation.y);
|
@@ -695,7 +697,7 @@ SC.ScrollerView = SC.View.extend(
|
|
695
697
|
delta = (evt.pageX - this._mouseDownLocation.x);
|
696
698
|
break;
|
697
699
|
}
|
698
|
-
|
700
|
+
|
699
701
|
// if we are in alt now, but were not before, update the old thumb position to the new one
|
700
702
|
if (evt.altKey) {
|
701
703
|
if (!this._altIsDown || (this._shiftIsDown !== evt.shiftKey)) {
|
@@ -704,24 +706,24 @@ SC.ScrollerView = SC.View.extend(
|
|
704
706
|
this._mouseDownLocation = { x: evt.pageX, y: evt.pageY };
|
705
707
|
this._valueAtDragStart = this.get("value");
|
706
708
|
}
|
707
|
-
|
709
|
+
|
708
710
|
// because I feel like it. Probably almost no one will find this tiny, buried feature.
|
709
711
|
// Too bad.
|
710
712
|
if (evt.shiftKey) delta = -delta;
|
711
|
-
|
713
|
+
|
712
714
|
this.set('value', Math.round(this._valueAtDragStart + delta * 2));
|
713
715
|
} else {
|
714
716
|
thumbPosition = thumbPositionAtDragStart + delta;
|
715
717
|
length = this.get('trackLength') - this.get('thumbLength');
|
716
718
|
this.set('value', Math.round( (thumbPosition/length) * this.get('maximum')));
|
717
719
|
}
|
718
|
-
|
720
|
+
|
719
721
|
} else if (isScrollingUp || isScrollingDown) {
|
720
722
|
var nowScrollingUp = NO, nowScrollingDown = NO;
|
721
|
-
|
723
|
+
|
722
724
|
var topButtonRect = this.$('.button-top')[0].getBoundingClientRect();
|
723
725
|
var bottomButtonRect = this.$('.button-bottom')[0].getBoundingClientRect();
|
724
|
-
|
726
|
+
|
725
727
|
switch (this.get('layoutDirection')) {
|
726
728
|
case SC.LAYOUT_VERTICAL:
|
727
729
|
if (evt.clientY < topButtonRect.bottom) nowScrollingUp = YES;
|
@@ -732,12 +734,12 @@ SC.ScrollerView = SC.View.extend(
|
|
732
734
|
else nowScrollingDown = YES;
|
733
735
|
break;
|
734
736
|
}
|
735
|
-
|
737
|
+
|
736
738
|
if ((nowScrollingUp || nowScrollingDown) && nowScrollingUp !== isScrollingUp){
|
737
739
|
//
|
738
740
|
// STOP OLD
|
739
741
|
//
|
740
|
-
|
742
|
+
|
741
743
|
// If we have an element that was set as active in mouseDown,
|
742
744
|
// remove its active state
|
743
745
|
if (active) {
|
@@ -746,19 +748,19 @@ SC.ScrollerView = SC.View.extend(
|
|
746
748
|
|
747
749
|
// Stop firing repeating events after mouseup
|
748
750
|
this._mouseDownTimerAction = nowScrollingUp ? "scrollUp" : "scrollDown";
|
749
|
-
|
751
|
+
|
750
752
|
if (nowScrollingUp) {
|
751
753
|
this.makeButtonActive('.button-top');
|
752
754
|
} else if (nowScrollingDown) {
|
753
755
|
this.makeButtonActive('.button-bottom');
|
754
756
|
}
|
755
|
-
|
757
|
+
|
756
758
|
this._isScrollingUp = nowScrollingUp;
|
757
759
|
this._isScrollingDown = nowScrollingDown;
|
758
760
|
}
|
759
761
|
}
|
760
|
-
|
761
|
-
|
762
|
+
|
763
|
+
|
762
764
|
this._altIsDown = evt.altKey;
|
763
765
|
this._shiftIsDown = evt.shiftKey;
|
764
766
|
return YES;
|
@@ -769,7 +771,7 @@ SC.ScrollerView = SC.View.extend(
|
|
769
771
|
clicks a button or inside the track to move a page at a time. If they
|
770
772
|
continue holding the mouse button down, we want to repeat that action
|
771
773
|
after a small delay. This timer will be invalidated in mouseUp.
|
772
|
-
|
774
|
+
|
773
775
|
Specify "immediate" as YES if it should not wait.
|
774
776
|
*/
|
775
777
|
startMouseDownTimer: function(action, immediate) {
|
@@ -849,52 +851,52 @@ SC.TouchScrollerView = SC.ScrollerView.extend(
|
|
849
851
|
@see SC.View#classNames
|
850
852
|
*/
|
851
853
|
classNames: ['sc-touch-scroller-view'],
|
852
|
-
|
854
|
+
|
853
855
|
/**
|
854
856
|
@type Number
|
855
857
|
@default 12
|
856
858
|
*/
|
857
859
|
scrollbarThickness: 12,
|
858
|
-
|
860
|
+
|
859
861
|
/**
|
860
862
|
@type Number
|
861
863
|
@default 5
|
862
864
|
*/
|
863
865
|
capLength: 5,
|
864
|
-
|
866
|
+
|
865
867
|
/**
|
866
868
|
@type Number
|
867
869
|
@default 0
|
868
870
|
*/
|
869
871
|
capOverlap: 0,
|
870
|
-
|
872
|
+
|
871
873
|
/**
|
872
874
|
@type Boolean
|
873
875
|
@default NO
|
874
876
|
*/
|
875
877
|
hasButtons: NO,
|
876
|
-
|
878
|
+
|
877
879
|
/**
|
878
880
|
@type Number
|
879
881
|
@default 36
|
880
882
|
*/
|
881
883
|
buttonOverlap: 36,
|
882
|
-
|
884
|
+
|
883
885
|
/** @private */
|
884
886
|
adjustThumb: function(thumb, position, length) {
|
885
887
|
var thumbInner = this.$('.thumb-inner');
|
886
888
|
var max = this.get("scrollerLength") - this.capLength, min = this.get("minimum") + this.capLength;
|
887
|
-
|
889
|
+
|
888
890
|
if (position + length > max) {
|
889
891
|
position = Math.min(max - 20, position);
|
890
892
|
length = max - position;
|
891
893
|
}
|
892
|
-
|
894
|
+
|
893
895
|
if (position < min) {
|
894
896
|
length -= min - position;
|
895
897
|
position = min;
|
896
898
|
}
|
897
|
-
|
899
|
+
|
898
900
|
switch (this.get('layoutDirection')) {
|
899
901
|
case SC.LAYOUT_VERTICAL:
|
900
902
|
if (this._thumbPosition !== position) thumb.css('-webkit-transform', 'translate3d(0px,' + position + 'px,0px)');
|
@@ -913,7 +915,7 @@ SC.TouchScrollerView = SC.ScrollerView.extend(
|
|
913
915
|
this._thumbPosition = position;
|
914
916
|
this._thumbSize = length;
|
915
917
|
},
|
916
|
-
|
918
|
+
|
917
919
|
/** @private */
|
918
920
|
render: function(context, firstTime) {
|
919
921
|
var classNames = [],
|
data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/split_view/mixins/split_child.js
CHANGED
@@ -214,7 +214,7 @@ SC.SplitChild =
|
|
214
214
|
* @property SC.SplitView
|
215
215
|
*/
|
216
216
|
splitView: function() {
|
217
|
-
var view = this ;
|
217
|
+
var view = this.get('parentView') ;
|
218
218
|
while (view && !view.isSplitView) view = view.get('parentView') ;
|
219
219
|
return view ;
|
220
220
|
}.property('parentView').cacheable(),
|
data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/split_view/tests/split_child.js
CHANGED
@@ -33,7 +33,14 @@ module("SplitView - SplitChild (" + (layoutDirection === SC.LAYOUT_HORIZONTAL ?
|
|
33
33
|
|
34
34
|
left: SC.View.extend(SC.SplitChild, { name: 'left', size: 100 }),
|
35
35
|
middle: SC.View.extend(SC.SplitChild, { name: 'middle', size: 300, positionOffset: -10, sizeOffset: 20 }),
|
36
|
-
right: SC.
|
36
|
+
right: SC.SplitView.extend(SC.SplitChild, {
|
37
|
+
name: 'right',
|
38
|
+
size: 100,
|
39
|
+
splitDividerView: null,
|
40
|
+
childViews: ['top', 'bottom'],
|
41
|
+
top: SC.View.extend(SC.SplitChild, { name: 'top', size: 100 }),
|
42
|
+
bottom: SC.View.extend(SC.SplitChild, { name: 'bottom', size: 400 })
|
43
|
+
}),
|
37
44
|
|
38
45
|
layout: {
|
39
46
|
left: 0, top: 0,
|
@@ -129,6 +136,18 @@ test("Check that changing orientation changes layouts.", function() {
|
|
129
136
|
verifyChildren(splitView, 100, 100, 100);
|
130
137
|
});
|
131
138
|
|
139
|
+
test("Check that the `splitView` computed is correct on SC.SplitChilds", function () {
|
140
|
+
equals(splitView, splitView.childViews[0].get('splitView'));
|
141
|
+
equals(splitView, splitView.childViews[1].get('splitView'));
|
142
|
+
equals(splitView, splitView.childViews[2].get('splitView'),
|
143
|
+
'the splitView should the closest parent splitView');
|
144
|
+
|
145
|
+
var nestedSplitView = splitView.childViews[2];
|
146
|
+
|
147
|
+
equals(nestedSplitView, nestedSplitView.childViews[0].get('splitView'));
|
148
|
+
equals(nestedSplitView, nestedSplitView.childViews[1].get('splitView'));
|
149
|
+
});
|
150
|
+
|
132
151
|
}
|
133
152
|
|
134
153
|
setupSuite(SC.LAYOUT_HORIZONTAL);
|
@@ -29,67 +29,67 @@ SC.RESIZE_AUTOMATIC = 'sc-automatic-resize';
|
|
29
29
|
|
30
30
|
/**
|
31
31
|
@class
|
32
|
-
|
32
|
+
|
33
33
|
SC.SplitView arranges multiple views side-by-side or on top of each
|
34
34
|
other.
|
35
|
-
|
36
|
-
SplitView can resize its children to fit (the default behavior),
|
35
|
+
|
36
|
+
SplitView can resize its children to fit (the default behavior),
|
37
37
|
or resize itself to fit its children--allowing you to build column-
|
38
|
-
based file browsers and the like. As one child (a divider, most likely)
|
38
|
+
based file browsers and the like. As one child (a divider, most likely)
|
39
39
|
is moved, SplitView can move additional children to get them out of the way.
|
40
|
-
|
40
|
+
|
41
41
|
Setting Up SplitViews
|
42
42
|
=======================================
|
43
43
|
You can set up a split view like any other view in SproutCore:
|
44
|
-
|
44
|
+
|
45
45
|
SplitView.design({
|
46
46
|
childViews: 'leftPanel rightPanel'.w(),
|
47
|
-
|
47
|
+
|
48
48
|
leftPanel: SC.View.design(SC.SplitChild, {
|
49
49
|
minimumSize: 200
|
50
50
|
}),
|
51
|
-
|
51
|
+
|
52
52
|
rightPanel: SC.View.design(SC.SplitChild, {
|
53
|
-
// it is usually the right panel you want to resize
|
53
|
+
// it is usually the right panel you want to resize
|
54
54
|
// as the SplitView resizes:
|
55
55
|
autoResizeStyle: SC.RESIZE_AUTOMATIC
|
56
56
|
})
|
57
57
|
})
|
58
|
-
|
58
|
+
|
59
59
|
Dividers
|
60
60
|
------------------------------------------
|
61
|
-
Dividers are automatically added between every child view.
|
62
|
-
|
61
|
+
Dividers are automatically added between every child view.
|
62
|
+
|
63
63
|
You can specify what dividers to create in two ways:
|
64
|
-
|
64
|
+
|
65
65
|
- Set splitDividerView to change the default divider view class to use.
|
66
|
-
|
66
|
+
|
67
67
|
- Override splitDividerViewBetween(splitView, view1, view2), either in
|
68
68
|
your subclass of SC.SplitView or in a delegate, and return the divider
|
69
69
|
view instance that should go between the two views.
|
70
|
-
|
70
|
+
|
71
71
|
As far as SplitView is concerned, dividers are actually just ordinary
|
72
72
|
child views. They usually have an autoResizeStyle of SC.FIXED_SIZE, and
|
73
73
|
usually mixin SC.SplitThumb to relay mouse and touch events to the SplitView.
|
74
74
|
To prevent adding dividers between dividers and views or dividers and dividers,
|
75
75
|
SC.SplitView marks all dividers with an isSplitDivider property.
|
76
|
-
|
76
|
+
|
77
77
|
If you do not want to use split dividers at all, or wish to set them up
|
78
78
|
manually in your childViews array, set splitDividerView to null.
|
79
|
-
|
79
|
+
|
80
80
|
@extends SC.View
|
81
81
|
@author Alex Iskander
|
82
82
|
*/
|
83
83
|
SC.SplitView = SC.View.extend({
|
84
84
|
/**@scope SC.SplitView.prototype*/
|
85
|
-
|
85
|
+
|
86
86
|
classNames: ['sc-split-view'],
|
87
|
-
|
87
|
+
|
88
88
|
childViews: ['topLeftView', 'bottomRightView'],
|
89
|
-
|
89
|
+
|
90
90
|
// used by the splitView computed property to find the nearest SplitView.
|
91
91
|
isSplitView: YES,
|
92
|
-
|
92
|
+
|
93
93
|
/**
|
94
94
|
* The type of view to create for the divider views. SC.SplitDividerView by default.
|
95
95
|
*
|
@@ -98,12 +98,12 @@ SC.SplitView = SC.View.extend({
|
|
98
98
|
* @type {SC.View}
|
99
99
|
*/
|
100
100
|
splitDividerView: SC.SplitDividerView,
|
101
|
-
|
101
|
+
|
102
102
|
/**
|
103
103
|
* Determines whether the SplitView should lay out its children
|
104
104
|
* horizontally or vertically.
|
105
105
|
*
|
106
|
-
* Possible values:
|
106
|
+
* Possible values:
|
107
107
|
*
|
108
108
|
* - SC.LAYOUT_HORIZONTAL: side-by-side
|
109
109
|
* - SC.LAYOUT_VERTICAL: on top of each other
|
@@ -111,10 +111,10 @@ SC.SplitView = SC.View.extend({
|
|
111
111
|
* @type LayoutDirection
|
112
112
|
*/
|
113
113
|
layoutDirection: SC.LAYOUT_HORIZONTAL,
|
114
|
-
|
114
|
+
|
115
115
|
/**
|
116
116
|
* Determines whether the SplitView should attempt to resize its
|
117
|
-
* child views to fit within the SplitView's own frame (the default).
|
117
|
+
* child views to fit within the SplitView's own frame (the default).
|
118
118
|
*
|
119
119
|
* If NO, the SplitView will decide its own size based on its children.
|
120
120
|
*
|
@@ -122,7 +122,7 @@ SC.SplitView = SC.View.extend({
|
|
122
122
|
* @default YES
|
123
123
|
*/
|
124
124
|
shouldResizeChildrenToFit: YES,
|
125
|
-
|
125
|
+
|
126
126
|
/**
|
127
127
|
* The cursor of the child view currently being dragged (if any).
|
128
128
|
* This allows the cursor to be used even if the user drags "too far",
|
@@ -131,7 +131,7 @@ SC.SplitView = SC.View.extend({
|
|
131
131
|
* @type {String}
|
132
132
|
*/
|
133
133
|
splitChildCursorStyle: null,
|
134
|
-
|
134
|
+
|
135
135
|
/**
|
136
136
|
@private
|
137
137
|
Only occurs during drag, which only happens after render, so we
|
@@ -140,8 +140,8 @@ SC.SplitView = SC.View.extend({
|
|
140
140
|
_scsv_splitChildCursorDidChange: function() {
|
141
141
|
this.get('cursor').set('cursorStyle', this.get('splitChildCursorStyle'));
|
142
142
|
}.observes('splitChildCursorStyle'),
|
143
|
-
|
144
|
-
|
143
|
+
|
144
|
+
|
145
145
|
// set up the SC.Cursor instance that this view and all the subviews
|
146
146
|
// will share.
|
147
147
|
init: function() {
|
@@ -156,7 +156,7 @@ SC.SplitView = SC.View.extend({
|
|
156
156
|
//
|
157
157
|
displayProperties: ['layoutDirection'],
|
158
158
|
renderDelegateName: 'splitRenderDelegate',
|
159
|
-
|
159
|
+
|
160
160
|
//
|
161
161
|
// UTILITIES
|
162
162
|
//
|
@@ -182,23 +182,23 @@ SC.SplitView = SC.View.extend({
|
|
182
182
|
this.scheduleTiling();
|
183
183
|
orig();
|
184
184
|
}.enhance(),
|
185
|
-
|
185
|
+
|
186
186
|
layoutDirectionDidChange: function() {
|
187
187
|
this.scheduleTiling();
|
188
188
|
}.observes('layoutDirection'),
|
189
|
-
|
190
|
-
//
|
189
|
+
|
190
|
+
//
|
191
191
|
// PUBLIC CHILD VIEW ADJUSTMENT API
|
192
192
|
//
|
193
193
|
/**
|
194
194
|
* Attempts to adjust the position of a child view, such as a divider.
|
195
|
-
*
|
195
|
+
*
|
196
196
|
* The implementation for this may be overridden in the delegate method
|
197
197
|
* splitViewAdjustPositionForChild.
|
198
198
|
*
|
199
199
|
* You may use this method to automatically collapse the view by setting
|
200
200
|
* the view's position to the position of the next or previous view (accessible
|
201
|
-
* via the child's nextView and previousView properties and the
|
201
|
+
* via the child's nextView and previousView properties and the
|
202
202
|
* getPositionForChild method).
|
203
203
|
*
|
204
204
|
* @param {SC.View} child The child to move.
|
@@ -208,14 +208,14 @@ SC.SplitView = SC.View.extend({
|
|
208
208
|
adjustPositionForChild: function(child, position){
|
209
209
|
return this.invokeDelegateMethod(this.get('delegate'), 'splitViewAdjustPositionForChild', this, child, position);
|
210
210
|
},
|
211
|
-
|
211
|
+
|
212
212
|
/**
|
213
|
-
* Returns the position within the split view for a child view,
|
213
|
+
* Returns the position within the split view for a child view,
|
214
214
|
* such as a divider. This position is not necessarily identical
|
215
215
|
* to the view's actual layout 'left' or 'right'; that position could
|
216
216
|
* be offset--for instance, to give a larger grab area to the divider.
|
217
217
|
*
|
218
|
-
* The implementation for this is in the delegate method
|
218
|
+
* The implementation for this is in the delegate method
|
219
219
|
* splitViewGetPositionForChild.
|
220
220
|
*
|
221
221
|
* @param {SC.View} child The child whose position to find.
|
@@ -224,11 +224,11 @@ SC.SplitView = SC.View.extend({
|
|
224
224
|
getPositionForChild: function(child){
|
225
225
|
return this.invokeDelegateMethod(this.get('delegate'), 'splitViewGetPositionForChild', this, child);
|
226
226
|
},
|
227
|
-
|
227
|
+
|
228
228
|
//
|
229
229
|
// CHILD VIEW MANAGEMENT
|
230
230
|
//
|
231
|
-
|
231
|
+
|
232
232
|
// When children are added and removed, we must re-run the setup process that
|
233
233
|
// sets the SplitView child properties such as nextView, previousView, etc.,
|
234
234
|
// and which adds dividers.
|
@@ -239,12 +239,12 @@ SC.SplitView = SC.View.extend({
|
|
239
239
|
// setupChildViews, because of the invokeOnce.
|
240
240
|
if (this._scsv_settingUpChildViews) return;
|
241
241
|
this._scsv_settingUpChildViews = YES;
|
242
|
-
|
242
|
+
|
243
243
|
this.invokeOnce('_scsv_setupChildViews');
|
244
|
-
|
244
|
+
|
245
245
|
this._scsv_settingUpChildViews = NO;
|
246
246
|
},
|
247
|
-
|
247
|
+
|
248
248
|
didRemoveChild: function() {
|
249
249
|
// we have to add a guard because _scsv_setupChildViews may add or remove
|
250
250
|
// dividers, causing this method to be called again uselessly.
|
@@ -252,23 +252,23 @@ SC.SplitView = SC.View.extend({
|
|
252
252
|
// setupChildViews, because of the invokeOnce.
|
253
253
|
if (this._scsv_settingUpChildViews) return;
|
254
254
|
this._scsv_settingUpChildViews = YES;
|
255
|
-
|
255
|
+
|
256
256
|
this.invokeOnce('_scsv_setupChildViews');
|
257
|
-
|
257
|
+
|
258
258
|
this._scsv_settingUpChildViews = NO;
|
259
259
|
},
|
260
|
-
|
260
|
+
|
261
261
|
createChildViews: function() {
|
262
262
|
sc_super();
|
263
263
|
|
264
264
|
if (this._scsv_settingUpChildViews) return;
|
265
265
|
this._scsv_settingUpChildViews = YES;
|
266
|
-
|
266
|
+
|
267
267
|
this.invokeOnce('_scsv_setupChildViews');
|
268
|
-
|
268
|
+
|
269
269
|
this._scsv_settingUpChildViews = NO;
|
270
270
|
},
|
271
|
-
|
271
|
+
|
272
272
|
/**
|
273
273
|
* @private
|
274
274
|
* During initialization and whenever the child views change, SplitView needs
|
@@ -276,17 +276,17 @@ SC.SplitView = SC.View.extend({
|
|
276
276
|
*
|
277
277
|
* Note: If dividers are added, childViews changes, causing this to be called again;
|
278
278
|
* this is proper, because this updates the nextView, etc. properties appropriately.
|
279
|
-
*
|
279
|
+
*
|
280
280
|
* The helper properties are: previousView, nextView, viewIndex.
|
281
281
|
*/
|
282
282
|
_scsv_setupChildViews: function() {
|
283
283
|
var del = this.get('delegate'),
|
284
|
-
|
284
|
+
|
285
285
|
children = this.get('childViews').copy(), len = children.length, idx,
|
286
286
|
child, lastChild, lastNonDividerChild,
|
287
|
-
|
287
|
+
|
288
288
|
oldDividers = this._scsv_dividers || {}, newDividers = {}, divider, dividerId;
|
289
|
-
|
289
|
+
|
290
290
|
// loop through all children, keeping track of the previous child
|
291
291
|
// as we loop using the lastChild variable.
|
292
292
|
for (idx = 0; idx < len; idx++) {
|
@@ -300,7 +300,7 @@ SC.SplitView = SC.View.extend({
|
|
300
300
|
child.set('autoResizeStyle', SC.RESIZE_AUTOMATIC);
|
301
301
|
}
|
302
302
|
}
|
303
|
-
|
303
|
+
|
304
304
|
// we initialize the size first thing in case the size is empty (fill)
|
305
305
|
// if it is empty, the way we position the views would lead to inconsistent
|
306
306
|
// sizes. In addition, we will constrain all initial sizes so they'll be valid
|
@@ -308,31 +308,31 @@ SC.SplitView = SC.View.extend({
|
|
308
308
|
var size = this.invokeDelegateMethod(del, 'splitViewGetSizeForChild', this, child);
|
309
309
|
size = this.invokeDelegateMethod(del, 'splitViewConstrainSizeForChild', this, child, size);
|
310
310
|
this.invokeDelegateMethod(del, 'splitViewSetSizeForChild', this, child, size);
|
311
|
-
|
311
|
+
|
312
312
|
child.previousView = lastChild;
|
313
313
|
child.nextView = undefined;
|
314
314
|
child.viewIndex = idx;
|
315
|
-
|
315
|
+
|
316
316
|
if (lastChild) {
|
317
317
|
lastChild.nextView = child;
|
318
318
|
}
|
319
|
-
|
319
|
+
|
320
320
|
if (lastNonDividerChild && !child.isSplitDivider) {
|
321
321
|
dividerId = SC.guidFor(lastNonDividerChild) + "-" + SC.guidFor(child);
|
322
|
-
|
322
|
+
|
323
323
|
divider = oldDividers[dividerId];
|
324
|
-
|
324
|
+
|
325
325
|
// if the previous view is a divider, but is not in our set of dividers,
|
326
326
|
// then it is manually created. If it is manually created, we should not
|
327
327
|
// create a new one.
|
328
328
|
if (!divider && !lastChild.isSplitDivider) {
|
329
329
|
divider = this.invokeDelegateMethod(del, 'splitViewDividerBetween', this, lastNonDividerChild, child);
|
330
330
|
}
|
331
|
-
|
331
|
+
|
332
332
|
if (divider) {
|
333
333
|
divider.isSplitDivider = YES;
|
334
334
|
newDividers[dividerId] = divider;
|
335
|
-
|
335
|
+
|
336
336
|
if (oldDividers[dividerId]) {
|
337
337
|
delete oldDividers[dividerId];
|
338
338
|
} else {
|
@@ -341,32 +341,32 @@ SC.SplitView = SC.View.extend({
|
|
341
341
|
}
|
342
342
|
}
|
343
343
|
|
344
|
-
|
344
|
+
|
345
345
|
lastChild = child;
|
346
346
|
if (!child.isSplitDivider) lastNonDividerChild = child;
|
347
347
|
}
|
348
|
-
|
348
|
+
|
349
349
|
// finally, remove all dividers that we didn't keep
|
350
350
|
for (dividerId in oldDividers) {
|
351
351
|
oldDividers[dividerId].destroy();
|
352
352
|
}
|
353
|
-
|
353
|
+
|
354
354
|
this._scsv_dividers = newDividers;
|
355
|
-
|
356
|
-
// retile immediately.
|
355
|
+
|
356
|
+
// retile immediately.
|
357
357
|
this._scsv_tile();
|
358
358
|
},
|
359
|
-
|
359
|
+
|
360
360
|
//
|
361
361
|
// BASIC LAYOUT CODE
|
362
362
|
//
|
363
|
-
|
363
|
+
|
364
364
|
/**
|
365
365
|
Whether the SplitView needs to be re-laid out. You can change this by
|
366
366
|
calling scheduleTiling.
|
367
367
|
*/
|
368
368
|
needsTiling: YES,
|
369
|
-
|
369
|
+
|
370
370
|
/**
|
371
371
|
Schedules a retile of the SplitView.
|
372
372
|
*/
|
@@ -374,12 +374,12 @@ SC.SplitView = SC.View.extend({
|
|
374
374
|
this.set('needsTiling', YES);
|
375
375
|
this.invokeOnce('_scsv_tile');
|
376
376
|
},
|
377
|
-
|
377
|
+
|
378
378
|
tileIfNeeded: function() {
|
379
379
|
if (!this.get('needsTiling')) return;
|
380
380
|
this._scsv_tile();
|
381
381
|
},
|
382
|
-
|
382
|
+
|
383
383
|
/**
|
384
384
|
* @private
|
385
385
|
* Tiling is the simpler of two layout paths. Tiling lays out all of the
|
@@ -392,29 +392,29 @@ SC.SplitView = SC.View.extend({
|
|
392
392
|
*/
|
393
393
|
_scsv_tile: function() {
|
394
394
|
var del = this.get('delegate');
|
395
|
-
|
395
|
+
|
396
396
|
// LOGIC:
|
397
397
|
//
|
398
|
-
// - Call splitViewLayoutChildren delegate method to position views and
|
398
|
+
// - Call splitViewLayoutChildren delegate method to position views and
|
399
399
|
// find total size.
|
400
|
-
//
|
400
|
+
//
|
401
401
|
// - If meant to automatically resize children to fit, run the
|
402
402
|
// splitViewResizeChildrenToFit delegate method.
|
403
|
-
//
|
403
|
+
//
|
404
404
|
// - Call splitViewLayoutChildren again if splitViewResizeChildrenToFit was called.
|
405
|
-
//
|
405
|
+
//
|
406
406
|
// - If not meant to automatically resize children to fit, change the SplitView
|
407
407
|
// size to match the total size of all children.
|
408
|
-
|
408
|
+
|
409
409
|
var size, frameSize = this.get('_frameSize');
|
410
|
-
|
410
|
+
|
411
411
|
size = this.invokeDelegateMethod(del, 'splitViewLayoutChildren', this);
|
412
|
-
|
412
|
+
|
413
413
|
if (this.get('shouldResizeChildrenToFit') && size !== frameSize) {
|
414
414
|
this.invokeDelegateMethod(del, 'splitViewResizeChildrenToFit', this, size);
|
415
415
|
size = this.invokeDelegateMethod(del, 'splitViewLayoutChildren', this);
|
416
416
|
}
|
417
|
-
|
417
|
+
|
418
418
|
if (!this.get('shouldResizeChildrenToFit')) {
|
419
419
|
if (this.get('layoutDirection') === SC.LAYOUT_HORIZONTAL) {
|
420
420
|
this.adjust('width', size);
|
@@ -422,10 +422,10 @@ SC.SplitView = SC.View.extend({
|
|
422
422
|
this.adjust('height', size);
|
423
423
|
}
|
424
424
|
}
|
425
|
-
|
425
|
+
|
426
426
|
this.set('needsTiling', NO);
|
427
427
|
},
|
428
|
-
|
428
|
+
|
429
429
|
/**
|
430
430
|
* Lays out the children one next to each other or one on top of the other,
|
431
431
|
* based on their sizes. It returns the total size.
|
@@ -437,20 +437,20 @@ SC.SplitView = SC.View.extend({
|
|
437
437
|
*/
|
438
438
|
splitViewLayoutChildren: function(splitView) {
|
439
439
|
var del = this.get('delegate');
|
440
|
-
|
441
|
-
var children = this.get('childViews'), len = children.length, idx,
|
440
|
+
|
441
|
+
var children = this.get('childViews'), len = children.length, idx,
|
442
442
|
child, pos = 0;
|
443
443
|
|
444
444
|
for (idx = 0; idx < len; idx++) {
|
445
445
|
child = children[idx];
|
446
|
-
|
446
|
+
|
447
447
|
this.invokeDelegateMethod(del, 'splitViewSetPositionForChild', this, children[idx], pos);
|
448
448
|
pos += this.invokeDelegateMethod(del, 'splitViewGetSizeForChild', this, children[idx]);
|
449
449
|
}
|
450
450
|
|
451
451
|
return pos;
|
452
452
|
},
|
453
|
-
|
453
|
+
|
454
454
|
/**
|
455
455
|
* Attempts to resize the child views of the split view to fit in the SplitView's
|
456
456
|
* frame. So it may proportionally adjust the child views, the current size of the
|
@@ -463,37 +463,37 @@ SC.SplitView = SC.View.extend({
|
|
463
463
|
*/
|
464
464
|
splitViewResizeChildrenToFit: function(splitView, contentSize) {
|
465
465
|
var del = this.get('delegate');
|
466
|
-
|
466
|
+
|
467
467
|
// LOGIC:
|
468
468
|
//
|
469
469
|
// - 1) Size auto-resizable children in proportion to their existing sizes to attempt
|
470
470
|
// to fit within the target size— auto-resizable views have autoResizeStyle set
|
471
471
|
// to SC.RESIZE_AUTOMATIC.
|
472
|
-
//
|
472
|
+
//
|
473
473
|
// - 2) Size non-auto-resizable children in proportion to their existing sizes—these
|
474
474
|
// views will _not_ have an autoResizeStyle of SC.RESIZE_AUTOMATIC.
|
475
475
|
//
|
476
|
-
|
476
|
+
|
477
477
|
var frameSize = this.get('_frameSize');
|
478
478
|
var children = this.get('childViews'), len = children.length, idx,
|
479
479
|
child, resizableSize = 0, nonResizableSize = 0, childSize;
|
480
|
-
|
480
|
+
|
481
481
|
// To do this sizing while keeping things proportionate, the total size of resizable
|
482
482
|
// views and the total size of non-auto-resizable views must be calculated independently.
|
483
483
|
for (idx = 0; idx < len; idx++) {
|
484
484
|
child = children[idx];
|
485
|
-
|
485
|
+
|
486
486
|
childSize = this.invokeDelegateMethod(del, 'splitViewGetSizeForChild', this, child);
|
487
|
-
|
487
|
+
|
488
488
|
if (this.invokeDelegateMethod(del, 'splitViewShouldResizeChildToFit', this, child)) {
|
489
489
|
resizableSize += childSize;
|
490
490
|
} else {
|
491
491
|
nonResizableSize += childSize;
|
492
492
|
}
|
493
493
|
}
|
494
|
-
|
494
|
+
|
495
495
|
var runningSize = contentSize;
|
496
|
-
|
496
|
+
|
497
497
|
// we run through each twice: non-aggressively, then aggressively. This is controlled by providing
|
498
498
|
// a -1 for the outOfSize. This tells the resizing to not bother with proportions and just resize
|
499
499
|
// whatever it can.
|
@@ -502,7 +502,7 @@ SC.SplitView = SC.View.extend({
|
|
502
502
|
runningSize = this._resizeChildrenForSize(runningSize, frameSize, NO, nonResizableSize);
|
503
503
|
runningSize = this._resizeChildrenForSize(runningSize, frameSize, NO, -1);
|
504
504
|
},
|
505
|
-
|
505
|
+
|
506
506
|
/**
|
507
507
|
* @private
|
508
508
|
* Utility method used by splitViewResizeChildrenToFit to do the proportionate
|
@@ -514,40 +514,40 @@ SC.SplitView = SC.View.extend({
|
|
514
514
|
var del = this.get('delegate');
|
515
515
|
|
516
516
|
var children = this.get('childViews'), idx, len = children.length, child;
|
517
|
-
|
518
|
-
var diff = targetSize - runningSize;
|
517
|
+
|
518
|
+
var diff = targetSize - runningSize;
|
519
519
|
for (idx = 0; idx < len; idx++) {
|
520
520
|
child = children[idx];
|
521
|
-
|
521
|
+
|
522
522
|
var originalChildSize = this.invokeDelegateMethod(del, 'splitViewGetSizeForChild', this, child),
|
523
523
|
size = originalChildSize;
|
524
|
-
|
524
|
+
|
525
525
|
var isResizable = this.invokeDelegateMethod(del, 'splitViewShouldResizeChildToFit', this, child);
|
526
526
|
if (isResizable === useResizable) {
|
527
527
|
// if outOfSize === -1 then we are aggressively resizing (not resizing proportionally)
|
528
528
|
if (outOfSize === -1) size += diff
|
529
529
|
else size += (size / outOfSize) * diff;
|
530
|
-
|
530
|
+
|
531
531
|
size = Math.round(size);
|
532
532
|
|
533
533
|
size = this.invokeDelegateMethod(del, 'splitViewConstrainSizeForChild', this, child, size);
|
534
|
-
this.invokeDelegateMethod(del, 'splitViewSetSizeForChild', this, child, size);
|
535
|
-
|
536
|
-
|
534
|
+
this.invokeDelegateMethod(del, 'splitViewSetSizeForChild', this, child, size);
|
535
|
+
|
536
|
+
|
537
537
|
// we remove the original child size—but we don't add it back.
|
538
538
|
// we don't add it back because the load is no longer shared.
|
539
539
|
if (outOfSize !== -1) outOfSize -= originalChildSize;
|
540
540
|
}
|
541
541
|
|
542
|
-
// We modify the old size to account for our changes so we can keep a running diff
|
542
|
+
// We modify the old size to account for our changes so we can keep a running diff
|
543
543
|
runningSize -= originalChildSize;
|
544
544
|
runningSize += size;
|
545
545
|
diff = targetSize - runningSize;
|
546
546
|
}
|
547
|
-
|
547
|
+
|
548
548
|
return runningSize;
|
549
549
|
},
|
550
|
-
|
550
|
+
|
551
551
|
/**
|
552
552
|
* Determines whether the SplitView should attempt to resize the specified
|
553
553
|
* child view when the SplitView's size changes.
|
@@ -586,20 +586,20 @@ SC.SplitView = SC.View.extend({
|
|
586
586
|
// - resize the child itself to compensate for its movement if
|
587
587
|
// child.compensatesForMovement is YES.
|
588
588
|
// - adjust position of next child.
|
589
|
-
//
|
589
|
+
//
|
590
590
|
// As the process is recursive in both directions (resizing a child may attempt
|
591
591
|
// to move it if it cannot be resized further), adjusting one child view could
|
592
592
|
// affect many _if not all_ of the SplitView's children.
|
593
|
-
//
|
594
|
-
// For safety, sanity, and stability, the recursive chain-reactions only travel
|
593
|
+
//
|
594
|
+
// For safety, sanity, and stability, the recursive chain-reactions only travel
|
595
595
|
// in one direction; for instance, resizing the previous view may attempt to adjust
|
596
596
|
// its position, but that adjustment will not propagate to views after it.
|
597
|
-
//
|
597
|
+
//
|
598
598
|
// This process, while powerful, has one complication: if you change a bunch of views
|
599
599
|
// before a view, and then _fail_ to move views after it, the views before must be
|
600
600
|
// moved back to their starting points. But if their positions were changed directly,
|
601
601
|
// this would be impossible.
|
602
|
-
//
|
602
|
+
//
|
603
603
|
// As such, the positions are not changed directly. Rather, the changes are written
|
604
604
|
// to a _plan_, and changes only committed once everything is finalized.
|
605
605
|
//
|
@@ -609,23 +609,23 @@ SC.SplitView = SC.View.extend({
|
|
609
609
|
var plan = this._scsv_createPlan();
|
610
610
|
var finalPosition = this._scsv_adjustPositionForChildInPlan(plan, child, position, child);
|
611
611
|
this._scsv_commitPlan(plan);
|
612
|
-
|
612
|
+
|
613
613
|
return finalPosition;
|
614
614
|
},
|
615
|
-
|
615
|
+
|
616
616
|
/**
|
617
617
|
* @private
|
618
618
|
* Creates a plan in which to prepare changes to the SplitView's children.
|
619
619
|
*
|
620
620
|
* A plan is an array with the same number of elements as the SplitView has children.
|
621
621
|
* Each element is a hash containing these properties:
|
622
|
-
*
|
622
|
+
*
|
623
623
|
* - child: the view the hash represents
|
624
624
|
* - originalPosition: the position before the planning process
|
625
625
|
* - position: the planned new position.
|
626
626
|
* - originalSize: the size before the planning process
|
627
627
|
* - size: the planned new size.
|
628
|
-
*
|
628
|
+
*
|
629
629
|
* The repositioning and resizing logic can, at any time, reset part of the plan
|
630
630
|
* to its original state, allowing layout processes to be run non-destructively.
|
631
631
|
* In addition, storing the original positions and sizes is more performant
|
@@ -635,14 +635,14 @@ SC.SplitView = SC.View.extend({
|
|
635
635
|
*/
|
636
636
|
_scsv_createPlan: function() {
|
637
637
|
var del = this.get('delegate'),
|
638
|
-
plan = [], children = this.get('childViews'), idx, len = children.length,
|
638
|
+
plan = [], children = this.get('childViews'), idx, len = children.length,
|
639
639
|
child, childPosition, childSize;
|
640
|
-
|
640
|
+
|
641
641
|
for (idx = 0; idx < len; idx++) {
|
642
642
|
child = children[idx];
|
643
643
|
childPosition = this.invokeDelegateMethod(del, 'splitViewGetPositionForChild', this, child);
|
644
644
|
childSize = this.invokeDelegateMethod(del, 'splitViewGetSizeForChild', this, child);
|
645
|
-
|
645
|
+
|
646
646
|
plan[idx] = {
|
647
647
|
child: child,
|
648
648
|
originalPosition: childPosition,
|
@@ -651,10 +651,10 @@ SC.SplitView = SC.View.extend({
|
|
651
651
|
size: childSize
|
652
652
|
};
|
653
653
|
}
|
654
|
-
|
654
|
+
|
655
655
|
return plan;
|
656
656
|
},
|
657
|
-
|
657
|
+
|
658
658
|
/**
|
659
659
|
* @private
|
660
660
|
* Resets a range of the plan to its original settings.
|
@@ -669,7 +669,7 @@ SC.SplitView = SC.View.extend({
|
|
669
669
|
plan[idx].size = plan[idx].originalSize;
|
670
670
|
}
|
671
671
|
},
|
672
|
-
|
672
|
+
|
673
673
|
/**
|
674
674
|
* @private
|
675
675
|
* Commits the changes specified in the plan to the child views.
|
@@ -678,21 +678,21 @@ SC.SplitView = SC.View.extend({
|
|
678
678
|
*/
|
679
679
|
_scsv_commitPlan: function(plan) {
|
680
680
|
var del = this.get('delegate'), len = plan.length, idx, item, end = 0;
|
681
|
-
|
681
|
+
|
682
682
|
for (idx = 0; idx < len; idx++) {
|
683
683
|
item = plan[idx];
|
684
684
|
if (item.size !== item.originalSize) {
|
685
685
|
this.invokeDelegateMethod(del, 'splitViewSetSizeForChild', this, item.child, item.size);
|
686
686
|
}
|
687
|
-
|
687
|
+
|
688
688
|
if (item.position !== item.originalPosition) {
|
689
689
|
this.invokeDelegateMethod(del, 'splitViewSetPositionForChild', this, item.child, item.position);
|
690
690
|
}
|
691
|
-
|
691
|
+
|
692
692
|
end = item.position + item.size;
|
693
693
|
}
|
694
|
-
|
695
|
-
|
694
|
+
|
695
|
+
|
696
696
|
if (!this.get('shouldResizeChildrenToFit')) {
|
697
697
|
if (this.get('layoutDirection') === SC.LAYOUT_HORIZONTAL) {
|
698
698
|
this.adjust('width', end);
|
@@ -701,13 +701,13 @@ SC.SplitView = SC.View.extend({
|
|
701
701
|
}
|
702
702
|
}
|
703
703
|
},
|
704
|
-
|
704
|
+
|
705
705
|
/**
|
706
706
|
* Moves the specified child view as close as it can to the specified
|
707
707
|
* position, saving all changes this causes into the plan.
|
708
708
|
*
|
709
709
|
* The "directness" of the action also comes into play. An action is direct if:
|
710
|
-
*
|
710
|
+
*
|
711
711
|
* - The child being modified is the originating child (the one being dragged, most likely)
|
712
712
|
* - The child is being _positioned_ as is immediately _after_ the originating child.
|
713
713
|
* - The child is being _sized_ and is immediately _before_ the originating child.
|
@@ -726,40 +726,40 @@ SC.SplitView = SC.View.extend({
|
|
726
726
|
*/
|
727
727
|
_scsv_adjustPositionForChildInPlan: function(plan, child, position, source) {
|
728
728
|
var del = this.get('delegate');
|
729
|
-
|
729
|
+
|
730
730
|
if (
|
731
731
|
!child.get('allowsIndirectAdjustments') &&
|
732
732
|
source !== child && source !== child.previousView
|
733
733
|
) {
|
734
734
|
return plan[child.viewIndex].position;
|
735
735
|
}
|
736
|
-
|
736
|
+
|
737
737
|
// since the process is recursive, we need to prevent the processing from
|
738
738
|
// coming back in this direction.
|
739
739
|
if (child._splitViewIsAdjusting) {
|
740
740
|
return plan[child.viewIndex].position;
|
741
741
|
}
|
742
|
-
|
742
|
+
|
743
743
|
child._splitViewIsAdjusting = YES;
|
744
|
-
|
744
|
+
|
745
745
|
//
|
746
746
|
// STEP 1: attept to resize the previous child.
|
747
|
-
//
|
747
|
+
//
|
748
748
|
var previousChild = child.previousView, nextChild = child.nextView,
|
749
|
-
previousChildPosition, previousChildSize,
|
749
|
+
previousChildPosition, previousChildSize,
|
750
750
|
nextChildPosition, nextChildSize,
|
751
751
|
size = plan[child.viewIndex].size;
|
752
|
-
|
752
|
+
|
753
753
|
if (previousChild && !previousChild._splitViewIsAdjusting) {
|
754
754
|
// we determine the size we would like it to be by subtracting its position
|
755
755
|
// from the position _we_ would like to have.
|
756
756
|
previousChildPosition = plan[previousChild.viewIndex].position;
|
757
757
|
previousChildSize = position - previousChildPosition;
|
758
|
-
|
758
|
+
|
759
759
|
previousChildSize = this._scsv_adjustSizeForChildInPlan(
|
760
760
|
plan, previousChild, previousChildSize, source
|
761
761
|
);
|
762
|
-
|
762
|
+
|
763
763
|
// the child may not have resized/moved itself all the way, so we will
|
764
764
|
// recalculate the target position based on how much it _was_ able to.
|
765
765
|
position = previousChildPosition + previousChildSize;
|
@@ -768,7 +768,7 @@ SC.SplitView = SC.View.extend({
|
|
768
768
|
// as such _must_ be at 0.
|
769
769
|
position = 0;
|
770
770
|
}
|
771
|
-
|
771
|
+
|
772
772
|
// further steps deal with children _after_ this one; these steps should
|
773
773
|
// not be performed if those children are already being taken care of.
|
774
774
|
if (nextChild && nextChild._splitViewIsAdjusting) {
|
@@ -776,11 +776,11 @@ SC.SplitView = SC.View.extend({
|
|
776
776
|
plan[child.viewIndex].position = position;
|
777
777
|
return position;
|
778
778
|
}
|
779
|
-
|
780
|
-
|
779
|
+
|
780
|
+
|
781
781
|
//
|
782
782
|
// STEP 2: attempt to resize this view to avoid moving the next one.
|
783
|
-
// Only occurs if the view's settings tell it to compensate _and_ there is a
|
783
|
+
// Only occurs if the view's settings tell it to compensate _and_ there is a
|
784
784
|
// next view to compensate for, or we are resizing to fit and there _is no_ next child.
|
785
785
|
//
|
786
786
|
if (child.get('compensatesForMovement') && nextChild) {
|
@@ -797,32 +797,32 @@ SC.SplitView = SC.View.extend({
|
|
797
797
|
nextChildPosition = position + size;
|
798
798
|
nextChildPosition = this._scsv_adjustPositionForChildInPlan(plan, nextChild, nextChildPosition, source);
|
799
799
|
}
|
800
|
-
|
800
|
+
|
801
801
|
// if we were unable to position the next child, or there is no next
|
802
802
|
// child but we need to resize children to fit, we have to undo some
|
803
803
|
// of our previous work.
|
804
804
|
if (nextChildPosition && position !== nextChildPosition - size) {
|
805
805
|
position = nextChildPosition - size;
|
806
|
-
|
806
|
+
|
807
807
|
// then, for whatever is left, we again resize the previous view, after throwing
|
808
|
-
// away the previous calculations.
|
808
|
+
// away the previous calculations.
|
809
809
|
if (previousChild && !previousChild._splitViewIsAdjusting) {
|
810
810
|
this._scsv_resetPlanRange(plan, 0, previousChild.viewIndex);
|
811
811
|
previousChildSize = position - plan[previousChild.viewIndex].position;
|
812
812
|
this._scsv_adjustSizeForChildInPlan(plan, previousChild, previousChildSize, child);
|
813
813
|
}
|
814
|
-
|
814
|
+
|
815
815
|
}
|
816
|
-
|
817
|
-
|
816
|
+
|
817
|
+
|
818
818
|
plan[child.viewIndex].position = position;
|
819
819
|
child._splitViewIsAdjusting = NO;
|
820
820
|
return position;
|
821
821
|
},
|
822
|
-
|
822
|
+
|
823
823
|
_scsv_adjustSizeForChildInPlan: function(plan, child, size, source) {
|
824
824
|
var del = this.get('delegate');
|
825
|
-
|
825
|
+
|
826
826
|
if (
|
827
827
|
source &&
|
828
828
|
!child.get('allowsIndirectAdjustments') &&
|
@@ -830,26 +830,26 @@ SC.SplitView = SC.View.extend({
|
|
830
830
|
) {
|
831
831
|
return plan[child.viewIndex].size;
|
832
832
|
}
|
833
|
-
|
833
|
+
|
834
834
|
// First, see if resizing alone will do the job.
|
835
835
|
var actualSize = this.invokeDelegateMethod(del, 'splitViewConstrainSizeForChild', this, child, size);
|
836
|
-
|
836
|
+
|
837
837
|
plan[child.viewIndex].size = actualSize;
|
838
|
-
|
838
|
+
|
839
839
|
if (size === actualSize) return size;
|
840
|
-
|
840
|
+
|
841
841
|
// if not, attempt to move the view.
|
842
842
|
var currentPosition = plan[child.viewIndex].position,
|
843
843
|
targetPosition = currentPosition + size - actualSize;
|
844
844
|
|
845
845
|
var position = this._scsv_adjustPositionForChildInPlan(plan, child, targetPosition, source);
|
846
|
-
|
846
|
+
|
847
847
|
// the result is the new right edge minus the old left edge—that is,
|
848
848
|
// the size we can pretend we are for the caller, now that we have
|
849
849
|
// resized some other views.
|
850
850
|
return position + actualSize - currentPosition;
|
851
851
|
},
|
852
|
-
|
852
|
+
|
853
853
|
/**
|
854
854
|
* Returns a view instance to be used as a divider between two other views,
|
855
855
|
* or null if no divider should be used.
|
@@ -863,15 +863,15 @@ SC.SplitView = SC.View.extend({
|
|
863
863
|
* @param {SC.SplitView} splitView The split view that is hte parent of the
|
864
864
|
* two views.
|
865
865
|
* @param {SC.View} view1 The first view.
|
866
|
-
* @param {SC.View} view2 The second view.
|
866
|
+
* @param {SC.View} view2 The second view.
|
867
867
|
* @returns {SC.View} The view instance to use as a divider.
|
868
868
|
*/
|
869
869
|
splitViewDividerBetween: function(splitView, view1, view2){
|
870
870
|
if (!this.get('splitDividerView')) return null;
|
871
|
-
|
871
|
+
|
872
872
|
return this.get('splitDividerView').create();
|
873
873
|
},
|
874
|
-
|
874
|
+
|
875
875
|
/**
|
876
876
|
* Returns the current position for the specified child.
|
877
877
|
*
|
@@ -884,7 +884,7 @@ SC.SplitView = SC.View.extend({
|
|
884
884
|
splitViewGetPositionForChild: function(splitView, child) {
|
885
885
|
return child.get('position');
|
886
886
|
},
|
887
|
-
|
887
|
+
|
888
888
|
/**
|
889
889
|
* Sets the position for the specified child.
|
890
890
|
*
|
@@ -897,7 +897,7 @@ SC.SplitView = SC.View.extend({
|
|
897
897
|
splitViewSetPositionForChild: function(splitView, child, position) {
|
898
898
|
child.set('position', position);
|
899
899
|
},
|
900
|
-
|
900
|
+
|
901
901
|
/**
|
902
902
|
* Returns the current size for the specified child.
|
903
903
|
*
|
@@ -910,10 +910,10 @@ SC.SplitView = SC.View.extend({
|
|
910
910
|
splitViewGetSizeForChild: function(splitView, child) {
|
911
911
|
var size = child.get('size');
|
912
912
|
if (SC.none(size)) return 100;
|
913
|
-
|
913
|
+
|
914
914
|
return size;
|
915
915
|
},
|
916
|
-
|
916
|
+
|
917
917
|
/**
|
918
918
|
* Sets the size for the specified child.
|
919
919
|
*
|
@@ -926,13 +926,13 @@ SC.SplitView = SC.View.extend({
|
|
926
926
|
splitViewSetSizeForChild: function(splitView, child, size) {
|
927
927
|
child.set('size', size);
|
928
928
|
},
|
929
|
-
|
929
|
+
|
930
930
|
/**
|
931
|
-
* Returns the nearest valid size to a proposed size for a child view.
|
932
|
-
* By default, constrains the size to the range specified by the child's
|
931
|
+
* Returns the nearest valid size to a proposed size for a child view.
|
932
|
+
* By default, constrains the size to the range specified by the child's
|
933
933
|
* minimumSize and maximumSize properties, and returns 0 if the child
|
934
934
|
* has canCollapse set and the size is less than the child's collapseAtSize.
|
935
|
-
*
|
935
|
+
*
|
936
936
|
* You may override this in a delegate.
|
937
937
|
*
|
938
938
|
* @param {SC.SplitView} splitView The SplitView which owns the child.
|
@@ -944,18 +944,18 @@ SC.SplitView = SC.View.extend({
|
|
944
944
|
if (child.get('autoResizeStyle') === SC.FIXED_SIZE) {
|
945
945
|
return this.invokeDelegateMethod(this.get('delegate'), 'splitViewGetSizeForChild', this, child);
|
946
946
|
}
|
947
|
-
|
947
|
+
|
948
948
|
if (child.get('canCollapse')) {
|
949
949
|
var collapseAtSize = child.get('collapseAtSize');
|
950
950
|
if (collapseAtSize && size < collapseAtSize) return 0;
|
951
951
|
}
|
952
|
-
|
952
|
+
|
953
953
|
var minSize = child.get('minimumSize') || 0;
|
954
954
|
if (minSize !== undefined && minSize !== null) size = Math.max(minSize, size);
|
955
|
-
|
955
|
+
|
956
956
|
var maxSize = child.get('maximumSize');
|
957
957
|
if (maxSize !== undefined && maxSize !== null) size = Math.min(maxSize, size);
|
958
|
-
|
958
|
+
|
959
959
|
return size;
|
960
960
|
}
|
961
961
|
});
|