Path: blob/main/src/vs/base/browser/ui/hover/hoverWidget.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import * as dom from '../../dom.js';6import { StandardKeyboardEvent } from '../../keyboardEvent.js';7import { DomScrollableElement } from '../scrollbar/scrollableElement.js';8import { KeyCode } from '../../../common/keyCodes.js';9import { Disposable } from '../../../common/lifecycle.js';10import './hoverWidget.css';11import { localize } from '../../../../nls.js';1213const $ = dom.$;1415export const enum HoverPosition {16LEFT,17RIGHT,18BELOW,19ABOVE,20}2122export class HoverWidget extends Disposable {2324public readonly containerDomNode: HTMLElement;25public readonly contentsDomNode: HTMLElement;26public readonly scrollbar: DomScrollableElement;2728constructor(fadeIn: boolean) {29super();3031this.containerDomNode = document.createElement('div');32this.containerDomNode.className = 'monaco-hover';33this.containerDomNode.classList.toggle('fade-in', !!fadeIn);34this.containerDomNode.tabIndex = 0;35this.containerDomNode.setAttribute('role', 'tooltip');3637this.contentsDomNode = document.createElement('div');38this.contentsDomNode.className = 'monaco-hover-content';3940this.scrollbar = this._register(new DomScrollableElement(this.contentsDomNode, {41consumeMouseWheelIfScrollbarIsNeeded: true42}));43this.containerDomNode.appendChild(this.scrollbar.getDomNode());44}4546public onContentsChanged(): void {47this.scrollbar.scanDomNode();48}49}5051export class HoverAction extends Disposable {52public static render(parent: HTMLElement, actionOptions: { label: string; iconClass?: string; run: (target: HTMLElement) => void; commandId: string }, keybindingLabel: string | null) {53return new HoverAction(parent, actionOptions, keybindingLabel);54}5556public readonly actionLabel: string;57public readonly actionKeybindingLabel: string | null;5859public readonly actionRenderedLabel: string;60public readonly actionContainer: HTMLElement;6162private readonly action: HTMLElement;6364private constructor(parent: HTMLElement, actionOptions: { label: string; iconClass?: string; run: (target: HTMLElement) => void; commandId: string }, keybindingLabel: string | null) {65super();6667this.actionLabel = actionOptions.label;68this.actionKeybindingLabel = keybindingLabel;6970this.actionContainer = dom.append(parent, $('div.action-container'));71this.actionContainer.setAttribute('tabindex', '0');7273this.action = dom.append(this.actionContainer, $('a.action'));74this.action.setAttribute('role', 'button');75if (actionOptions.iconClass) {76const iconElement = dom.append(this.action, $(`span.icon`));77iconElement.classList.add(...actionOptions.iconClass.split(' '));78}79this.actionRenderedLabel = keybindingLabel ? `${actionOptions.label} (${keybindingLabel})` : actionOptions.label;80const label = dom.append(this.action, $('span'));81label.textContent = this.actionRenderedLabel;8283this._store.add(new ClickAction(this.actionContainer, actionOptions.run));84this._store.add(new KeyDownAction(this.actionContainer, actionOptions.run, [KeyCode.Enter, KeyCode.Space]));85this.setEnabled(true);86}8788public setEnabled(enabled: boolean): void {89if (enabled) {90this.actionContainer.classList.remove('disabled');91this.actionContainer.removeAttribute('aria-disabled');92} else {93this.actionContainer.classList.add('disabled');94this.actionContainer.setAttribute('aria-disabled', 'true');95}96}97}9899export function getHoverAccessibleViewHint(shouldHaveHint?: boolean, keybinding?: string | null): string | undefined {100return shouldHaveHint && keybinding ? localize('acessibleViewHint', "Inspect this in the accessible view with {0}.", keybinding) : shouldHaveHint ? localize('acessibleViewHintNoKbOpen', "Inspect this in the accessible view via the command Open Accessible View which is currently not triggerable via keybinding.") : '';101}102103export class ClickAction extends Disposable {104constructor(container: HTMLElement, run: (container: HTMLElement) => void) {105super();106this._register(dom.addDisposableListener(container, dom.EventType.CLICK, e => {107e.stopPropagation();108e.preventDefault();109run(container);110}));111}112}113114export class KeyDownAction extends Disposable {115constructor(container: HTMLElement, run: (container: HTMLElement) => void, keyCodes: KeyCode[]) {116super();117this._register(dom.addDisposableListener(container, dom.EventType.KEY_DOWN, e => {118const event = new StandardKeyboardEvent(e);119if (keyCodes.some(keyCode => event.equals(keyCode))) {120e.stopPropagation();121e.preventDefault();122run(container);123}124}));125}126}127128129