Skip to content

Commit

Permalink
Merge pull request #93630 from nrayburn-tech/resizeobserver
Browse files Browse the repository at this point in the history
Use ResizeObserver for monaco editor automaticLayout
  • Loading branch information
alexdima committed Mar 29, 2020
2 parents dcdb4b7 + dbc1450 commit 35cbc3f
Showing 1 changed file with 53 additions and 28 deletions.
81 changes: 53 additions & 28 deletions src/vs/editor/browser/config/elementSizeObserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,52 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { Disposable } from 'vs/base/common/lifecycle';
import { IDimension } from 'vs/editor/common/editorCommon';
import * as dom from 'vs/base/browser/dom';

interface ResizeObserver {
observe(target: Element): void;
unobserve(target: Element): void;
disconnect(): void;
}

interface ResizeObserverSize {
inlineSize: number;
blockSize: number;
}

interface ResizeObserverEntry {
readonly target: Element;
readonly contentRect: DOMRectReadOnly;
readonly borderBoxSize: ResizeObserverSize;
readonly contentBoxSize: ResizeObserverSize;
}

type ResizeObserverCallback = (entries: ReadonlyArray<ResizeObserverEntry>, observer: ResizeObserver) => void;

declare const ResizeObserver: {
prototype: ResizeObserver;
new(callback: ResizeObserverCallback): ResizeObserver;
};


export class ElementSizeObserver extends Disposable {

private readonly referenceDomElement: HTMLElement | null;
private readonly changeCallback: () => void;
private width: number;
private height: number;
private mutationObserver: MutationObserver | null;
private windowSizeListener: IDisposable | null;
private resizeObserver: ResizeObserver | null;
private measureReferenceDomElementToken: number;

constructor(referenceDomElement: HTMLElement | null, dimension: IDimension | undefined, changeCallback: () => void) {
super();
this.referenceDomElement = referenceDomElement;
this.changeCallback = changeCallback;
this.width = -1;
this.height = -1;
this.mutationObserver = null;
this.windowSizeListener = null;
this.resizeObserver = null;
this.measureReferenceDomElementToken = -1;
this.measureReferenceDomElement(false, dimension);
}

Expand All @@ -41,40 +66,40 @@ export class ElementSizeObserver extends Disposable {
}

public startObserving(): void {
if (!this.mutationObserver && this.referenceDomElement) {
this.mutationObserver = new MutationObserver(() => this._onDidMutate());
this.mutationObserver.observe(this.referenceDomElement, {
attributes: true,
});
}
if (!this.windowSizeListener) {
this.windowSizeListener = dom.addDisposableListener(window, 'resize', () => this._onDidResizeWindow());
if (typeof ResizeObserver !== 'undefined') {
if (!this.resizeObserver && this.referenceDomElement) {
this.resizeObserver = new ResizeObserver((entries) => {
if (entries && entries[0] && entries[0].contentRect) {
this.observe({ width: entries[0].contentRect.width, height: entries[0].contentRect.height });
} else {
this.observe();
}
});
this.resizeObserver.observe(this.referenceDomElement);
}
} else {
if (this.measureReferenceDomElementToken === -1) {
// setInterval type defaults to NodeJS.Timeout instead of number, so specify it as a number
this.measureReferenceDomElementToken = <number><any>setInterval(() => this.observe(), 100);
}
}
}

public stopObserving(): void {
if (this.mutationObserver) {
this.mutationObserver.disconnect();
this.mutationObserver = null;
if (this.resizeObserver) {
this.resizeObserver.disconnect();
this.resizeObserver = null;
}
if (this.windowSizeListener) {
this.windowSizeListener.dispose();
this.windowSizeListener = null;
if (this.measureReferenceDomElementToken !== -1) {
clearInterval(this.measureReferenceDomElementToken);
this.measureReferenceDomElementToken = -1;
}
}

public observe(dimension?: IDimension): void {
this.measureReferenceDomElement(true, dimension);
}

private _onDidMutate(): void {
this.measureReferenceDomElement(true);
}

private _onDidResizeWindow(): void {
this.measureReferenceDomElement(true);
}

private measureReferenceDomElement(callChangeCallback: boolean, dimension?: IDimension): void {
let observedWidth = 0;
let observedHeight = 0;
Expand Down

0 comments on commit 35cbc3f

Please sign in to comment.