提交 6f612660 编写于 作者: P Peng Lyu

trigger webview and list view scroll at the same time.

上级 0c0e3692
...@@ -196,6 +196,9 @@ export class ListView<T> implements ISpliceable<T>, IDisposable { ...@@ -196,6 +196,9 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
get onDidScroll(): Event<ScrollEvent> { return this.scrollableElement.onScroll; } get onDidScroll(): Event<ScrollEvent> { return this.scrollableElement.onScroll; }
private readonly _willScroll = new Emitter<ScrollEvent>();
get onWillScroll(): Event<ScrollEvent> { return this._willScroll.event; }
constructor( constructor(
container: HTMLElement, container: HTMLElement,
private virtualDelegate: IListVirtualDelegate<T>, private virtualDelegate: IListVirtualDelegate<T>,
...@@ -556,6 +559,9 @@ export class ListView<T> implements ISpliceable<T>, IDisposable { ...@@ -556,6 +559,9 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
} }
this.rowsContainer.style.left = `-${renderLeft}px`; this.rowsContainer.style.left = `-${renderLeft}px`;
console.log('------');
const date = new Date();
console.log('list view render top change, old ', this.rowsContainer.style.top, ' new ', `-${renderTop}` + ' - ' + date.getMinutes() + ':' + date.getSeconds() + ':' + date.getMilliseconds());
this.rowsContainer.style.top = `-${renderTop}px`; this.rowsContainer.style.top = `-${renderTop}px`;
if (this.horizontalScrolling) { if (this.horizontalScrolling) {
...@@ -757,6 +763,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable { ...@@ -757,6 +763,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
private onScroll(e: ScrollEvent): void { private onScroll(e: ScrollEvent): void {
try { try {
this._willScroll.fire(e);
this.render(e.scrollTop, e.height, e.scrollLeft, e.scrollWidth); this.render(e.scrollTop, e.height, e.scrollLeft, e.scrollWidth);
if (this.supportDynamicHeights) { if (this.supportDynamicHeights) {
......
...@@ -1139,6 +1139,7 @@ export class List<T> implements ISpliceable<T>, IDisposable { ...@@ -1139,6 +1139,7 @@ export class List<T> implements ISpliceable<T>, IDisposable {
get domId(): string { return this.view.domId; } get domId(): string { return this.view.domId; }
get onDidScroll(): Event<ScrollEvent> { return this.view.onDidScroll; } get onDidScroll(): Event<ScrollEvent> { return this.view.onDidScroll; }
get onWillScroll(): Event<ScrollEvent> { return this.view.onWillScroll; }
get onMouseClick(): Event<IListMouseEvent<T>> { return this.view.onMouseClick; } get onMouseClick(): Event<IListMouseEvent<T>> { return this.view.onMouseClick; }
get onMouseDblClick(): Event<IListMouseEvent<T>> { return this.view.onMouseDblClick; } get onMouseDblClick(): Event<IListMouseEvent<T>> { return this.view.onMouseDblClick; }
get onMouseMiddleClick(): Event<IListMouseEvent<T>> { return this.view.onMouseMiddleClick; } get onMouseMiddleClick(): Event<IListMouseEvent<T>> { return this.view.onMouseMiddleClick; }
......
...@@ -582,30 +582,31 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende ...@@ -582,30 +582,31 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
} }
} }
// if (height !== undefined && hasDynamicHeight) { if (height !== undefined && hasDynamicHeight) {
// let dimensions = DOM.getClientArea(templateData.outputContainer!); let dimensions = DOM.getClientArea(templateData.outputContainer!);
// const elementSizeObserver = new ElementSizeObserver(templateData.outputContainer!, dimensions, () => { const elementSizeObserver = new ElementSizeObserver(templateData.outputContainer!, dimensions, () => {
// if (templateData.outputContainer && document.body.contains(templateData.outputContainer!)) { if (templateData.outputContainer && document.body.contains(templateData.outputContainer!)) {
// let height = elementSizeObserver.getHeight(); let height = elementSizeObserver.getHeight();
// if (dimensions.height !== height) { if (dimensions.height !== height) {
// element.setDynamicHeight(totalHeight + 32 + height); element.setDynamicHeight(totalHeight + 32 + height);
// this.handler.layoutElement(element, totalHeight + 32 + height); this.handler.layoutElement(element, totalHeight + 32 + height);
// } }
// }
// }); elementSizeObserver.dispose();
// elementSizeObserver.startObserving(); }
// if (!hasDynamicHeight && dimensions.height !== 0) { });
// element.setDynamicHeight(totalHeight + 32 + dimensions.height); elementSizeObserver.startObserving();
// this.handler.layoutElement(element, totalHeight + 32 + dimensions.height); if (!hasDynamicHeight && dimensions.height !== 0) {
// } element.setDynamicHeight(totalHeight + 32 + dimensions.height);
this.handler.layoutElement(element, totalHeight + 32 + dimensions.height);
// this.disposables.set(templateData.outputContainer!, { }
// dispose: () => {
// elementSizeObserver.stopObserving(); this.disposables.set(templateData.cellContainer, {
// elementSizeObserver.dispose(); dispose: () => {
// } elementSizeObserver.dispose();
// }); }
// } });
}
} }
} }
......
...@@ -7,6 +7,7 @@ import { NotebookHandler, ViewCell } from 'vs/workbench/contrib/notebook/browser ...@@ -7,6 +7,7 @@ import { NotebookHandler, ViewCell } from 'vs/workbench/contrib/notebook/browser
import { IWebviewService, WebviewElement } from 'vs/workbench/contrib/webview/browser/webview'; import { IWebviewService, WebviewElement } from 'vs/workbench/contrib/webview/browser/webview';
import * as DOM from 'vs/base/browser/dom'; import * as DOM from 'vs/base/browser/dom';
import * as UUID from 'vs/base/common/uuid'; import * as UUID from 'vs/base/common/uuid';
import { Disposable } from 'vs/base/common/lifecycle';
export interface IDimentionMessage { export interface IDimentionMessage {
...@@ -15,6 +16,13 @@ export interface IDimentionMessage { ...@@ -15,6 +16,13 @@ export interface IDimentionMessage {
data: DOM.Dimension; data: DOM.Dimension;
} }
export interface IScrollAckMessage {
type: 'scroll-ack';
data: { top: number };
version: number;
}
export interface IClearMessage { export interface IClearMessage {
type: 'clear'; type: 'clear';
} }
...@@ -26,20 +34,36 @@ export interface ICreationRequestMessage { ...@@ -26,20 +34,36 @@ export interface ICreationRequestMessage {
top: number; top: number;
} }
export interface IContentWidgetTopRequest {
id: string;
top: number;
}
export interface IViewScrollTopRequestMessage {
type: 'view-scroll';
top?: number;
widgets: IContentWidgetTopRequest[];
version: number;
}
export interface IScrollRequestMessage { export interface IScrollRequestMessage {
type: 'scroll'; type: 'scroll';
id: string; id: string;
top: number; top: number;
widgetTop?: number;
version: number;
} }
type IMessage = IDimentionMessage; type IMessage = IDimentionMessage | IScrollAckMessage;
export class BackLayerWebView { let version = 0;
export class BackLayerWebView extends Disposable {
public element: HTMLElement; public element: HTMLElement;
public webview: WebviewElement; public webview: WebviewElement;
public mapping: Map<string, { cell: ViewCell, offset: number }> = new Map(); public mapping: Map<string, { cell: ViewCell, offset: number, top: number }> = new Map();
constructor(public webviewService: IWebviewService, public notebookHandler: NotebookHandler) { constructor(public webviewService: IWebviewService, public notebookHandler: NotebookHandler) {
super();
this.element = document.createElement('div'); this.element = document.createElement('div');
this.element.style.width = 'calc(100% - 36px)'; this.element.style.width = 'calc(100% - 36px)';
this.element.style.height = '1400px'; this.element.style.height = '1400px';
...@@ -53,9 +77,10 @@ export class BackLayerWebView { ...@@ -53,9 +77,10 @@ export class BackLayerWebView {
<meta charset="UTF-8"> <meta charset="UTF-8">
</head> </head>
<body style="overflow: hidden;"> <body style="overflow: hidden;">
<div id='container' style="overflow: hidden;"></div> <div id='container' style="position: absolute;width:100%;"></div>
<script> <script>
(function () { (function () {
// eslint-disable-next-line no-undef
const vscode = acquireVsCodeApi(); const vscode = acquireVsCodeApi();
console.log('a'); console.log('a');
...@@ -85,13 +110,26 @@ export class BackLayerWebView { ...@@ -85,13 +110,26 @@ export class BackLayerWebView {
}); });
} }
break; break;
case 'scroll': case 'view-scroll':
{ {
let top = event.data.top; const date = new Date();
let element = document.getElementById(id); console.log('----- will scroll ---- ', date.getMinutes() + ':' + date.getSeconds() + ':' + date.getMilliseconds());
element.style.top = top + 'px';
document.getElementById('container').style.top = event.data.top + 'px';
for (let i = 0; i < event.data.widgets.length; i++) {
let widget = document.getElementById(event.data.widgets[i].id);
widget.style.top = event.data.widgets[i].top + 'px';
}
vscode.postMessage({
type: 'scroll-ack',
data: {
top: event.data.top,
},
version: event.data.version
});
break;
} }
break;
case 'clear': case 'clear':
document.getElementById('container').innerHTML = ''; document.getElementById('container').innerHTML = '';
break; break;
...@@ -106,11 +144,11 @@ export class BackLayerWebView { ...@@ -106,11 +144,11 @@ export class BackLayerWebView {
this.webview = this._createInset(webviewService, content); this.webview = this._createInset(webviewService, content);
this.webview.mountTo(this.element); this.webview.mountTo(this.element);
this.webview.onDidWheel(e => { this._register(this.webview.onDidWheel(e => {
this.notebookHandler.triggerWheel(e); this.notebookHandler.triggerWheel(e);
}); }));
this.webview.onMessage((data: IMessage) => { this._register(this.webview.onMessage((data: IMessage) => {
if (data.type === 'dimension') { if (data.type === 'dimension') {
let cell = this.mapping.get(data.id)?.cell; let cell = this.mapping.get(data.id)?.cell;
let height = data.data.height; let height = data.data.height;
...@@ -120,8 +158,12 @@ export class BackLayerWebView { ...@@ -120,8 +158,12 @@ export class BackLayerWebView {
cell.setDynamicHeight(totalHeight + 32 + height); cell.setDynamicHeight(totalHeight + 32 + height);
this.notebookHandler.layoutElement(cell, totalHeight + 32 + height); this.notebookHandler.layoutElement(cell, totalHeight + 32 + height);
} }
} else if (data.type === 'scroll-ack') {
const date = new Date();
const top = data.data.top;
console.log('ack top ', top, ' version: ', data.version, ' - ', date.getMinutes() + ':' + date.getSeconds() + ':' + date.getMilliseconds());
} }
}); }));
} }
private _createInset(webviewService: IWebviewService, content: string) { private _createInset(webviewService: IWebviewService, content: string) {
...@@ -134,16 +176,31 @@ export class BackLayerWebView { ...@@ -134,16 +176,31 @@ export class BackLayerWebView {
return webview; return webview;
} }
public updateContentWidgetTop(id: string, top: number) { public shouldRenderContentWidget(id: string, widgetTop: number) {
let item = this.mapping.get(id); let item = this.mapping.get(id);
if (item) {
let message: IScrollRequestMessage = { if (item && widgetTop + item.offset !== item.top) {
type: 'scroll', return widgetTop + item.offset;
id: id,
top: item.offset + top
};
this.webview.sendMessage(message);
} }
return undefined;
}
public updateViewScrollTop(top: number, items: { top: number, id: string }[]) {
items.forEach(item => {
if (this.mapping.has(item.id)) {
this.mapping.get(item.id)!.top = item.top;
}
});
let message: IViewScrollTopRequestMessage = {
top,
type: 'view-scroll',
version: version++,
widgets: items
};
this.webview.sendMessage(message);
} }
public createContentWidget(cell: ViewCell, offset: number, shadowContent: string, initialTop: number) { public createContentWidget(cell: ViewCell, offset: number, shadowContent: string, initialTop: number) {
...@@ -155,7 +212,7 @@ export class BackLayerWebView { ...@@ -155,7 +212,7 @@ export class BackLayerWebView {
}; };
this.webview.sendMessage(message); this.webview.sendMessage(message);
this.mapping.set(cell.id, { cell: cell, offset }); this.mapping.set(cell.id, { cell: cell, offset, top: initialTop });
} }
public clearContentWidgets() { public clearContentWidgets() {
......
...@@ -23,6 +23,7 @@ import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsSe ...@@ -23,6 +23,7 @@ import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsSe
import { IWebviewService } from 'vs/workbench/contrib/webview/browser/webview'; import { IWebviewService } from 'vs/workbench/contrib/webview/browser/webview';
import { BackLayerWebView } from 'vs/workbench/contrib/notebook/browser/contentWidget'; import { BackLayerWebView } from 'vs/workbench/contrib/notebook/browser/contentWidget';
import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent';
import { DisposableStore } from 'vs/base/common/lifecycle';
const $ = DOM.$; const $ = DOM.$;
...@@ -36,6 +37,7 @@ export class NotebookEditor extends BaseEditor implements NotebookHandler { ...@@ -36,6 +37,7 @@ export class NotebookEditor extends BaseEditor implements NotebookHandler {
private list: WorkbenchList<ViewCell> | undefined; private list: WorkbenchList<ViewCell> | undefined;
private model: NotebookEditorModel | undefined; private model: NotebookEditorModel | undefined;
private viewCells: ViewCell[] = []; private viewCells: ViewCell[] = [];
private localStore: DisposableStore = new DisposableStore();
constructor( constructor(
@ITelemetryService telemetryService: ITelemetryService, @ITelemetryService telemetryService: ITelemetryService,
...@@ -116,22 +118,6 @@ export class NotebookEditor extends BaseEditor implements NotebookHandler { ...@@ -116,22 +118,6 @@ export class NotebookEditor extends BaseEditor implements NotebookHandler {
this.webview = new BackLayerWebView(this.webviewService, this); this.webview = new BackLayerWebView(this.webviewService, this);
this.list.view.rowsContainer.appendChild(this.webview.element); this.list.view.rowsContainer.appendChild(this.webview.element);
const updateScrollPosition = () => {
let scrollTop = this.list?.scrollTop || 0;
this.webview!.element.style.top = `${scrollTop}px`;
this.webview!.mapping.forEach((item) => {
let index = this.model!.getNotebook().cells.indexOf(item.cell.cell);
let top = this.list?.getElementTop(index);
if (top !== null && top !== undefined) {
this.webview!.updateContentWidgetTop(item.cell.id, -scrollTop + top);
}
});
};
this._register(this.list.onDidScroll(() => updateScrollPosition()));
this._register(this.list.onDidChangeContentHeight(() => updateScrollPosition()));
this._register(this.list); this._register(this.list);
} }
...@@ -140,31 +126,38 @@ export class NotebookEditor extends BaseEditor implements NotebookHandler { ...@@ -140,31 +126,38 @@ export class NotebookEditor extends BaseEditor implements NotebookHandler {
} }
createContentWidget(cell: ViewCell, shadowContent: string, offset: number) { createContentWidget(cell: ViewCell, shadowContent: string, offset: number) {
if (!this.webview) {
return;
}
if (!this.webview!.mapping.has(cell.id)) { if (!this.webview!.mapping.has(cell.id)) {
let index = this.model!.getNotebook().cells.indexOf(cell.cell); let index = this.model!.getNotebook().cells.indexOf(cell.cell);
let top = this.list?.getElementTop(index) || 0; let top = this.list?.getElementTop(index) || 0;
let scrollTop = this.list?.scrollTop || 0; this.webview!.createContentWidget(cell, offset, shadowContent, top + offset);
this.webview!.createContentWidget(cell, offset, shadowContent, -scrollTop + top + offset);
} else { } else {
let index = this.model!.getNotebook().cells.indexOf(cell.cell); let index = this.model!.getNotebook().cells.indexOf(cell.cell);
let top = this.list?.getElementTop(index) || 0; let top = this.list?.getElementTop(index) || 0;
let scrollTop = this.list?.scrollTop || 0; let scrollTop = this.list?.scrollTop || 0;
this.webview!.updateContentWidgetTop(cell.id, -scrollTop + top + offset); this.webview!.updateViewScrollTop(-scrollTop, [{ id: cell.id, top: top + offset }]);
} }
} }
disposeViewCell(cell: ViewCell) { disposeViewCell(cell: ViewCell) {
if (this.webview!.mapping.has(cell.id)) {
this.webview!.updateContentWidgetTop(cell.id, -2400);
return;
}
} }
onHide() { onHide() {
super.onHide();
this.viewCells.forEach(cell => cell.isEditing = false); this.viewCells.forEach(cell => cell.isEditing = false);
if (this.webview) {
this.localStore.clear();
this.list?.view.rowsContainer.removeChild(this.webview?.element);
this.webview?.dispose();
this.webview = null;
}
this.list?.splice(0, this.list?.length);
super.onHide();
} }
setVisible(visible: boolean, group?: IEditorGroup): void { setVisible(visible: boolean, group?: IEditorGroup): void {
...@@ -180,19 +173,60 @@ export class NotebookEditor extends BaseEditor implements NotebookHandler { ...@@ -180,19 +173,60 @@ export class NotebookEditor extends BaseEditor implements NotebookHandler {
return input.resolve(); return input.resolve();
}) })
.then(model => { .then(model => {
if (this.model !== undefined && this.model.textModel === model.textModel) { if (this.model !== undefined && this.model.textModel === model.textModel && this.webview !== null) {
return; return;
} }
this.localStore.clear();
this.viewCells.forEach(cell => { this.viewCells.forEach(cell => {
cell.save(); cell.save();
}); });
this.webview?.clearContentWidgets(); if (this.webview) {
this.webview?.clearContentWidgets();
} else {
this.webview = new BackLayerWebView(this.webviewService, this);
this.list?.view.rowsContainer.insertAdjacentElement('afterbegin', this.webview!.element);
}
this.model = model; this.model = model;
this.viewCells = model.getNotebook().cells.map(cell => { this.viewCells = model.getNotebook().cells.map(cell => {
return new ViewCell(cell, false, this.modelService, this.modeService); return new ViewCell(cell, false, this.modelService, this.modeService);
}); });
const updateScrollPosition = () => {
let scrollTop = this.list?.scrollTop || 0;
this.webview!.element.style.top = `${scrollTop}px`;
let updateItems: { top: number, id: string }[] = [];
const date = new Date();
this.webview?.mapping.forEach((item) => {
let index = this.model!.getNotebook().cells.indexOf(item.cell.cell);
let top = this.list?.getElementTop(index) || 0;
let newTop = this.webview!.shouldRenderContentWidget(item.cell.id, top);
if (newTop !== undefined) {
updateItems.push({
top: newTop,
id: item.cell.id
});
}
});
if (updateItems.length > 0) {
console.log('----- did scroll ---- ', date.getMinutes() + ':' + date.getSeconds() + ':' + date.getMilliseconds());
this.webview?.updateViewScrollTop(-scrollTop, updateItems);
}
};
this.localStore.add(this.list!.onWillScroll(e => {
const date = new Date();
console.log('----- will scroll ---- ', date.getMinutes() + ':' + date.getSeconds() + ':' + date.getMilliseconds());
this.webview?.updateViewScrollTop(-e.scrollTop, []);
}));
this.localStore.add(this.list!.onDidScroll(() => updateScrollPosition()));
this.localStore.add(this.list!.onDidChangeContentHeight(() => updateScrollPosition()));
this.list?.splice(0, this.list?.length, this.viewCells); this.list?.splice(0, this.list?.length, this.viewCells);
this.list?.layout(); this.list?.layout();
}); });
......
...@@ -37,11 +37,43 @@ ...@@ -37,11 +37,43 @@
break; break;
case 'scroll': case 'scroll':
{ {
let top = event.data.top;
let element = document.getElementById(id); let element = document.getElementById(id);
element.style.top = top + 'px'; let top = event.data.top;
if (event.data.widgetTop !== undefined) {
let widgetTop = event.data.widgetTop;
element.style.top = widgetTop + 'px';
document.getElementById('container').style.top = top + 'px';
} else {
document.getElementById('container').style.top = top + 'px';
}
vscode.postMessage({
type: 'scroll-ack',
id: id,
data: {
top: top,
},
version: event.data.version
});
} }
break; break;
case 'view-scroll':
{
document.getElementById('container').style.top = top + 'px';
for (let i = 0; i < event.data.widgets.length; i++) {
let widget = document.getElementById(event.data.widgets[i].id);
widget.style.top = event.data.widgets[i].top + 'px';
}
vscode.postMessage({
type: 'scroll-ack',
data: {
top: top,
},
version: event.data.version
});
break;
}
case 'clear': case 'clear':
document.getElementById('container').innerHTML = ''; document.getElementById('container').innerHTML = '';
break; break;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册