未验证 提交 412f45fa 编写于 作者: R rebornix

re #111663.

上级 14373a5f
......@@ -50,6 +50,17 @@ export class DiffNestedCellViewModel extends Disposable implements IDiffNestedCe
this._hoveringOutput = v;
this._onDidChangeState.fire({ outputIsHoveredChanged: true });
}
private _focusOnOutput: boolean = false;
public get outputIsFocused(): boolean {
return this._focusOnOutput;
}
public set outputIsFocused(v: boolean) {
this._focusOnOutput = v;
this._onDidChangeState.fire({ outputIsFocusedChanged: true });
}
private _outputViewModels: ICellOutputViewModel[];
get outputsViewModels() {
......
......@@ -129,6 +129,7 @@ export interface IGenericCellViewModel {
uri: URI;
metadata: NotebookCellMetadata | undefined;
outputIsHovered: boolean;
outputIsFocused: boolean;
outputsViewModels: ICellOutputViewModel[];
getOutputOffset(index: number): number;
updateOutputHeight(index: number, height: number): void;
......@@ -811,6 +812,7 @@ export interface CellViewModelStateChangeEvent {
readonly foldingStateChanged?: boolean;
readonly contentChanged?: boolean;
readonly outputIsHoveredChanged?: boolean;
readonly outputIsFocusedChanged?: boolean;
readonly cellIsHoveredChanged?: boolean;
}
......
......@@ -52,6 +52,16 @@ export interface IMouseLeaveMessage extends BaseToWebviewMessage {
id: string;
}
export interface IOutputFocusMessage extends BaseToWebviewMessage {
type: 'outputFocus';
id: string;
}
export interface IOutputBlurMessage extends BaseToWebviewMessage {
type: 'outputBlur';
id: string;
}
export interface IWheelMessage extends BaseToWebviewMessage {
type: 'did-scroll-wheel';
payload: any;
......@@ -292,6 +302,8 @@ export type FromWebviewMessage =
| IDimensionMessage
| IMouseEnterMessage
| IMouseLeaveMessage
| IOutputFocusMessage
| IOutputBlurMessage
| IWheelMessage
| IScrollAckMessage
| IBlurOutputMessage
......@@ -843,6 +855,28 @@ var requirejs = (function() {
}
break;
}
case 'outputFocus':
{
const resolvedResult = this.resolveOutputId(data.id);
if (resolvedResult) {
const latestCell = this.notebookEditor.getCellByInfo(resolvedResult.cellInfo);
if (latestCell) {
latestCell.outputIsFocused = true;
}
}
break;
}
case 'outputBlur':
{
const resolvedResult = this.resolveOutputId(data.id);
if (resolvedResult) {
const latestCell = this.notebookEditor.getCellByInfo(resolvedResult.cellInfo);
if (latestCell) {
latestCell.outputIsFocused = false;
}
}
break;
}
case 'scroll-ack':
{
// const date = new Date();
......
......@@ -953,6 +953,10 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
templateData.container.classList.toggle('cell-output-hover', element.outputIsHovered);
}
private updateForFocus(element: CodeCellViewModel, templateData: CodeCellRenderTemplate): void {
templateData.container.classList.toggle('cell-output-focus', element.outputIsFocused);
}
private updateForLayout(element: CodeCellViewModel, templateData: CodeCellRenderTemplate): void {
templateData.focusIndicatorLeft.style.height = `${element.layoutInfo.indicatorHeight}px`;
templateData.focusIndicatorRight.style.height = `${element.layoutInfo.indicatorHeight}px`;
......@@ -1028,6 +1032,7 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
templateData.cellRunState.clear();
this.updateForMetadata(element, templateData, cellEditorOptions);
this.updateForHover(element, templateData);
this.updateForFocus(element, templateData);
elementDisposables.add(element.onDidChangeState((e) => {
if (e.metadataChanged) {
this.updateForMetadata(element, templateData, cellEditorOptions);
......@@ -1036,6 +1041,10 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
if (e.outputIsHoveredChanged) {
this.updateForHover(element, templateData);
}
if (e.outputIsFocusedChanged) {
this.updateForFocus(element, templateData);
}
}));
elementDisposables.add(this.notebookEditor.viewModel.notebookDocument.onDidChangeContent(e => {
if (e.rawEvents.find(event => event.kind === NotebookCellsChangeType.ChangeDocumentMetadata)) {
......
......@@ -6,7 +6,7 @@
import type { Event } from 'vs/base/common/event';
import type { IDisposable } from 'vs/base/common/lifecycle';
import { RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { FromWebviewMessage, IBlurOutputMessage, ICellDropMessage, ICellDragMessage, ICellDragStartMessage, IClickedDataUrlMessage, ICustomRendererMessage, IDimensionMessage, IClickMarkdownPreviewMessage, IMouseEnterMarkdownPreviewMessage, IMouseEnterMessage, IMouseLeaveMarkdownPreviewMessage, IMouseLeaveMessage, IToggleMarkdownPreviewMessage, IWheelMessage, ToWebviewMessage, ICellDragEndMessage } from 'vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView';
import { FromWebviewMessage, IBlurOutputMessage, ICellDropMessage, ICellDragMessage, ICellDragStartMessage, IClickedDataUrlMessage, ICustomRendererMessage, IDimensionMessage, IClickMarkdownPreviewMessage, IMouseEnterMarkdownPreviewMessage, IMouseEnterMessage, IMouseLeaveMarkdownPreviewMessage, IMouseLeaveMessage, IToggleMarkdownPreviewMessage, IWheelMessage, ToWebviewMessage, ICellDragEndMessage, IOutputFocusMessage, IOutputBlurMessage } from 'vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView';
// !! IMPORTANT !! everything must be in-line within the webviewPreloads
// function. Imports are not allowed. This is stringifies and injected into
......@@ -259,6 +259,75 @@ function webviewPreloads() {
});
}
function isAncestor(testChild: Node | null, testAncestor: Node | null): boolean {
while (testChild) {
if (testChild === testAncestor) {
return true;
}
testChild = testChild.parentNode;
}
return false;
}
class FocusTracker {
private _outputId: string;
private _hasFocus: boolean = false;
private _loosingFocus: boolean = false;
private _element: HTMLElement | Window;
constructor(element: HTMLElement | Window, outputId: string) {
this._element = element;
this._outputId = outputId;
this._hasFocus = isAncestor(document.activeElement, <HTMLElement>element);
this._loosingFocus = false;
element.addEventListener('focus', this._onFocus.bind(this), true);
element.addEventListener('blur', this._onBlur.bind(this), true);
}
private _onFocus() {
this._loosingFocus = false;
if (!this._hasFocus) {
this._hasFocus = true;
postNotebookMessage<IOutputFocusMessage>('outputFocus', {
id: this._outputId,
});
}
}
private _onBlur() {
if (this._hasFocus) {
this._loosingFocus = true;
window.setTimeout(() => {
if (this._loosingFocus) {
this._loosingFocus = false;
this._hasFocus = false;
postNotebookMessage<IOutputBlurMessage>('outputBlur', {
id: this._outputId,
});
}
}, 0);
}
}
dispose() {
if (this._element) {
this._element.removeEventListener('focus', this._onFocus, true);
this._element.removeEventListener('blur', this._onBlur, true);
}
}
}
const focusTrackers = new Map<string, FocusTracker>();
function addFocusTracker(element: HTMLElement, outputId: string): void {
if (focusTrackers.has(outputId)) {
focusTrackers.get(outputId)?.dispose();
}
focusTrackers.set(outputId, new FocusTracker(element, outputId));
}
const dontEmit = Symbol('dontEmit');
function createEmitter<T>(listenerChange: (listeners: Set<Listener<T>>) => void = () => undefined): EmitterLike<T> {
......@@ -513,6 +582,7 @@ function webviewPreloads() {
outputNode.id = outputId;
addMouseoverListeners(outputNode, outputId);
addFocusTracker(outputNode, outputId);
const content = data.content;
if (content.type === RenderOutputType.Html) {
const trustedHtml = ttPolicy?.createHTML(content.htmlContent) ?? content.htmlContent;
......@@ -617,6 +687,10 @@ function webviewPreloads() {
ob.disconnect();
});
outputObservers.clear();
focusTrackers.forEach(ft => {
ft.dispose();
});
focusTrackers.clear();
break;
case 'clearOutput':
const output = document.getElementById(event.data.outputId);
......
......@@ -50,6 +50,16 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
this._onDidChangeState.fire({ outputIsHoveredChanged: true });
}
private _focusOnOutput: boolean = false;
public get outputIsFocused(): boolean {
return this._focusOnOutput;
}
public set outputIsFocused(v: boolean) {
this._focusOnOutput = v;
this._onDidChangeState.fire({ outputIsFocusedChanged: true });
}
private _outputMinHeight: number = 0;
get outputMinHeight() {
......
......@@ -73,6 +73,15 @@ export class MarkdownCellViewModel extends BaseCellViewModel implements ICellVie
this._hoveringOutput = v;
}
private _focusOnOutput: boolean = false;
public get outputIsFocused(): boolean {
return this._focusOnOutput;
}
public set outputIsFocused(v: boolean) {
this._focusOnOutput = v;
}
private _hoveringCell = false;
public get cellIsHovered(): boolean {
return this._hoveringCell;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册