Skip to content

Commit

Permalink
SelectBox: space hide WIP for microsoft#55750
Browse files Browse the repository at this point in the history
  • Loading branch information
cleidigh committed Aug 7, 2018
1 parent e30a864 commit db26c23
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 13 deletions.
8 changes: 8 additions & 0 deletions src/vs/base/browser/ui/contextview/contextview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,12 @@ export class ContextView {
}

private doLayout(): void {

// Check that we still have a delegate - this.delegate.layout may have hidden
if (!this.isVisible()) {
return;
}

// Get anchor
let anchor = this.delegate.getAnchor();

Expand Down Expand Up @@ -222,9 +228,11 @@ export class ContextView {
this.$view.addClass(anchorPosition === AnchorPosition.BELOW ? 'bottom' : 'top');
this.$view.addClass(anchorAlignment === AnchorAlignment.LEFT ? 'left' : 'right');
this.$view.style({ top: `${top}px`, left: `${left}px`, width: 'initial' });
console.debug('End ContextV doLayout');
}

public hide(data?: any): void {
console.debug('contextV hide');
if (this.delegate && this.delegate.onHide) {
this.delegate.onHide(data);
}
Expand Down
59 changes: 46 additions & 13 deletions src/vs/base/browser/ui/selectBox/selectBoxCustom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,10 @@ export class SelectBoxList implements ISelectBoxDelegate, IVirtualDelegate<ISele
}

// Set drop-down position above/below from required height and margins
this.layoutSelectDropDown(true);
// If pre-layout cannot ship at least one option do not show
if (!this.layoutSelectDropDown(true)) {
return;
}

this._isVisible = true;
this.cloneElementFont(this.selectElement, this.selectDropDownContainer);
Expand All @@ -406,7 +409,7 @@ export class SelectBoxList implements ISelectBoxDelegate, IVirtualDelegate<ISele
dom.toggleClass(this.selectDropDownContainer, 'visible', false);
dom.toggleClass(this.selectElement, 'synthetic-focus', false);
},
anchorPosition: this._dropDownPosition
anchorPosition: this._dropDownPosition,
});

// Track initial selection the case user escape, blur
Expand All @@ -423,6 +426,8 @@ export class SelectBoxList implements ISelectBoxDelegate, IVirtualDelegate<ISele
if (focusSelect) {
this.selectElement.focus();
}

console.debug('call hideContextview ');
this.contextViewProvider.hideContextView();
}

Expand All @@ -443,31 +448,57 @@ export class SelectBoxList implements ISelectBoxDelegate, IVirtualDelegate<ISele
};
}

private layoutSelectDropDown(preLayoutPosition?: boolean) {
private layoutSelectDropDown(preLayoutPosition?: boolean): boolean {

// Layout ContextView drop down select list and container
// Have to manage our vertical overflow, sizing, position below or above
// Position has to be determined and set prior to contextView instantiation

console.debug('Layout ' + preLayoutPosition);
if (this.selectList) {

const selectPosition = dom.getDomNodePagePosition(this.selectElement);
const styles = getComputedStyle(this.selectElement);
const verticalPadding = parseFloat(styles.getPropertyValue('--dropdown-padding-top')) + parseFloat(styles.getPropertyValue('--dropdown-padding-bottom'));
let maxSelectDropDownHeight = 0;
maxSelectDropDownHeight = (window.innerHeight - selectPosition.top - selectPosition.height - this.selectBoxOptions.minBottomMargin);
let maxSelectDropDownHeightBelow = 0;
maxSelectDropDownHeightBelow = (window.innerHeight - selectPosition.top - selectPosition.height - this.selectBoxOptions.minBottomMargin);
const maxSelectDropDownHeightAbove = (selectPosition.top - SelectBoxList.DEFAULT_DROPDOWN_MINIMUM_TOP_MARGIN);

this.selectList.layout();
let listHeight = this.selectList.contentHeight;
const minRequiredDropDownHeight = listHeight + verticalPadding;

if ((maxSelectDropDownHeightBelow + maxSelectDropDownHeightAbove) < this.getHeight() + verticalPadding) {
// If at least one option cannot be shown, don't open the drop-down or hide/remove if open
if (this._isVisible) {
// We must be doing a re-layout, hide if we don't fit

// Approach 1: ContextView.hide - fails when ContextView.doLayout called
this.hideSelectDropDown(true);
// Above approach will work whether minimal change in ContextView.layout
// See following code block

// Approach 2: CSS hide triggers this.selectList.onDidBlur which destroys ContextView
// as long as blur occurs after ContextView.layout, hide/remove call succeeds
// I don't think this can be guaranteed, but I have not seen it fail
// dom.toggleClass(this.selectDropDownContainer, 'visible', false);

// Approach 3: Focus back on parent select, causes immediate blur
// and hide before layout returns, always fails
// This would also be the failure mode for approach 2
// this.selectElement.focus();
}
return false;
}

// If we are only doing pre-layout check/adjust position only
// Calculate vertical space available, flip up if insufficient
// Use reflected padding on parent select, ContextView style properties not available before DOM attachment
if (preLayoutPosition) {

// Always show complete list items - never more than Max available vertical height
if (listHeight + verticalPadding > maxSelectDropDownHeight) {
const maxVisibleOptions = ((Math.floor((maxSelectDropDownHeight - verticalPadding) / this.getHeight())));
if (listHeight + verticalPadding > maxSelectDropDownHeightBelow) {
const maxVisibleOptions = ((Math.floor((maxSelectDropDownHeightBelow - verticalPadding) / this.getHeight())));

// Check if we can at least show min items otherwise flip above
if (maxVisibleOptions < SelectBoxList.DEFAULT_MINIMUM_VISIBLE_OPTIONS) {
Expand All @@ -477,7 +508,7 @@ export class SelectBoxList implements ISelectBoxDelegate, IVirtualDelegate<ISele
}
}
// Do full layout on showSelectDropDown only
return;
return true;
}

// Make visible to enable measurements
Expand All @@ -487,14 +518,14 @@ export class SelectBoxList implements ISelectBoxDelegate, IVirtualDelegate<ISele
// Use position to check above or below available space
if (this._dropDownPosition === AnchorPosition.BELOW) {
// Set container height to max from select bottom to margin (default/minBottomMargin)
if (listHeight + verticalPadding > maxSelectDropDownHeight) {
listHeight = ((Math.floor((maxSelectDropDownHeight - verticalPadding) / this.getHeight())) * this.getHeight());
if (listHeight + verticalPadding > maxSelectDropDownHeightBelow) {
listHeight = ((Math.floor((maxSelectDropDownHeightBelow - verticalPadding) / this.getHeight())) * this.getHeight());
}
} else {
// Set container height to max from select top to margin (default/minTopMargin)
maxSelectDropDownHeight = (selectPosition.top - SelectBoxList.DEFAULT_DROPDOWN_MINIMUM_TOP_MARGIN);
if (listHeight + verticalPadding > maxSelectDropDownHeight) {
listHeight = ((Math.floor((maxSelectDropDownHeight - SelectBoxList.DEFAULT_DROPDOWN_MINIMUM_TOP_MARGIN) / this.getHeight())) * this.getHeight());
maxSelectDropDownHeightBelow = (selectPosition.top - SelectBoxList.DEFAULT_DROPDOWN_MINIMUM_TOP_MARGIN);
if (listHeight + verticalPadding > maxSelectDropDownHeightBelow) {
listHeight = ((Math.floor((maxSelectDropDownHeightBelow - SelectBoxList.DEFAULT_DROPDOWN_MINIMUM_TOP_MARGIN) / this.getHeight())) * this.getHeight());
}
}

Expand Down Expand Up @@ -523,6 +554,7 @@ export class SelectBoxList implements ISelectBoxDelegate, IVirtualDelegate<ISele
dom.toggleClass(this.selectElement, 'synthetic-focus', true);
dom.toggleClass(this.selectDropDownContainer, 'synthetic-focus', true);
}
return true;
}

private setWidthControlElement(container: HTMLElement): number {
Expand Down Expand Up @@ -635,6 +667,7 @@ export class SelectBoxList implements ISelectBoxDelegate, IVirtualDelegate<ISele
// List Exit - passive - implicit no selection change, hide drop-down
private onListBlur(): void {

console.debug('OnListBlur');
if (this.selected !== this._currentSelection) {
// Reset selected to current if no change
this.select(this._currentSelection);
Expand Down

0 comments on commit db26c23

Please sign in to comment.