Added windows
This commit is contained in:
13
package-lock.json
generated
13
package-lock.json
generated
@@ -17,6 +17,7 @@
|
||||
"@angular/platform-browser-dynamic": "^17.3.0",
|
||||
"@angular/router": "^17.3.0",
|
||||
"@fortawesome/angular-fontawesome": "^0.14.1",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.6.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.6.0",
|
||||
"chart.js": "^4.4.3",
|
||||
"papaparse": "^5.4.1",
|
||||
@@ -2720,6 +2721,18 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/free-regular-svg-icons": {
|
||||
"version": "6.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.6.0.tgz",
|
||||
"integrity": "sha512-Yv9hDzL4aI73BEwSEh20clrY8q/uLxawaQ98lekBx6t9dQKDHcDzzV1p2YtBGTtolYtNqcWdniOnhzB+JPnQEQ==",
|
||||
"license": "(CC-BY-4.0 AND MIT)",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "6.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/free-solid-svg-icons": {
|
||||
"version": "6.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.6.0.tgz",
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
"@angular/platform-browser-dynamic": "^17.3.0",
|
||||
"@angular/router": "^17.3.0",
|
||||
"@fortawesome/angular-fontawesome": "^0.14.1",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.6.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.6.0",
|
||||
"chart.js": "^4.4.3",
|
||||
"papaparse": "^5.4.1",
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
<div class="header">Fields!</div>
|
||||
<div class="header">Fields</div>
|
||||
<fbi-tree
|
||||
class="tree"
|
||||
[node]="node"
|
||||
(actionClick)="onActionClick($event)"
|
||||
></fbi-tree>
|
||||
|
||||
<fbi-window #filter [config]="windowConfig"
|
||||
>content content content content content content content content content
|
||||
content content content content content content content content content
|
||||
</fbi-window>
|
||||
|
||||
@@ -1,22 +1,30 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, ViewChild } from '@angular/core';
|
||||
import { TreeComponent } from '../tree/tree.component';
|
||||
import { TreeNode } from '../../models/tree-node';
|
||||
import { MetaService } from '../../services/meta.service';
|
||||
import { Action } from '../../models/action';
|
||||
import { faAdd } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faAdd, faFilter } from '@fortawesome/free-solid-svg-icons';
|
||||
import { QueryService } from '../../services/query.service';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import { Query } from '../../models/query';
|
||||
import { WindowComponent } from '../window/window.component';
|
||||
|
||||
@Component({
|
||||
selector: 'fbi-metadata',
|
||||
standalone: true,
|
||||
imports: [TreeComponent],
|
||||
imports: [TreeComponent, WindowComponent],
|
||||
templateUrl: './metadata.component.html',
|
||||
styleUrl: './metadata.component.scss',
|
||||
})
|
||||
export class MetadataComponent {
|
||||
node: TreeNode = new TreeNode({});
|
||||
@ViewChild(WindowComponent) window!: WindowComponent;
|
||||
|
||||
windowComponent = WindowComponent;
|
||||
|
||||
windowConfig = {
|
||||
title: 'test',
|
||||
};
|
||||
|
||||
constructor(metaService: MetaService, private queryService: QueryService) {
|
||||
combineLatest({
|
||||
@@ -33,7 +41,10 @@ export class MetadataComponent {
|
||||
const children = node.children ?? [];
|
||||
children.forEach((child: Partial<TreeNode>) => recurse(child));
|
||||
if (children.length === 0) {
|
||||
const actions = [{ label: 'Add', icon: faAdd, data: ACTIONS.ADD }];
|
||||
const actions = [
|
||||
{ label: 'Filter', icon: faFilter, data: ACTIONS.FILTER },
|
||||
{ label: 'Add', icon: faAdd, data: ACTIONS.ADD },
|
||||
];
|
||||
node.actions = actions as Action[];
|
||||
}
|
||||
};
|
||||
@@ -53,6 +64,9 @@ export class MetadataComponent {
|
||||
case ACTIONS.ADD:
|
||||
this.queryService.add(event.node.data);
|
||||
break;
|
||||
case ACTIONS.FILTER:
|
||||
this.window.show();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,4 +86,5 @@ export class MetadataComponent {
|
||||
|
||||
enum ACTIONS {
|
||||
ADD = 'add',
|
||||
FILTER = 'filter',
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="header">Query!</div>
|
||||
<div class="header">Query</div>
|
||||
<fbi-tree
|
||||
class="tree"
|
||||
[node]="node"
|
||||
|
||||
@@ -50,12 +50,14 @@ export class QueryComponent {
|
||||
label: 'Filters',
|
||||
expanded: true,
|
||||
leaf: false,
|
||||
hidden: filters.length === 0,
|
||||
children: filters,
|
||||
},
|
||||
{
|
||||
label: 'Sort',
|
||||
expanded: true,
|
||||
leaf: false,
|
||||
hidden: sort.length === 0,
|
||||
children: sort,
|
||||
},
|
||||
] as TreeNode[],
|
||||
|
||||
@@ -46,11 +46,37 @@
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td [attr.colspan]="data.headers.length + 1">
|
||||
<span>
|
||||
Showing {{ (data.page.page - 1) * data.page.size + 1 }} to
|
||||
{{ data.page.page * data.page.size }} of {{ data.total }}
|
||||
<div class="left">
|
||||
@for (btn of pagesize; track btn) {
|
||||
<input
|
||||
role="button"
|
||||
type="submit"
|
||||
(click)="onPageSize($event, btn.page)"
|
||||
[class.clickable]="!btn.current"
|
||||
[class.current]="btn.current"
|
||||
[attr.value]="btn.page"
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
<span class="center">
|
||||
{{ (data.page.page - 1) * data.page.size + 1 }}-{{
|
||||
Math.min(data.page.page * data.page.size, data.total)
|
||||
}}
|
||||
of {{ data.total }}
|
||||
</span>
|
||||
<span> </span>
|
||||
<div class="right">
|
||||
@for (btn of pager; track page) { @if (btn.ellipsis) {
|
||||
<span>...</span>
|
||||
} @else {
|
||||
<input
|
||||
role="button"
|
||||
type="submit"
|
||||
(click)="onPage($event, btn.page)"
|
||||
[class.clickable]="!btn.current"
|
||||
[class.current]="btn.current"
|
||||
[attr.value]="btn.page"
|
||||
/>} }
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
min-width: 400px;
|
||||
}
|
||||
|
||||
thead {
|
||||
@@ -56,6 +57,27 @@ tfoot {
|
||||
color: #777;
|
||||
}
|
||||
|
||||
div.left {
|
||||
float: left;
|
||||
}
|
||||
|
||||
div.right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input {
|
||||
border: 1px solid #ddd;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
input:hover {
|
||||
background-color: #eff;
|
||||
}
|
||||
|
||||
input.current {
|
||||
background-color: #95b9c7;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnChanges,
|
||||
Output,
|
||||
SimpleChanges,
|
||||
} from '@angular/core';
|
||||
import { Header } from '../../models/header';
|
||||
import {
|
||||
faSort,
|
||||
@@ -18,24 +25,108 @@ import { Page } from '../../models/page';
|
||||
templateUrl: './table.component.html',
|
||||
styleUrl: './table.component.scss',
|
||||
})
|
||||
export class TableComponent {
|
||||
export class TableComponent implements OnChanges {
|
||||
@Input() data!: Result;
|
||||
|
||||
@Output() page = new EventEmitter<Page>();
|
||||
@Output() sort = new EventEmitter<Header>();
|
||||
|
||||
Math = Math;
|
||||
faSortDown = faSortDown;
|
||||
faSortUp = faSortUp;
|
||||
faSort = faSort;
|
||||
SORT = SORT;
|
||||
pagesize: PageButton[] = [];
|
||||
pager: PageButton[] = [];
|
||||
|
||||
onPage(event: MouseEvent): void {
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
const data = changes['data']?.currentValue;
|
||||
if (data) {
|
||||
this.updatePageSize(data);
|
||||
this.updatePager(data);
|
||||
}
|
||||
}
|
||||
|
||||
onPage(event: MouseEvent, page: number): void {
|
||||
event.stopPropagation();
|
||||
this.page.emit();
|
||||
const current = this.data?.page?.page;
|
||||
const size = this.data?.page?.size;
|
||||
if (current === page) return;
|
||||
this.page.emit(new Page({ page: page, size: size }));
|
||||
}
|
||||
|
||||
onPageSize(event: MouseEvent, size: number): void {
|
||||
event.stopPropagation();
|
||||
const current = this.data?.page?.size;
|
||||
if (current === size) return;
|
||||
|
||||
const page = this.data?.page ?? { page: 1, size: 100 };
|
||||
const start = (page.page - 1) * page.size + 1;
|
||||
const newPage = Math.ceil(start / size);
|
||||
this.page.emit(new Page({ page: newPage, size: size }));
|
||||
}
|
||||
|
||||
onSort(event: MouseEvent, header: Header): void {
|
||||
event.stopPropagation();
|
||||
this.sort.emit(header);
|
||||
}
|
||||
|
||||
private updatePageSize(data: Result): void {
|
||||
const size = data.page?.size ?? 20;
|
||||
const sizes = [10, 20, 50].map(
|
||||
(i) => new PageButton({ page: i, current: i === size })
|
||||
);
|
||||
|
||||
this.pagesize = sizes;
|
||||
}
|
||||
|
||||
private updatePager(data: Result): void {
|
||||
const page = data.page?.page ?? 1;
|
||||
const last = Math.ceil(data.total / (data.page?.size ?? data.total));
|
||||
|
||||
// get the list of pages
|
||||
const pages = [
|
||||
1,
|
||||
page + 1 > last ? page - 2 : 1,
|
||||
page - 1,
|
||||
page,
|
||||
page + 1,
|
||||
page < 3 ? 3 : last,
|
||||
last,
|
||||
]
|
||||
// unique
|
||||
.filter((v, i, a) => a.indexOf(v) === i)
|
||||
// in range
|
||||
.filter((i) => 1 <= i && i <= last);
|
||||
|
||||
const buttons = pages.map(
|
||||
(i) =>
|
||||
new PageButton({
|
||||
page: i,
|
||||
current: i === page,
|
||||
})
|
||||
);
|
||||
if (buttons.length > 2) {
|
||||
if (buttons[0].page !== buttons[1].page - 1) {
|
||||
buttons.splice(1, 0, new PageButton({ ellipsis: true }));
|
||||
}
|
||||
const length = buttons.length;
|
||||
if (buttons[length - 2].page !== buttons[length - 1].page - 1) {
|
||||
buttons.splice(length - 1, 0, new PageButton({ ellipsis: true }));
|
||||
}
|
||||
}
|
||||
this.pager = buttons;
|
||||
}
|
||||
}
|
||||
|
||||
export class PageButton {
|
||||
page: number;
|
||||
current: boolean;
|
||||
ellipsis: boolean;
|
||||
|
||||
constructor(data: Partial<PageButton>) {
|
||||
this.page = data?.page ?? -1;
|
||||
this.current = data?.current ?? false;
|
||||
this.ellipsis = data?.ellipsis ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +1,29 @@
|
||||
@if (!node.hidden) {
|
||||
<div
|
||||
*ngIf="!node?.hidden"
|
||||
class="treenode"
|
||||
[class.disabled]="node.disabled"
|
||||
[class.clickable]="!node.leaf"
|
||||
(click)="toggle($event)"
|
||||
>
|
||||
<span *ngIf="!node.leaf" class="icon">
|
||||
<fa-icon *ngIf="node.expanded" [icon]="faCaretDown"></fa-icon>
|
||||
<fa-icon *ngIf="!node.expanded" [icon]="faCaretRight"></fa-icon>
|
||||
@if (!node.leaf) {
|
||||
<span class="icon">
|
||||
<fa-icon [icon]="node.expanded ? faCaretDown : faCaretRight"></fa-icon>
|
||||
</span>
|
||||
}
|
||||
<span [title]="node.label" class="fill ellipsis">{{ node.label }}</span>
|
||||
<ng-container *ngIf="node.leaf && !node.disabled" class="actions">
|
||||
@if (node.leaf && !node.disabled) { @for (action of node.actions; track
|
||||
action) {
|
||||
<fa-icon
|
||||
*ngFor="let action of node.actions"
|
||||
class="action clickable"
|
||||
[icon]="action.icon"
|
||||
(click)="onActionClick($event, action)"
|
||||
></fa-icon>
|
||||
</ng-container>
|
||||
} }
|
||||
</div>
|
||||
|
||||
<div
|
||||
*ngIf="node && node.children && node.expanded"
|
||||
[class.branch]="node.label !== ''"
|
||||
>
|
||||
<fbi-tree
|
||||
*ngFor="let child of node.children"
|
||||
[node]="child"
|
||||
(actionClick)="passActionClick($event)"
|
||||
></fbi-tree>
|
||||
} @if (node && node.children && node.expanded) {
|
||||
<div [class.branch]="node.label !== ''">
|
||||
@for (child of node.children; track child) {
|
||||
<fbi-tree [node]="child" (actionClick)="passActionClick($event)"></fbi-tree>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
11
src/components/window/window-config.ts
Normal file
11
src/components/window/window-config.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export interface WindowConfig {
|
||||
height?: number;
|
||||
width?: number;
|
||||
x?: number;
|
||||
y?: number;
|
||||
|
||||
resizable?: boolean;
|
||||
closable?: boolean;
|
||||
|
||||
title?: string;
|
||||
}
|
||||
36
src/components/window/window.component.html
Normal file
36
src/components/window/window.component.html
Normal file
@@ -0,0 +1,36 @@
|
||||
<div
|
||||
class="resize vertical left"
|
||||
[class.grab]="resizing"
|
||||
(mousedown)="startResize($event, Resize.Left)"
|
||||
></div>
|
||||
<div class="wrap">
|
||||
<div
|
||||
class="resize horizontal top"
|
||||
[class.grab]="resizing"
|
||||
(mousedown)="startResize($event, Resize.Top)"
|
||||
></div>
|
||||
<div class="header" [class.grab]="dragging" (mousedown)="startDrag($event)">
|
||||
@if (config.title) {
|
||||
<span class="title ellipsis">{{ config.title }}</span>
|
||||
} @if (config.closable ?? true) {
|
||||
<fa-icon
|
||||
[icon]="faRectangleXmark"
|
||||
class="icon clickable"
|
||||
(click)="onClose($event)"
|
||||
></fa-icon>
|
||||
}
|
||||
</div>
|
||||
<div class="content">
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
<div
|
||||
class="resize horizontal bottom"
|
||||
[class.grab]="resizing"
|
||||
(mousedown)="startResize($event, Resize.Bottom)"
|
||||
></div>
|
||||
</div>
|
||||
<div
|
||||
class="resize vertical right"
|
||||
[class.grab]="resizing"
|
||||
(mousedown)="startResize($event, Resize.Right)"
|
||||
></div>
|
||||
93
src/components/window/window.component.scss
Normal file
93
src/components/window/window.component.scss
Normal file
@@ -0,0 +1,93 @@
|
||||
:host {
|
||||
position: absolute;
|
||||
// border: 1px solid black;
|
||||
background-color: transparent;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.header {
|
||||
background-color: lightgray;
|
||||
border-bottom: 1px solid black;
|
||||
padding: 2px 4px 0px 5px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.resize {
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
.horizontal {
|
||||
height: 0px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.vertical {
|
||||
height: 100%;
|
||||
width: 0px;
|
||||
}
|
||||
|
||||
.top {
|
||||
cursor: ns-resize;
|
||||
// margin-top: 2px;
|
||||
border-top: 1px solid black;
|
||||
background-color: lightgray;
|
||||
}
|
||||
|
||||
.bottom {
|
||||
cursor: ns-resize;
|
||||
// margin-bottom: 2px;
|
||||
border-bottom: 1px solid black;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.left {
|
||||
cursor: ew-resize;
|
||||
// margin-left: 2px;
|
||||
border-left: 1px solid black;
|
||||
}
|
||||
|
||||
.right {
|
||||
cursor: ew-resize;
|
||||
// margin-right: 2px;
|
||||
border-right: 1px solid black;
|
||||
}
|
||||
|
||||
.grab {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.content {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 2px;
|
||||
background-color: white;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icon {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.title {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.ellipsis {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
23
src/components/window/window.component.spec.ts
Normal file
23
src/components/window/window.component.spec.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { WindowComponent } from './window.component';
|
||||
|
||||
describe('WindowComponent', () => {
|
||||
let component: WindowComponent;
|
||||
let fixture: ComponentFixture<WindowComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [WindowComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(WindowComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
140
src/components/window/window.component.ts
Normal file
140
src/components/window/window.component.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
import {
|
||||
Component,
|
||||
EventEmitter,
|
||||
HostBinding,
|
||||
Inject,
|
||||
Input,
|
||||
Output,
|
||||
} from '@angular/core';
|
||||
import { CommonModule, DOCUMENT } from '@angular/common';
|
||||
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
||||
import { faRectangleXmark } from '@fortawesome/free-regular-svg-icons';
|
||||
import { WindowConfig } from './window-config';
|
||||
|
||||
export enum Resize {
|
||||
Top = 't',
|
||||
Right = 'r',
|
||||
Bottom = 'b',
|
||||
Left = 'l',
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'fbi-window',
|
||||
standalone: true,
|
||||
imports: [CommonModule, FontAwesomeModule],
|
||||
templateUrl: './window.component.html',
|
||||
styleUrls: ['./window.component.scss'],
|
||||
})
|
||||
export class WindowComponent {
|
||||
@HostBinding('style.height.px') height: number = 200;
|
||||
@HostBinding('style.width.px') width: number = 400;
|
||||
@HostBinding('style.left.px') x: number = 200;
|
||||
@HostBinding('style.top.px') y: number = 200;
|
||||
@HostBinding('style.visibility') visibility: string = 'hidden';
|
||||
private _display: boolean = false;
|
||||
private get visible() {
|
||||
return this._display;
|
||||
}
|
||||
private set visible(value: boolean) {
|
||||
this._display = value;
|
||||
this.visibility = value ? 'visible' : 'hidden';
|
||||
}
|
||||
|
||||
@Input() config!: WindowConfig;
|
||||
@Output() closing = new EventEmitter<void>();
|
||||
|
||||
dragging: boolean = false;
|
||||
resizing: boolean = false;
|
||||
|
||||
faRectangleXmark = faRectangleXmark;
|
||||
Resize = Resize;
|
||||
|
||||
constructor(@Inject(DOCUMENT) private _document: Document) {
|
||||
this.visible = true;
|
||||
}
|
||||
|
||||
toggle = (display?: boolean) => (this.visible = display ?? !this.visible);
|
||||
hide = () => this.toggle(false);
|
||||
show = () => this.toggle(true);
|
||||
|
||||
startDrag(event: MouseEvent): void {
|
||||
event.preventDefault();
|
||||
const { innerHeight, innerWidth } = window;
|
||||
const { clientX, clientY } = event;
|
||||
const x = this.x;
|
||||
const y = this.y;
|
||||
const h = this.height;
|
||||
const w = this.width;
|
||||
const doc = this._document;
|
||||
|
||||
this.dragging = true;
|
||||
const dragging = (e: MouseEvent) => {
|
||||
this.x = Math.min(Math.max(x + e.clientX - clientX, 0), innerWidth - w);
|
||||
this.y = Math.min(Math.max(y + e.clientY - clientY, 0), innerHeight - h);
|
||||
};
|
||||
|
||||
const dragEnd = (e: MouseEvent) => {
|
||||
this.dragging = false;
|
||||
doc.removeEventListener('mousemove', dragging);
|
||||
doc.removeEventListener('mouseup', dragEnd);
|
||||
};
|
||||
|
||||
doc.addEventListener('mousemove', dragging);
|
||||
doc.addEventListener('mouseup', dragEnd);
|
||||
}
|
||||
|
||||
startResize(event: MouseEvent, anchor: Resize): void {
|
||||
event.preventDefault();
|
||||
const { innerHeight, innerWidth } = window;
|
||||
const { clientX, clientY } = event;
|
||||
const x = this.x;
|
||||
const y = this.y;
|
||||
const h = this.height;
|
||||
const w = this.width;
|
||||
const doc = this._document;
|
||||
const minH = 32;
|
||||
const minW = 100;
|
||||
|
||||
this.resizing = true;
|
||||
const resizing = (e: MouseEvent) => {
|
||||
const dx = e.clientX - clientX;
|
||||
const dy = e.clientY - clientY;
|
||||
|
||||
switch (anchor) {
|
||||
case Resize.Top:
|
||||
this.y = Math.min(Math.max(y + dy, 0), y + h - minH);
|
||||
if (this.y > 0)
|
||||
this.height = Math.min(
|
||||
Math.max(h - dy, minH),
|
||||
innerHeight - this.y
|
||||
);
|
||||
break;
|
||||
case Resize.Bottom:
|
||||
this.height = Math.min(Math.max(h + dy, minH), innerHeight - this.y);
|
||||
break;
|
||||
case Resize.Left:
|
||||
this.x = Math.min(Math.max(x + dx, 0), x + w - minW);
|
||||
if (this.x > 0)
|
||||
this.width = Math.min(Math.max(w - dx, minW), innerWidth - this.x);
|
||||
break;
|
||||
case Resize.Right:
|
||||
this.width = Math.min(Math.max(w + dx, minW), innerWidth - this.x);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const resizeEnd = (e: MouseEvent) => {
|
||||
this.resizing = false;
|
||||
doc.removeEventListener('mousemove', resizing);
|
||||
doc.removeEventListener('mouseup', resizeEnd);
|
||||
};
|
||||
doc.addEventListener('mousemove', resizing);
|
||||
doc.addEventListener('mouseup', resizeEnd);
|
||||
}
|
||||
|
||||
onClose(event: MouseEvent): void {
|
||||
event.preventDefault();
|
||||
this.hide();
|
||||
this.closing.emit();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user