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