mirror of
https://github.com/mathuo/dockview
synced 2025-05-06 03:28:25 +00:00
Merge pull request #686 from mathuo/651-offical-support-for-vanilla-typescript-1
chore: updateOptions logic
This commit is contained in:
commit
05084030db
@ -1,20 +1,16 @@
|
||||
import { DockviewApi } from '../../../../api/component.api';
|
||||
import { Watermark } from '../../../../dockview/components/watermark/watermark';
|
||||
import { fromPartial } from '@total-typescript/shoehorn';
|
||||
|
||||
describe('watermark', () => {
|
||||
test('that the group is closed when the close button is clicked', () => {
|
||||
const cut = new Watermark();
|
||||
|
||||
const mockApi = jest.fn<Partial<DockviewApi>, any[]>(() => {
|
||||
return {
|
||||
removeGroup: jest.fn(),
|
||||
};
|
||||
const api = fromPartial<DockviewApi>({
|
||||
removeGroup: jest.fn(),
|
||||
});
|
||||
const api = <DockviewApi>new mockApi();
|
||||
const group = jest.fn() as any;
|
||||
|
||||
cut.init({ containerApi: api });
|
||||
cut.updateParentGroup(group, true);
|
||||
cut.init({ containerApi: api, group });
|
||||
|
||||
const closeEl = cut.element.querySelector('.close-action')!;
|
||||
|
||||
|
@ -8,9 +8,9 @@ import { PanelUpdateEvent } from '../../panel/types';
|
||||
import { Orientation } from '../../splitview/splitview';
|
||||
import { CompositeDisposable } from '../../lifecycle';
|
||||
import { Emitter } from '../../events';
|
||||
import { DockviewPanel, IDockviewPanel } from '../../dockview/dockviewPanel';
|
||||
import { IDockviewPanel } from '../../dockview/dockviewPanel';
|
||||
import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel';
|
||||
import { fireEvent, getByTestId, queryByTestId } from '@testing-library/dom';
|
||||
import { fireEvent, queryByTestId } from '@testing-library/dom';
|
||||
import { getPanelData } from '../../dnd/dataTransfer';
|
||||
import {
|
||||
GroupDragEvent,
|
||||
|
@ -116,10 +116,6 @@ class Watermark implements IWatermarkRenderer {
|
||||
return {};
|
||||
}
|
||||
|
||||
updateParentGroup() {
|
||||
//
|
||||
}
|
||||
|
||||
dispose() {
|
||||
//
|
||||
}
|
||||
|
@ -68,8 +68,8 @@ class TestPanel implements IGridPanelView {
|
||||
class ClassUnderTest extends BaseGrid<TestPanel> {
|
||||
readonly gridview = this.gridview;
|
||||
|
||||
constructor(options: BaseGridOptions) {
|
||||
super(options);
|
||||
constructor(parentElement: HTMLElement, options: BaseGridOptions) {
|
||||
super(parentElement, options);
|
||||
}
|
||||
|
||||
doRemoveGroup(
|
||||
@ -106,8 +106,7 @@ class ClassUnderTest extends BaseGrid<TestPanel> {
|
||||
|
||||
describe('baseComponentGridview', () => {
|
||||
test('that .layout(...) force flag works', () => {
|
||||
const cut = new ClassUnderTest({
|
||||
parentElement: document.createElement('div'),
|
||||
const cut = new ClassUnderTest(document.createElement('div'), {
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
proportionalLayout: true,
|
||||
});
|
||||
@ -131,8 +130,7 @@ describe('baseComponentGridview', () => {
|
||||
});
|
||||
|
||||
test('can add group', () => {
|
||||
const cut = new ClassUnderTest({
|
||||
parentElement: document.createElement('div'),
|
||||
const cut = new ClassUnderTest(document.createElement('div'), {
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
proportionalLayout: true,
|
||||
});
|
||||
|
@ -5,8 +5,7 @@ import {
|
||||
import { addDisposableListener } from '../../../events';
|
||||
import { toggleClass } from '../../../dom';
|
||||
import { CompositeDisposable } from '../../../lifecycle';
|
||||
import { DockviewGroupPanel } from '../../dockviewGroupPanel';
|
||||
import { PanelUpdateEvent } from '../../../panel/types';
|
||||
import { IDockviewGroupPanel } from '../../dockviewGroupPanel';
|
||||
import { createCloseButton } from '../../../svg';
|
||||
import { DockviewApi } from '../../../api/component.api';
|
||||
|
||||
@ -15,7 +14,7 @@ export class Watermark
|
||||
implements IWatermarkRenderer
|
||||
{
|
||||
private _element: HTMLElement;
|
||||
private _group: DockviewGroupPanel | undefined;
|
||||
private _group: IDockviewGroupPanel | undefined;
|
||||
private _api: DockviewApi | undefined;
|
||||
|
||||
get element(): HTMLElement {
|
||||
@ -52,8 +51,9 @@ export class Watermark
|
||||
title.appendChild(actionsContainer);
|
||||
|
||||
this.addDisposables(
|
||||
addDisposableListener(closeAnchor, 'click', (ev) => {
|
||||
ev.preventDefault();
|
||||
addDisposableListener(closeAnchor, 'click', (event: MouseEvent) => {
|
||||
event.preventDefault();
|
||||
|
||||
if (this._group) {
|
||||
this._api?.removeGroup(this._group);
|
||||
}
|
||||
@ -61,32 +61,12 @@ export class Watermark
|
||||
);
|
||||
}
|
||||
|
||||
update(_event: PanelUpdateEvent): void {
|
||||
// noop
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
// noop
|
||||
}
|
||||
|
||||
layout(_width: number, _height: number): void {
|
||||
// noop
|
||||
}
|
||||
|
||||
init(_params: WatermarkRendererInitParameters): void {
|
||||
this._api = _params.containerApi;
|
||||
this._group = _params.group;
|
||||
this.render();
|
||||
}
|
||||
|
||||
updateParentGroup(group: DockviewGroupPanel, _visible: boolean): void {
|
||||
this._group = group;
|
||||
this.render();
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private render(): void {
|
||||
const isOneGroup = !!(this._api && this._api.size <= 1);
|
||||
toggleClass(this.element, 'has-actions', isOneGroup);
|
||||
|
@ -51,7 +51,12 @@ import { DockviewPanelModel } from './dockviewPanelModel';
|
||||
import { getPanelData } from '../dnd/dataTransfer';
|
||||
import { Parameters } from '../panel/types';
|
||||
import { Overlay } from '../overlay/overlay';
|
||||
import { addTestId, toggleClass, watchElementResize } from '../dom';
|
||||
import {
|
||||
addTestId,
|
||||
getDockviewTheme,
|
||||
toggleClass,
|
||||
watchElementResize,
|
||||
} from '../dom';
|
||||
import { DockviewFloatingGroupPanel } from './dockviewFloatingGroupPanel';
|
||||
import {
|
||||
GroupDragEvent,
|
||||
@ -92,33 +97,6 @@ function moveGroupWithoutDestroying(options: {
|
||||
});
|
||||
}
|
||||
|
||||
function getDockviewTheme(element: HTMLElement): string | undefined {
|
||||
function toClassList(element: HTMLElement) {
|
||||
const list: string[] = [];
|
||||
|
||||
for (let i = 0; i < element.classList.length; i++) {
|
||||
list.push(element.classList.item(i)!);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
let theme: string | undefined = undefined;
|
||||
let parent: HTMLElement | null = element;
|
||||
|
||||
while (parent !== null) {
|
||||
theme = toClassList(parent).find((cls) =>
|
||||
cls.startsWith('dockview-theme-')
|
||||
);
|
||||
if (typeof theme === 'string') {
|
||||
break;
|
||||
}
|
||||
parent = parent.parentElement;
|
||||
}
|
||||
|
||||
return theme;
|
||||
}
|
||||
|
||||
export interface PanelReference {
|
||||
update: (event: { params: { [key: string]: any } }) => void;
|
||||
remove: () => void;
|
||||
@ -362,23 +340,18 @@ export class DockviewComponent
|
||||
}
|
||||
|
||||
constructor(parentElement: HTMLElement, options: DockviewComponentOptions) {
|
||||
super({
|
||||
super(parentElement, {
|
||||
proportionalLayout: true,
|
||||
orientation: Orientation.HORIZONTAL,
|
||||
styles: options.hideBorders
|
||||
? { separatorBorder: 'transparent' }
|
||||
: undefined,
|
||||
parentElement: parentElement,
|
||||
disableAutoResizing: options.disableAutoResizing,
|
||||
locked: options.locked,
|
||||
margin: options.gap,
|
||||
className: options.className,
|
||||
});
|
||||
|
||||
// const gready = document.createElement('div');
|
||||
// gready.className = 'dv-overlay-render-container';
|
||||
// this.gridview.element.appendChild(gready);
|
||||
|
||||
this.overlayRenderContainer = new OverlayRenderContainer(
|
||||
this.gridview.element,
|
||||
this
|
||||
@ -1022,19 +995,9 @@ export class DockviewComponent
|
||||
override updateOptions(options: Partial<DockviewComponentOptions>): void {
|
||||
super.updateOptions(options);
|
||||
|
||||
const changed_floatingGroupBounds =
|
||||
'floatingGroupBounds' in options &&
|
||||
options.floatingGroupBounds !== this.options.floatingGroupBounds;
|
||||
|
||||
const changed_rootOverlayOptions =
|
||||
'rootOverlayModel' in options &&
|
||||
options.rootOverlayModel !== this.options.rootOverlayModel;
|
||||
|
||||
this._options = { ...this.options, ...options };
|
||||
|
||||
if (changed_floatingGroupBounds) {
|
||||
if ('floatingGroupBounds' in options) {
|
||||
for (const group of this._floatingGroups) {
|
||||
switch (this.options.floatingGroupBounds) {
|
||||
switch (options.floatingGroupBounds) {
|
||||
case 'boundedWithinViewport':
|
||||
group.overlay.minimumInViewportHeight = undefined;
|
||||
group.overlay.minimumInViewportWidth = undefined;
|
||||
@ -1047,30 +1010,26 @@ export class DockviewComponent
|
||||
break;
|
||||
default:
|
||||
group.overlay.minimumInViewportHeight =
|
||||
this.options.floatingGroupBounds?.minimumHeightWithinViewport;
|
||||
options.floatingGroupBounds?.minimumHeightWithinViewport;
|
||||
group.overlay.minimumInViewportWidth =
|
||||
this.options.floatingGroupBounds?.minimumWidthWithinViewport;
|
||||
options.floatingGroupBounds?.minimumWidthWithinViewport;
|
||||
}
|
||||
|
||||
group.overlay.setBounds();
|
||||
}
|
||||
}
|
||||
|
||||
if (changed_rootOverlayOptions) {
|
||||
this._rootDropTarget.setOverlayModel(options.rootOverlayModel!);
|
||||
if ('rootOverlayModel' in options) {
|
||||
this._rootDropTarget.setOverlayModel(
|
||||
options.rootOverlayModel ?? DEFAULT_ROOT_OVERLAY_MODEL
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
// if explicitly set as `undefined`
|
||||
'gap' in options &&
|
||||
options.gap === undefined
|
||||
) {
|
||||
this.gridview.margin = 0;
|
||||
if ('gap' in options) {
|
||||
this.gridview.margin = options.gap ?? 0;
|
||||
}
|
||||
|
||||
if (typeof options.gap === 'number') {
|
||||
this.gridview.margin = options.gap;
|
||||
}
|
||||
this._options = { ...this.options, ...options };
|
||||
|
||||
this.layout(this.gridview.width, this.gridview.height, true);
|
||||
}
|
||||
@ -1108,7 +1067,7 @@ export class DockviewComponent
|
||||
if (!this.activeGroup) {
|
||||
return;
|
||||
}
|
||||
options.group = this.activeGroup;
|
||||
options.group = this.activeGroup;
|
||||
}
|
||||
|
||||
if (options.includePanel && options.group) {
|
||||
|
@ -972,8 +972,6 @@ export class DockviewGroupPanelModel
|
||||
|
||||
this.tabsContainer.hide();
|
||||
this.contentContainer.element.appendChild(this.watermark.element);
|
||||
|
||||
this.watermark.updateParentGroup(this.groupPanel, true);
|
||||
}
|
||||
if (!this.isEmpty && this.watermark) {
|
||||
this.watermark.element.remove();
|
||||
|
@ -32,7 +32,6 @@ export interface IWatermarkRenderer
|
||||
extends Optional<Omit<IPanel, 'id' | 'init'>, RendererMethodOptionalList> {
|
||||
readonly element: HTMLElement;
|
||||
init: (params: WatermarkRendererInitParameters) => void;
|
||||
updateParentGroup(group: DockviewGroupPanel, visible: boolean): void;
|
||||
}
|
||||
|
||||
export interface ITabRenderer
|
||||
|
@ -280,3 +280,50 @@ export function disableIframePointEvents() {
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function getDockviewTheme(element: HTMLElement): string | undefined {
|
||||
function toClassList(element: HTMLElement) {
|
||||
const list: string[] = [];
|
||||
|
||||
for (let i = 0; i < element.classList.length; i++) {
|
||||
list.push(element.classList.item(i)!);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
let theme: string | undefined = undefined;
|
||||
let parent: HTMLElement | null = element;
|
||||
|
||||
while (parent !== null) {
|
||||
theme = toClassList(parent).find((cls) =>
|
||||
cls.startsWith('dockview-theme-')
|
||||
);
|
||||
if (typeof theme === 'string') {
|
||||
break;
|
||||
}
|
||||
parent = parent.parentElement;
|
||||
}
|
||||
|
||||
return theme;
|
||||
}
|
||||
|
||||
export class Classnames {
|
||||
private _classNames: string[] = [];
|
||||
|
||||
constructor(private readonly element: HTMLElement) {}
|
||||
|
||||
setClassNames(classNames: string) {
|
||||
for (const className of this._classNames) {
|
||||
toggleClass(this.element, className, false);
|
||||
}
|
||||
|
||||
this._classNames = classNames
|
||||
.split(' ')
|
||||
.filter((v) => v.trim().length > 0);
|
||||
|
||||
for (const className of this._classNames) {
|
||||
toggleClass(this.element, className, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import { ISplitviewStyles, Orientation, Sizing } from '../splitview/splitview';
|
||||
import { IPanel } from '../panel/types';
|
||||
import { MovementOptions2 } from '../dockview/options';
|
||||
import { Resizable } from '../resizable';
|
||||
import { toggleClass } from '../dom';
|
||||
import { Classnames, toggleClass } from '../dom';
|
||||
|
||||
const nextLayoutId = sequentialNumberGenerator();
|
||||
|
||||
@ -33,7 +33,6 @@ export interface BaseGridOptions {
|
||||
readonly proportionalLayout: boolean;
|
||||
readonly orientation: Orientation;
|
||||
readonly styles?: ISplitviewStyles;
|
||||
readonly parentElement: HTMLElement;
|
||||
readonly disableAutoResizing?: boolean;
|
||||
readonly locked?: boolean;
|
||||
readonly margin?: number;
|
||||
@ -100,7 +99,7 @@ export abstract class BaseGrid<T extends IGridPanelView>
|
||||
readonly onDidViewVisibilityChangeMicroTaskQueue =
|
||||
this._onDidViewVisibilityChangeMicroTaskQueue.onEvent;
|
||||
|
||||
private classNames: string[] = [];
|
||||
private readonly _classNames: Classnames;
|
||||
|
||||
get id(): string {
|
||||
return this._id;
|
||||
@ -147,18 +146,15 @@ export abstract class BaseGrid<T extends IGridPanelView>
|
||||
this.gridview.locked = value;
|
||||
}
|
||||
|
||||
constructor(options: BaseGridOptions) {
|
||||
constructor(parentElement: HTMLElement, options: BaseGridOptions) {
|
||||
super(document.createElement('div'), options.disableAutoResizing);
|
||||
this.element.style.height = '100%';
|
||||
this.element.style.width = '100%';
|
||||
|
||||
this.classNames = options.className?.split(' ') ?? [];
|
||||
this._classNames = new Classnames(this.element);
|
||||
this._classNames.setClassNames(options.className ?? '');
|
||||
|
||||
for (const className of this.classNames) {
|
||||
toggleClass(this.element, className, true);
|
||||
}
|
||||
|
||||
options.parentElement.appendChild(this.element);
|
||||
parentElement.appendChild(this.element);
|
||||
|
||||
this.gridview = new Gridview(
|
||||
!!options.proportionalLayout,
|
||||
@ -214,14 +210,26 @@ export abstract class BaseGrid<T extends IGridPanelView>
|
||||
}
|
||||
|
||||
updateOptions(options: Partial<BaseGridOptions>) {
|
||||
if (typeof options.proportionalLayout === 'boolean') {
|
||||
// this.gridview.proportionalLayout = options.proportionalLayout; // not supported
|
||||
}
|
||||
if (options.orientation) {
|
||||
this.gridview.orientation = options.orientation;
|
||||
}
|
||||
if ('styles' in options) {
|
||||
// this.gridview.styles = options.styles; // not supported
|
||||
}
|
||||
if ('disableResizing' in options) {
|
||||
this.disableResizing = options.disableAutoResizing ?? false;
|
||||
}
|
||||
if ('locked' in options) {
|
||||
this.locked = options.locked ?? false;
|
||||
}
|
||||
if ('margin' in options) {
|
||||
this.gridview.margin = options.margin ?? 0;
|
||||
}
|
||||
if ('className' in options) {
|
||||
for (const className of this.classNames) {
|
||||
toggleClass(this.element, className, false);
|
||||
}
|
||||
this.classNames = options.className?.split(' ') ?? [];
|
||||
for (const className of this.classNames) {
|
||||
toggleClass(this.element, className, true);
|
||||
}
|
||||
this._classNames.setClassNames(options.className ?? '');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,8 +115,7 @@ export class GridviewComponent
|
||||
}
|
||||
|
||||
constructor(parentElement: HTMLElement, options: GridviewComponentOptions) {
|
||||
super({
|
||||
parentElement: parentElement,
|
||||
super(parentElement, {
|
||||
proportionalLayout: options.proportionalLayout,
|
||||
orientation: options.orientation,
|
||||
styles: options.styles,
|
||||
|
@ -24,7 +24,7 @@ import { sequentialNumberGenerator } from '../math';
|
||||
import { PaneTransfer } from '../dnd/dataTransfer';
|
||||
import { Resizable } from '../resizable';
|
||||
import { Parameters } from '../panel/types';
|
||||
import { toggleClass } from '../dom';
|
||||
import { Classnames, toggleClass } from '../dom';
|
||||
|
||||
const nextLayoutId = sequentialNumberGenerator();
|
||||
|
||||
@ -152,7 +152,7 @@ export class PaneviewComponent extends Resizable implements IPaneviewComponent {
|
||||
private readonly _onDidRemoveView = new Emitter<PaneviewPanel>();
|
||||
readonly onDidRemoveView = this._onDidRemoveView.event;
|
||||
|
||||
private classNames: string[] = [];
|
||||
private readonly _classNames: Classnames;
|
||||
|
||||
get id(): string {
|
||||
return this._id;
|
||||
@ -213,11 +213,8 @@ export class PaneviewComponent extends Resizable implements IPaneviewComponent {
|
||||
this._onDidRemoveView
|
||||
);
|
||||
|
||||
this.classNames = options.className?.split(' ') ?? [];
|
||||
|
||||
for (const className of this.classNames) {
|
||||
toggleClass(this.element, className, true);
|
||||
}
|
||||
this._classNames = new Classnames(this.element);
|
||||
this._classNames.setClassNames(options.className ?? '');
|
||||
|
||||
this._options = options;
|
||||
|
||||
@ -247,13 +244,11 @@ export class PaneviewComponent extends Resizable implements IPaneviewComponent {
|
||||
|
||||
updateOptions(options: Partial<PaneviewComponentOptions>): void {
|
||||
if ('className' in options) {
|
||||
for (const className of this.classNames) {
|
||||
toggleClass(this.element, className, false);
|
||||
}
|
||||
this.classNames = options.className?.split(' ') ?? [];
|
||||
for (const className of this.classNames) {
|
||||
toggleClass(this.element, className, true);
|
||||
}
|
||||
this._classNames.setClassNames(options.className ?? '');
|
||||
}
|
||||
|
||||
if ('disableResizing' in options) {
|
||||
this.disableResizing = options.disableAutoResizing ?? false;
|
||||
}
|
||||
|
||||
this._options = { ...this.options, ...options };
|
||||
|
@ -17,7 +17,7 @@ import { Emitter, Event } from '../events';
|
||||
import { SplitviewPanel, ISplitviewPanel } from './splitviewPanel';
|
||||
import { createComponent } from '../panel/componentFactory';
|
||||
import { Resizable } from '../resizable';
|
||||
import { toggleClass } from '../dom';
|
||||
import { Classnames, toggleClass } from '../dom';
|
||||
|
||||
export interface SerializedSplitviewPanelData {
|
||||
id: string;
|
||||
@ -100,7 +100,7 @@ export class SplitviewComponent
|
||||
private readonly _onDidLayoutChange = new Emitter<void>();
|
||||
readonly onDidLayoutChange: Event<void> = this._onDidLayoutChange.event;
|
||||
|
||||
private classNames: string[] = [];
|
||||
private readonly _classNames: Classnames;
|
||||
|
||||
get panels(): SplitviewPanel[] {
|
||||
return this.splitview.getViews();
|
||||
@ -162,11 +162,8 @@ export class SplitviewComponent
|
||||
) {
|
||||
super(parentElement, options.disableAutoResizing);
|
||||
|
||||
this.classNames = options.className?.split(' ') ?? [];
|
||||
|
||||
for (const className of this.classNames) {
|
||||
toggleClass(this.element, className, true);
|
||||
}
|
||||
this._classNames = new Classnames(this.element);
|
||||
this._classNames.setClassNames(options.className ?? '');
|
||||
|
||||
this._options = options;
|
||||
|
||||
@ -189,25 +186,19 @@ export class SplitviewComponent
|
||||
|
||||
updateOptions(options: Partial<SplitviewComponentOptions>): void {
|
||||
if ('className' in options) {
|
||||
for (const className of this.classNames) {
|
||||
toggleClass(this.element, className, false);
|
||||
}
|
||||
this.classNames = options.className?.split(' ') ?? [];
|
||||
for (const className of this.classNames) {
|
||||
toggleClass(this.element, className, true);
|
||||
}
|
||||
this._classNames.setClassNames(options.className ?? '');
|
||||
}
|
||||
|
||||
const hasOrientationChanged =
|
||||
typeof options.orientation === 'string' &&
|
||||
this.options.orientation !== options.orientation;
|
||||
if ('disableResizing' in options) {
|
||||
this.disableResizing = options.disableAutoResizing ?? false;
|
||||
}
|
||||
|
||||
this._options = { ...this.options, ...options };
|
||||
|
||||
if (hasOrientationChanged) {
|
||||
if (typeof options.orientation === 'string') {
|
||||
this.splitview.orientation = options.orientation!;
|
||||
}
|
||||
|
||||
this._options = { ...this.options, ...options };
|
||||
|
||||
this.splitview.layout(
|
||||
this.splitview.size,
|
||||
this.splitview.orthogonalSize
|
||||
|
@ -183,10 +183,6 @@ export class VueWatermarkRenderer
|
||||
);
|
||||
}
|
||||
|
||||
updateParentGroup(group: DockviewGroupPanel, visible: boolean): void {
|
||||
// TODO: make optional on interface
|
||||
}
|
||||
|
||||
update(event: PanelUpdateEvent<Parameters>): void {
|
||||
// noop
|
||||
}
|
||||
|
@ -57,13 +57,6 @@ export class ReactWatermarkPart implements IWatermarkRenderer {
|
||||
// noop - retrieval from api
|
||||
}
|
||||
|
||||
updateParentGroup(
|
||||
_group: DockviewGroupPanel,
|
||||
_isPanelVisible: boolean
|
||||
): void {
|
||||
// noop
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.part?.dispose();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user