Markdown Horizontal Scrollbar Fix (#17083)

* dynamically change horizontal scrollbar

* working horizontal scrollbar

* created new event to handle both scrollbar and mouse wheel

* only show scrollbar when needed
This commit is contained in:
Vasu Bhog
2021-09-27 16:54:43 -07:00
committed by GitHub
parent 6b2e950f68
commit db1d3cc517
4 changed files with 67 additions and 4 deletions

View File

@@ -37,6 +37,7 @@ export class QueryTextEditor extends BaseTextEditor {
private _hideLineNumbers: boolean;
private _scrollbarHeight: number;
private _lineHeight: number;
private _shouldAddHorizontalScrollbarHeight: boolean = false;
constructor(
@ITelemetryService telemetryService: ITelemetryService,
@@ -123,6 +124,10 @@ export class QueryTextEditor extends BaseTextEditor {
return editorWidget.getScrollHeight();
}
public get shouldAddHorizontalScrollbar(): boolean {
return this._shouldAddHorizontalScrollbarHeight;
}
public setHeightToScrollHeight(configChanged?: boolean, isEditorCollapsed?: boolean,) {
let editorWidget = this.getControl() as ICodeEditor;
let layoutInfo = editorWidget.getLayoutInfo();
@@ -146,7 +151,7 @@ export class QueryTextEditor extends BaseTextEditor {
// number of lines that wrap). Finally, viewportColumn is calculated on editor resizing automatically; we can use it to ensure
// that the viewportColumn will always be greater than any character's column in an editor.
let numberWrappedLines = 0;
let shouldAddHorizontalScrollbarHeight = false;
this._shouldAddHorizontalScrollbarHeight = false;
if (!this._lineHeight || configChanged) {
this._lineHeight = editorWidget.getOption(EditorOption.lineHeight) || 18;
}
@@ -162,14 +167,14 @@ export class QueryTextEditor extends BaseTextEditor {
for (let line = 1; line <= lineCount; line++) {
// The horizontal scrollbar always appears 1 column past the viewport column when word wrap is disabled
if (editorWidgetModel.getLineMaxColumn(line) >= layoutInfo.viewportColumn + 1) {
shouldAddHorizontalScrollbarHeight = true;
this._shouldAddHorizontalScrollbarHeight = true;
break;
}
}
}
let editorHeightUsingLines = this._lineHeight * (lineCount + numberWrappedLines);
let editorHeightUsingMinHeight = Math.max(Math.min(editorHeightUsingLines, this._maxHeight), this._minHeight);
editorHeightUsingMinHeight = shouldAddHorizontalScrollbarHeight ? editorHeightUsingMinHeight + this._scrollbarHeight : editorHeightUsingMinHeight;
editorHeightUsingMinHeight = this._shouldAddHorizontalScrollbarHeight ? editorHeightUsingMinHeight + this._scrollbarHeight : editorHeightUsingMinHeight;
this.setHeight(editorHeightUsingMinHeight);
}

View File

@@ -242,6 +242,8 @@ export class CodeComponent extends CellView implements OnInit, OnChanges {
this.onContentChanged.emit();
this.checkForLanguageMagics();
// When content is updated we have to also update the horizontal scrollbar
this.horizontalScrollbar();
}));
this._register(this._configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('editor.wordWrap') || e.affectsConfiguration('editor.fontSize')) {
@@ -249,6 +251,9 @@ export class CodeComponent extends CellView implements OnInit, OnChanges {
}
}));
this._register(this.model.layoutChanged(() => this._layoutEmitter.fire(), this));
// Handles mouse wheel and scrollbar events
this._register(Event.debounce(this.model.onScroll.event, (l, e) => e, 250, /*leading=*/false)
(() => this.horizontalScrollbar()));
this._register(this.cellModel.onExecutionStateChange(event => {
if (event === CellExecutionState.Running && !this.cellModel.stdInVisible) {
this.setFocusAndScroll();
@@ -264,7 +269,6 @@ export class CodeComponent extends CellView implements OnInit, OnChanges {
}
this._layoutEmitter.fire();
}));
this.layout();
if (this._cellModel.isCollapsed) {
@@ -277,6 +281,51 @@ export class CodeComponent extends CellView implements OnInit, OnChanges {
DOM.getContentWidth(this.codeElement.nativeElement),
DOM.getContentHeight(this.codeElement.nativeElement)));
this._editor.setHeightToScrollHeight(false, this._cellModel.isCollapsed);
this.horizontalScrollbar();
}
/**
* Horizontal Scrollbar function will ensure we only calculate and trigger this if word wrap is off and it is a markdown cell
* This will adjust the horizontal scrollbar to either a fixed position at the bottom of the viewport (visible area)
* or it will set it to the bottom of the markdown editor if it is in the viewport (visible area)
*/
public horizontalScrollbar(): void {
let showScrollbar: boolean = this._editor.shouldAddHorizontalScrollbar;
let horizontalScrollbar: HTMLElement = this.codeElement.nativeElement.querySelector('div.scrollbar.horizontal');
if (this._configurationService.getValue('editor.wordWrap') === 'off' && this.cellModel.cellType !== CellTypes.Code && this.cellModel.source.length > 0 && showScrollbar) {
// Get markdown split view horizontal scrollbar
let viewport: HTMLElement = document.querySelector('.scrollable');
let markdownEditor: HTMLElement = this.codeElement.nativeElement.closest('.show-markdown .editor');
//Get values based on current context of the editor and ADS window
let markdownEditorBottom = Math.floor(markdownEditor.getBoundingClientRect().bottom);
let viewportBottom = Math.floor(viewport.getBoundingClientRect().bottom);
let viewportHeight = DOM.getTotalHeight(viewport);
let viewportTop = Math.floor(document.querySelector('.scrollable').getBoundingClientRect().top);
// Have to offset the height based on the contents viewport and the additional scrollbars that are present in markdown editor and notebook
let horizontalTop = Math.floor(Math.abs(viewportTop + viewportHeight) - Math.abs(2 * horizontalScrollbar.scrollHeight));
// Set opacity for both fixed and absolute
horizontalScrollbar.style.opacity = '1';
// If the bottom of the editor is in the viewport, then set the horizontal scrollbar to the bottom of the editor space
if (markdownEditorBottom < viewportBottom) {
horizontalScrollbar.style.position = 'absolute';
horizontalScrollbar.style.left = '0px';
horizontalScrollbar.style.top = '';
horizontalScrollbar.style.bottom = '0px';
// If the bottom of the editor is not in the viewport, then set the horizontal scrollbar to the bottom of the viewport
} else {
horizontalScrollbar.style.position = 'fixed';
horizontalScrollbar.style.left = '';
horizontalScrollbar.style.top = horizontalTop + 'px';
horizontalScrollbar.style.bottom = '';
}
} else {
// If horizontal scrollbar is not needed then set do not show it
horizontalScrollbar.style.opacity = '0';
}
}
protected initActionBar() {

View File

@@ -54,6 +54,7 @@ import { CellToolbarComponent } from 'sql/workbench/contrib/notebook/browser/cel
import { NotebookViewsExtension } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViewsExtension';
import { MaskedLabeledMenuItemActionItem } from 'sql/platform/actions/browser/menuEntryActionViewItem';
import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { Emitter } from 'vs/base/common/event';
export const NOTEBOOK_SELECTOR: string = 'notebook-component';
@@ -84,6 +85,7 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
private navigationResult: nb.NavigationResult;
public previewFeaturesEnabled: boolean = false;
public doubleClickEditEnabled: boolean;
private _onScroll = new Emitter<void>();
constructor(
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
@@ -223,6 +225,7 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
//Saves scrollTop value on scroll change
public scrollHandler(event: Event) {
this._scrollTop = (<HTMLElement>event.srcElement).scrollTop;
this.model.onScroll.fire();
}
public unselectActiveCell() {
@@ -339,6 +342,7 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
this._register(this._model.kernelChanged((kernelArgs) => this.handleKernelChanged(kernelArgs)));
this._register(this._model.onCellTypeChanged(() => this.detectChanges()));
this._register(this._model.layoutChanged(() => this.detectChanges()));
this._register(this.model.onScroll.event(() => this._onScroll.fire()));
this.setLoading(false);
// Check if URI fragment is present; if it is, navigate to section by default

View File

@@ -80,6 +80,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
private _trustedMode: boolean;
private _onActiveCellChanged = new Emitter<ICellModel | undefined>();
private _onCellTypeChanged = new Emitter<ICellModel>();
private _onScrollEmitter = new Emitter<void>();
private _cells: ICellModel[] | undefined;
private _defaultLanguageInfo: nb.ILanguageInfo | undefined;
@@ -213,6 +214,10 @@ export class NotebookModel extends Disposable implements INotebookModel {
return this._contextsChangedEmitter.event;
}
public get onScroll(): Emitter<void> {
return this._onScrollEmitter;
}
public get contextsLoading(): Event<void> {
return this._contextsLoadingEmitter.event;
}