mirror of
https://github.com/mathuo/dockview
synced 2025-05-03 10:08:24 +00:00
Merge branch 'master' of https://github.com/mathuo/dockview into 676-is-it-possiable-that-the-id-and-title-of-group-can-be-assigned
This commit is contained in:
commit
a44fc01f34
@ -3,7 +3,6 @@ import {
|
||||
Emitter,
|
||||
Event,
|
||||
addDisposableListener,
|
||||
addDisposableWindowListener,
|
||||
} from '../events';
|
||||
|
||||
describe('events', () => {
|
||||
@ -143,7 +142,7 @@ describe('events', () => {
|
||||
expect(value).toBe(3);
|
||||
});
|
||||
|
||||
it('addDisposableWindowListener with capture options', () => {
|
||||
it('addDisposableListener with capture options', () => {
|
||||
const element = {
|
||||
addEventListener: jest.fn(),
|
||||
removeEventListener: jest.fn(),
|
||||
@ -151,7 +150,7 @@ describe('events', () => {
|
||||
|
||||
const handler = jest.fn();
|
||||
|
||||
const disposable = addDisposableWindowListener(
|
||||
const disposable = addDisposableListener(
|
||||
element as any,
|
||||
'pointerdown',
|
||||
handler,
|
||||
@ -177,7 +176,7 @@ describe('events', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('addDisposableWindowListener without capture options', () => {
|
||||
it('addDisposableListener without capture options', () => {
|
||||
const element = {
|
||||
addEventListener: jest.fn(),
|
||||
removeEventListener: jest.fn(),
|
||||
@ -185,7 +184,7 @@ describe('events', () => {
|
||||
|
||||
const handler = jest.fn();
|
||||
|
||||
const disposable = addDisposableWindowListener(
|
||||
const disposable = addDisposableListener(
|
||||
element as any,
|
||||
'pointerdown',
|
||||
handler
|
||||
|
@ -3,6 +3,8 @@ import {
|
||||
FloatingGroupOptions,
|
||||
IDockviewComponent,
|
||||
MovePanelEvent,
|
||||
PopoutGroupChangePositionEvent,
|
||||
PopoutGroupChangeSizeEvent,
|
||||
SerializedDockview,
|
||||
} from '../dockview/dockviewComponent';
|
||||
import {
|
||||
@ -629,7 +631,6 @@ export class DockviewApi implements CommonApi<SerializedDockview> {
|
||||
return this.component.totalPanels;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invoked when the active group changes. May be undefined if no group is active.
|
||||
*/
|
||||
@ -740,6 +741,14 @@ export class DockviewApi implements CommonApi<SerializedDockview> {
|
||||
return this.component.onUnhandledDragOverEvent;
|
||||
}
|
||||
|
||||
get onDidPopoutGroupSizeChange(): Event<PopoutGroupChangeSizeEvent> {
|
||||
return this.component.onDidPopoutGroupSizeChange;
|
||||
}
|
||||
|
||||
get onDidPopoutGroupPositionChange(): Event<PopoutGroupChangePositionEvent> {
|
||||
return this.component.onDidPopoutGroupPositionChange;
|
||||
}
|
||||
|
||||
/**
|
||||
* All panel objects.
|
||||
*/
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { addDisposableWindowListener } from '../../events';
|
||||
import { addDisposableListener } from '../../events';
|
||||
import {
|
||||
CompositeDisposable,
|
||||
Disposable,
|
||||
@ -50,7 +50,7 @@ export class PopupService extends CompositeDisposable {
|
||||
this._active = wrapper;
|
||||
|
||||
this._activeDisposable.value = new CompositeDisposable(
|
||||
addDisposableWindowListener(window, 'pointerdown', (event) => {
|
||||
addDisposableListener(window, 'pointerdown', (event) => {
|
||||
const target = event.target;
|
||||
|
||||
if (!(target instanceof HTMLElement)) {
|
||||
|
@ -14,7 +14,7 @@ import {
|
||||
import { tail, sequenceEquals, remove } from '../array';
|
||||
import { DockviewPanel, IDockviewPanel } from './dockviewPanel';
|
||||
import { CompositeDisposable, Disposable } from '../lifecycle';
|
||||
import { Event, Emitter, addDisposableWindowListener } from '../events';
|
||||
import { Event, Emitter, addDisposableListener } from '../events';
|
||||
import { Watermark } from './components/watermark/watermark';
|
||||
import { IWatermarkRenderer, GroupviewPanelState } from './types';
|
||||
import { sequentialNumberGenerator } from '../math';
|
||||
@ -56,6 +56,8 @@ import {
|
||||
addTestId,
|
||||
Classnames,
|
||||
getDockviewTheme,
|
||||
onDidWindowResizeEnd,
|
||||
onDidWindowMoveEnd,
|
||||
toggleClass,
|
||||
watchElementResize,
|
||||
} from '../dom';
|
||||
@ -190,6 +192,18 @@ export interface DockviewMaximizedGroupChanged {
|
||||
isMaximized: boolean;
|
||||
}
|
||||
|
||||
export interface PopoutGroupChangeSizeEvent {
|
||||
width: number;
|
||||
height: number;
|
||||
group: DockviewGroupPanel;
|
||||
}
|
||||
|
||||
export interface PopoutGroupChangePositionEvent {
|
||||
screenX: number;
|
||||
screenY: number;
|
||||
group: DockviewGroupPanel;
|
||||
}
|
||||
|
||||
export interface IDockviewComponent extends IBaseGrid<DockviewGroupPanel> {
|
||||
readonly activePanel: IDockviewPanel | undefined;
|
||||
readonly totalPanels: number;
|
||||
@ -210,6 +224,8 @@ export interface IDockviewComponent extends IBaseGrid<DockviewGroupPanel> {
|
||||
readonly onUnhandledDragOverEvent: Event<DockviewDndOverlayEvent>;
|
||||
readonly onDidMovePanel: Event<MovePanelEvent>;
|
||||
readonly onDidMaximizedGroupChange: Event<DockviewMaximizedGroupChanged>;
|
||||
readonly onDidPopoutGroupSizeChange: Event<PopoutGroupChangeSizeEvent>;
|
||||
readonly onDidPopoutGroupPositionChange: Event<PopoutGroupChangePositionEvent>;
|
||||
readonly options: DockviewComponentOptions;
|
||||
updateOptions(options: DockviewOptions): void;
|
||||
moveGroupOrPanel(options: MoveGroupOrPanelOptions): void;
|
||||
@ -293,6 +309,16 @@ export class DockviewComponent
|
||||
private readonly _onDidAddPanel = new Emitter<IDockviewPanel>();
|
||||
readonly onDidAddPanel: Event<IDockviewPanel> = this._onDidAddPanel.event;
|
||||
|
||||
private readonly _onDidPopoutGroupSizeChange =
|
||||
new Emitter<PopoutGroupChangeSizeEvent>();
|
||||
readonly onDidPopoutGroupSizeChange: Event<PopoutGroupChangeSizeEvent> =
|
||||
this._onDidPopoutGroupSizeChange.event;
|
||||
|
||||
private readonly _onDidPopoutGroupPositionChange =
|
||||
new Emitter<PopoutGroupChangePositionEvent>();
|
||||
readonly onDidPopoutGroupPositionChange: Event<PopoutGroupChangePositionEvent> =
|
||||
this._onDidPopoutGroupPositionChange.event;
|
||||
|
||||
private readonly _onDidLayoutFromJSON = new Emitter<void>();
|
||||
readonly onDidLayoutFromJSON: Event<void> = this._onDidLayoutFromJSON.event;
|
||||
|
||||
@ -427,6 +453,8 @@ export class DockviewComponent
|
||||
this._onUnhandledDragOverEvent,
|
||||
this._onDidMaximizedGroupChange,
|
||||
this._onDidOptionsChange,
|
||||
this._onDidPopoutGroupSizeChange,
|
||||
this._onDidPopoutGroupPositionChange,
|
||||
this.onDidViewVisibilityChangeMicroTaskQueue(() => {
|
||||
this.updateWatermark();
|
||||
}),
|
||||
@ -463,7 +491,9 @@ export class DockviewComponent
|
||||
this.onDidAddGroup,
|
||||
this.onDidRemove,
|
||||
this.onDidMovePanel,
|
||||
this.onDidActivePanelChange
|
||||
this.onDidActivePanelChange,
|
||||
this.onDidPopoutGroupPositionChange,
|
||||
this.onDidPopoutGroupSizeChange
|
||||
)(() => {
|
||||
this._bufferOnDidLayoutChange.fire();
|
||||
}),
|
||||
@ -832,22 +862,37 @@ export class DockviewComponent
|
||||
},
|
||||
};
|
||||
|
||||
const _onDidWindowPositionChange = onDidWindowMoveEnd(
|
||||
_window.window!
|
||||
);
|
||||
|
||||
popoutWindowDisposable.addDisposables(
|
||||
_onDidWindowPositionChange,
|
||||
onDidWindowResizeEnd(_window.window!, () => {
|
||||
this._onDidPopoutGroupSizeChange.fire({
|
||||
width: _window.window!.innerWidth,
|
||||
height: _window.window!.innerHeight,
|
||||
group,
|
||||
});
|
||||
}),
|
||||
_onDidWindowPositionChange.event(() => {
|
||||
this._onDidPopoutGroupPositionChange.fire({
|
||||
screenX: _window.window!.screenX,
|
||||
screenY: _window.window!.screenX,
|
||||
group,
|
||||
});
|
||||
}),
|
||||
/**
|
||||
* ResizeObserver seems slow here, I do not know why but we don't need it
|
||||
* since we can reply on the window resize event as we will occupy the full
|
||||
* window dimensions
|
||||
*/
|
||||
addDisposableWindowListener(
|
||||
_window.window!,
|
||||
'resize',
|
||||
() => {
|
||||
group.layout(
|
||||
_window.window!.innerWidth,
|
||||
_window.window!.innerHeight
|
||||
);
|
||||
}
|
||||
),
|
||||
addDisposableListener(_window.window!, 'resize', () => {
|
||||
group.layout(
|
||||
_window.window!.innerWidth,
|
||||
_window.window!.innerHeight
|
||||
);
|
||||
}),
|
||||
overlayRenderContainer,
|
||||
Disposable.from(() => {
|
||||
if (this.isDisposed) {
|
||||
|
@ -2,7 +2,6 @@ import {
|
||||
Event as DockviewEvent,
|
||||
Emitter,
|
||||
addDisposableListener,
|
||||
addDisposableWindowListener,
|
||||
} from './events';
|
||||
import { IDisposable, CompositeDisposable } from './lifecycle';
|
||||
|
||||
@ -125,7 +124,7 @@ export interface IFocusTracker extends IDisposable {
|
||||
refreshState?(): void;
|
||||
}
|
||||
|
||||
export function trackFocus(element: HTMLElement | Window): IFocusTracker {
|
||||
export function trackFocus(element: HTMLElement): IFocusTracker {
|
||||
return new FocusTracker(element);
|
||||
}
|
||||
|
||||
@ -141,7 +140,7 @@ class FocusTracker extends CompositeDisposable implements IFocusTracker {
|
||||
|
||||
private readonly _refreshStateHandler: () => void;
|
||||
|
||||
constructor(element: HTMLElement | Window) {
|
||||
constructor(element: HTMLElement) {
|
||||
super();
|
||||
|
||||
this.addDisposables(this._onDidFocus, this._onDidBlur);
|
||||
@ -184,21 +183,12 @@ class FocusTracker extends CompositeDisposable implements IFocusTracker {
|
||||
}
|
||||
};
|
||||
|
||||
if (element instanceof HTMLElement) {
|
||||
this.addDisposables(
|
||||
addDisposableListener(element, 'focus', onFocus, true)
|
||||
);
|
||||
this.addDisposables(
|
||||
addDisposableListener(element, 'blur', onBlur, true)
|
||||
);
|
||||
} else {
|
||||
this.addDisposables(
|
||||
addDisposableWindowListener(element, 'focus', onFocus, true)
|
||||
);
|
||||
this.addDisposables(
|
||||
addDisposableWindowListener(element, 'blur', onBlur, true)
|
||||
);
|
||||
}
|
||||
this.addDisposables(
|
||||
addDisposableListener(element, 'focus', onFocus, true)
|
||||
);
|
||||
this.addDisposables(
|
||||
addDisposableListener(element, 'blur', onBlur, true)
|
||||
);
|
||||
}
|
||||
|
||||
refreshState(): void {
|
||||
@ -386,6 +376,8 @@ export class Classnames {
|
||||
}
|
||||
}
|
||||
|
||||
const DEBOUCE_DELAY = 100;
|
||||
|
||||
export function isChildEntirelyVisibleWithinParent(
|
||||
child: HTMLElement,
|
||||
parent: HTMLElement
|
||||
@ -407,3 +399,55 @@ export function isChildEntirelyVisibleWithinParent(
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function onDidWindowMoveEnd(window: Window): Emitter<void> {
|
||||
const emitter = new Emitter<void>();
|
||||
|
||||
let previousScreenX = window.screenX;
|
||||
let previousScreenY = window.screenY;
|
||||
|
||||
let timeout: any;
|
||||
|
||||
const checkMovement = () => {
|
||||
if (window.closed) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentScreenX = window.screenX;
|
||||
const currentScreenY = window.screenY;
|
||||
|
||||
if (
|
||||
currentScreenX !== previousScreenX ||
|
||||
currentScreenY !== previousScreenY
|
||||
) {
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => {
|
||||
emitter.fire();
|
||||
}, DEBOUCE_DELAY);
|
||||
|
||||
previousScreenX = currentScreenX;
|
||||
previousScreenY = currentScreenY;
|
||||
}
|
||||
|
||||
requestAnimationFrame(checkMovement);
|
||||
};
|
||||
|
||||
checkMovement();
|
||||
|
||||
return emitter;
|
||||
}
|
||||
|
||||
export function onDidWindowResizeEnd(element: Window, cb: () => void) {
|
||||
let resizeTimeout: any;
|
||||
|
||||
const disposable = new CompositeDisposable(
|
||||
addDisposableListener(element, 'resize', () => {
|
||||
clearTimeout(resizeTimeout);
|
||||
resizeTimeout = setTimeout(() => {
|
||||
cb();
|
||||
}, DEBOUCE_DELAY);
|
||||
})
|
||||
);
|
||||
|
||||
return disposable;
|
||||
}
|
||||
|
@ -193,32 +193,38 @@ export class Emitter<T> implements IDisposable {
|
||||
}
|
||||
}
|
||||
|
||||
export function addDisposableWindowListener<K extends keyof WindowEventMap>(
|
||||
export function addDisposableListener<K extends keyof WindowEventMap>(
|
||||
element: Window,
|
||||
type: K,
|
||||
listener: (this: Window, ev: WindowEventMap[K]) => any,
|
||||
options?: boolean | AddEventListenerOptions
|
||||
): IDisposable {
|
||||
element.addEventListener(type, listener, options);
|
||||
|
||||
return {
|
||||
dispose: () => {
|
||||
element.removeEventListener(type, listener, options);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
): IDisposable;
|
||||
export function addDisposableListener<K extends keyof HTMLElementEventMap>(
|
||||
element: HTMLElement,
|
||||
type: K,
|
||||
listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any,
|
||||
options?: boolean | AddEventListenerOptions
|
||||
): IDisposable;
|
||||
export function addDisposableListener<
|
||||
K extends keyof HTMLElementEventMap | keyof WindowEventMap
|
||||
>(
|
||||
element: HTMLElement | Window,
|
||||
type: K,
|
||||
listener: (
|
||||
this: K extends keyof HTMLElementEventMap ? HTMLElement : Window,
|
||||
ev: K extends keyof HTMLElementEventMap
|
||||
? HTMLElementEventMap[K]
|
||||
: K extends keyof WindowEventMap
|
||||
? WindowEventMap[K]
|
||||
: never
|
||||
) => any,
|
||||
options?: boolean | AddEventListenerOptions
|
||||
): IDisposable {
|
||||
element.addEventListener(type, listener, options);
|
||||
element.addEventListener(type, <any>listener, options);
|
||||
|
||||
return {
|
||||
dispose: () => {
|
||||
element.removeEventListener(type, listener, options);
|
||||
element.removeEventListener(type, <any>listener, options);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import {
|
||||
Emitter,
|
||||
Event,
|
||||
addDisposableListener,
|
||||
addDisposableWindowListener,
|
||||
} from '../events';
|
||||
import { CompositeDisposable, MutableDisposable } from '../lifecycle';
|
||||
import { clamp } from '../math';
|
||||
@ -258,7 +257,7 @@ export class Overlay extends CompositeDisposable {
|
||||
iframes.release();
|
||||
},
|
||||
},
|
||||
addDisposableWindowListener(window, 'pointermove', (e) => {
|
||||
addDisposableListener(window, 'pointermove', (e) => {
|
||||
const containerRect =
|
||||
this.options.container.getBoundingClientRect();
|
||||
const x = e.clientX - containerRect.left;
|
||||
@ -344,7 +343,7 @@ export class Overlay extends CompositeDisposable {
|
||||
|
||||
this.setBounds(bounds);
|
||||
}),
|
||||
addDisposableWindowListener(window, 'pointerup', () => {
|
||||
addDisposableListener(window, 'pointerup', () => {
|
||||
toggleClass(
|
||||
this._element,
|
||||
'dv-resize-container-dragging',
|
||||
@ -439,7 +438,7 @@ export class Overlay extends CompositeDisposable {
|
||||
const iframes = disableIframePointEvents();
|
||||
|
||||
move.value = new CompositeDisposable(
|
||||
addDisposableWindowListener(window, 'pointermove', (e) => {
|
||||
addDisposableListener(window, 'pointermove', (e) => {
|
||||
const containerRect =
|
||||
this.options.container.getBoundingClientRect();
|
||||
const overlayRect =
|
||||
@ -610,7 +609,7 @@ export class Overlay extends CompositeDisposable {
|
||||
iframes.release();
|
||||
},
|
||||
},
|
||||
addDisposableWindowListener(window, 'pointerup', () => {
|
||||
addDisposableListener(window, 'pointerup', () => {
|
||||
move.dispose();
|
||||
this._onDidChangeEnd.fire();
|
||||
})
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { addStyles } from './dom';
|
||||
import { Emitter, addDisposableWindowListener } from './events';
|
||||
import { Emitter, addDisposableListener } from './events';
|
||||
import { CompositeDisposable, Disposable, IDisposable } from './lifecycle';
|
||||
import { Box } from './types';
|
||||
|
||||
@ -101,7 +101,7 @@ export class PopoutWindow extends CompositeDisposable {
|
||||
Disposable.from(() => {
|
||||
externalWindow.close();
|
||||
}),
|
||||
addDisposableWindowListener(window, 'beforeunload', () => {
|
||||
addDisposableListener(window, 'beforeunload', () => {
|
||||
/**
|
||||
* before the main window closes we should close this popup too
|
||||
* to be good citizens
|
||||
@ -146,7 +146,7 @@ export class PopoutWindow extends CompositeDisposable {
|
||||
* beforeunload must be registered after load for reasons I could not determine
|
||||
* otherwise the beforeunload event will not fire when the window is closed
|
||||
*/
|
||||
addDisposableWindowListener(
|
||||
addDisposableListener(
|
||||
externalWindow,
|
||||
'beforeunload',
|
||||
() => {
|
||||
|
Loading…
Reference in New Issue
Block a user