Notebooks: Fix callout dialog being cut off at the bottom of the document (#14579)

* add above position for callout dialog

* use if else
This commit is contained in:
Lucy Zhang
2021-03-05 15:23:44 -08:00
committed by GitHub
parent 733c3628a1
commit f125b9b2c7
7 changed files with 31 additions and 13 deletions

View File

@@ -5,7 +5,7 @@
import 'vs/css!./media/calloutDialog'; import 'vs/css!./media/calloutDialog';
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys'; import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys';
import { IDialogProperties, Modal, DialogWidth } from 'sql/workbench/browser/modal/modal'; import { IDialogProperties, Modal, DialogWidth, DialogPosition } from 'sql/workbench/browser/modal/modal';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IThemeService } from 'vs/platform/theme/common/themeService';
@@ -20,6 +20,7 @@ export abstract class CalloutDialog<T> extends Modal {
title: string, title: string,
width: DialogWidth, width: DialogWidth,
dialogProperties: IDialogProperties, dialogProperties: IDialogProperties,
dialogPosition: DialogPosition,
@IThemeService themeService: IThemeService, @IThemeService themeService: IThemeService,
@ILayoutService layoutService: ILayoutService, @ILayoutService layoutService: ILayoutService,
@IAdsTelemetryService telemetryService: IAdsTelemetryService, @IAdsTelemetryService telemetryService: IAdsTelemetryService,
@@ -40,7 +41,7 @@ export abstract class CalloutDialog<T> extends Modal {
contextKeyService, contextKeyService,
{ {
dialogStyle: 'callout', dialogStyle: 'callout',
dialogPosition: 'below', dialogPosition: dialogPosition,
dialogProperties: dialogProperties, dialogProperties: dialogProperties,
width: width width: width
}); });

View File

@@ -48,6 +48,12 @@
top: -0.2em; top: -0.2em;
transform: rotate(135deg); transform: rotate(135deg);
} }
.callout-arrow.from-above:before {
border-width: 0.5em;
left: 2em;
bottom: -0.2em;
transform: rotate(-45deg);
}
.callout-arrow.from-left:before { .callout-arrow.from-left:before {
background-color: var(--bodybackground); background-color: var(--bodybackground);
height: 26px; height: 26px;

View File

@@ -60,7 +60,7 @@ export interface IModalDialogStyles {
export type DialogWidth = 'narrow' | 'medium' | 'wide' | number | string; export type DialogWidth = 'narrow' | 'medium' | 'wide' | number | string;
export type DialogStyle = 'normal' | 'flyout' | 'callout'; export type DialogStyle = 'normal' | 'flyout' | 'callout';
export type DialogPosition = 'left' | 'below'; export type DialogPosition = 'left' | 'below' | 'above';
export interface IDialogProperties { export interface IDialogProperties {
xPos: number, xPos: number,
@@ -438,7 +438,15 @@ export abstract class Modal extends Disposable implements IThemable {
dialogWidth = this._modalOptions.width; dialogWidth = this._modalOptions.width;
} }
if (this._modalOptions.dialogPosition === 'below') { if (this._modalOptions.dialogPosition === 'above') {
if (this._modalOptions.dialogProperties) {
this._modalDialog.style.left = `${this._modalOptions.dialogProperties.xPos - this._modalOptions.dialogProperties.width}px`;
this._modalDialog.style.top = `${this._modalOptions.dialogProperties.yPos - 235}px`;
} else {
this._modalDialog.style.left = `${this._modalOptions.positionX}px`;
this._modalDialog.style.top = `${this._modalOptions.positionY - 235}px`;
}
} else if (this._modalOptions.dialogPosition === 'below') {
if (this._modalOptions.dialogProperties) { if (this._modalOptions.dialogProperties) {
this._modalDialog.style.left = `${this._modalOptions.dialogProperties.xPos - this._modalOptions.dialogProperties.width}px`; this._modalDialog.style.left = `${this._modalOptions.dialogProperties.xPos - this._modalOptions.dialogProperties.width}px`;
this._modalDialog.style.top = `${this._modalOptions.dialogProperties.yPos + (this._modalOptions.dialogProperties.height)}px`; this._modalDialog.style.top = `${this._modalOptions.dialogProperties.yPos + (this._modalOptions.dialogProperties.height)}px`;
@@ -446,9 +454,7 @@ export abstract class Modal extends Disposable implements IThemable {
this._modalDialog.style.left = `${this._modalOptions.positionX}px`; this._modalDialog.style.left = `${this._modalOptions.positionX}px`;
this._modalDialog.style.top = `${this._modalOptions.positionY}px`; this._modalDialog.style.top = `${this._modalOptions.positionY}px`;
} }
} } else if (this._modalOptions.dialogPosition === 'left') {
if (this._modalOptions.dialogPosition === 'left') {
if (this._modalOptions.dialogProperties) { if (this._modalOptions.dialogProperties) {
this._modalDialog.style.left = `${this._modalOptions.positionX - (dialogWidth + this._modalOptions.dialogProperties.width)}px`; this._modalDialog.style.left = `${this._modalOptions.positionX - (dialogWidth + this._modalOptions.dialogProperties.width)}px`;
this._modalDialog.style.top = `${this._modalOptions.positionY - this._modalOptions.dialogProperties.height * 2}px`; this._modalDialog.style.top = `${this._modalOptions.positionY - this._modalOptions.dialogProperties.height * 2}px`;

View File

@@ -24,7 +24,7 @@ import { Deferred } from 'sql/base/common/promise';
import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox'; import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox';
import { Checkbox } from 'sql/base/browser/ui/checkbox/checkbox'; import { Checkbox } from 'sql/base/browser/ui/checkbox/checkbox';
import { RadioButton } from 'sql/base/browser/ui/radioButton/radioButton'; import { RadioButton } from 'sql/base/browser/ui/radioButton/radioButton';
import { DialogWidth } from 'sql/workbench/api/common/sqlExtHostTypes'; import { DialogPosition, DialogWidth } from 'sql/workbench/api/common/sqlExtHostTypes';
import { attachModalDialogStyler } from 'sql/workbench/common/styler'; import { attachModalDialogStyler } from 'sql/workbench/common/styler';
import { escapeUrl } from 'sql/workbench/contrib/notebook/browser/calloutDialog/common/utils'; import { escapeUrl } from 'sql/workbench/contrib/notebook/browser/calloutDialog/common/utils';
@@ -51,6 +51,7 @@ export class ImageCalloutDialog extends CalloutDialog<IImageCalloutDialogOptions
title: string, title: string,
width: DialogWidth, width: DialogWidth,
dialogProperties: IDialogProperties, dialogProperties: IDialogProperties,
dialogPosition: DialogPosition,
@IPathService private readonly _pathService: IPathService, @IPathService private readonly _pathService: IPathService,
@IFileDialogService private readonly _fileDialogService: IFileDialogService, @IFileDialogService private readonly _fileDialogService: IFileDialogService,
@IContextViewService private readonly _contextViewService: IContextViewService, @IContextViewService private readonly _contextViewService: IContextViewService,
@@ -66,6 +67,7 @@ export class ImageCalloutDialog extends CalloutDialog<IImageCalloutDialogOptions
title, title,
width, width,
dialogProperties, dialogProperties,
dialogPosition,
themeService, themeService,
layoutService, layoutService,
telemetryService, telemetryService,

View File

@@ -9,7 +9,7 @@ import * as styler from 'vs/platform/theme/common/styler';
import * as constants from 'sql/workbench/contrib/notebook/browser/calloutDialog/common/constants'; import * as constants from 'sql/workbench/contrib/notebook/browser/calloutDialog/common/constants';
import { CalloutDialog } from 'sql/workbench/browser/modal/calloutDialog'; import { CalloutDialog } from 'sql/workbench/browser/modal/calloutDialog';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { IDialogProperties } from 'sql/workbench/browser/modal/modal'; import { DialogPosition, IDialogProperties } from 'sql/workbench/browser/modal/modal';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IThemeService } from 'vs/platform/theme/common/themeService';
@@ -43,6 +43,7 @@ export class LinkCalloutDialog extends CalloutDialog<ILinkCalloutDialogOptions>
constructor( constructor(
title: string, title: string,
dialogProperties: IDialogProperties, dialogProperties: IDialogProperties,
dialogPosition: DialogPosition,
private readonly _defaultLabel: string = '', private readonly _defaultLabel: string = '',
@IContextViewService private readonly _contextViewService: IContextViewService, @IContextViewService private readonly _contextViewService: IContextViewService,
@IThemeService themeService: IThemeService, @IThemeService themeService: IThemeService,
@@ -57,6 +58,7 @@ export class LinkCalloutDialog extends CalloutDialog<ILinkCalloutDialogOptions>
title, title,
DEFAULT_DIALOG_WIDTH, DEFAULT_DIALOG_WIDTH,
dialogProperties, dialogProperties,
dialogPosition,
themeService, themeService,
layoutService, layoutService,
telemetryService, telemetryService,

View File

@@ -278,11 +278,12 @@ export class MarkdownToolbarComponent extends AngularDisposable {
const triggerHeight = triggerElement.offsetHeight; const triggerHeight = triggerElement.offsetHeight;
const triggerWidth = triggerElement.offsetWidth; const triggerWidth = triggerElement.offsetWidth;
const dialogProperties = { xPos: triggerPosX, yPos: triggerPosY, width: triggerWidth, height: triggerHeight }; const dialogProperties = { xPos: triggerPosX, yPos: triggerPosY, width: triggerWidth, height: triggerHeight };
const dialogPosition = window.innerHeight - triggerPosY < 250 ? 'above' : 'below';
let calloutOptions; let calloutOptions;
if (type === MarkdownButtonType.LINK_PREVIEW) { if (type === MarkdownButtonType.LINK_PREVIEW) {
const defaultLabel = this.getCurrentSelectionText(); const defaultLabel = this.getCurrentSelectionText();
this._linkCallout = this._instantiationService.createInstance(LinkCalloutDialog, this.insertLinkHeading, dialogProperties, defaultLabel); this._linkCallout = this._instantiationService.createInstance(LinkCalloutDialog, this.insertLinkHeading, dialogProperties, dialogPosition, defaultLabel);
this._linkCallout.render(); this._linkCallout.render();
calloutOptions = await this._linkCallout.open(); calloutOptions = await this._linkCallout.open();
} }

View File

@@ -26,7 +26,7 @@ suite('Link Callout Dialog', function (): void {
}); });
test('Should return empty markdown on cancel', async function (): Promise<void> { test('Should return empty markdown on cancel', async function (): Promise<void> {
let linkCalloutDialog = new LinkCalloutDialog('Title', undefined, 'defaultLabel', let linkCalloutDialog = new LinkCalloutDialog('Title', undefined, 'below', 'defaultLabel',
undefined, themeService, layoutService, telemetryService, contextKeyService, undefined, undefined, undefined); undefined, themeService, layoutService, telemetryService, contextKeyService, undefined, undefined, undefined);
linkCalloutDialog.render(); linkCalloutDialog.render();
@@ -47,7 +47,7 @@ suite('Link Callout Dialog', function (): void {
test('Should return expected values on insert', async function (): Promise<void> { test('Should return expected values on insert', async function (): Promise<void> {
const defaultLabel = 'defaultLabel'; const defaultLabel = 'defaultLabel';
const sampleUrl = 'https://www.aka.ms/azuredatastudio'; const sampleUrl = 'https://www.aka.ms/azuredatastudio';
let linkCalloutDialog = new LinkCalloutDialog('Title', undefined, defaultLabel, let linkCalloutDialog = new LinkCalloutDialog('Title', undefined, 'below', defaultLabel,
undefined, themeService, layoutService, telemetryService, contextKeyService, undefined, undefined, undefined); undefined, themeService, layoutService, telemetryService, contextKeyService, undefined, undefined, undefined);
linkCalloutDialog.render(); linkCalloutDialog.render();
@@ -70,7 +70,7 @@ suite('Link Callout Dialog', function (): void {
test('Should return expected values on insert when escape necessary', async function (): Promise<void> { test('Should return expected values on insert when escape necessary', async function (): Promise<void> {
const defaultLabel = 'default[]Label'; const defaultLabel = 'default[]Label';
const sampleUrl = 'https://www.aka.ms/azuredatastudio()'; const sampleUrl = 'https://www.aka.ms/azuredatastudio()';
let linkCalloutDialog = new LinkCalloutDialog('Title', undefined, defaultLabel, let linkCalloutDialog = new LinkCalloutDialog('Title', undefined, 'below', defaultLabel,
undefined, themeService, layoutService, telemetryService, contextKeyService, undefined, undefined, undefined); undefined, themeService, layoutService, telemetryService, contextKeyService, undefined, undefined, undefined);
linkCalloutDialog.render(); linkCalloutDialog.render();