You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
223 lines
6.2 KiB
223 lines
6.2 KiB
import { ChangeDetectorRef, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
|
|
|
|
import {
|
|
CdkDrag,
|
|
CdkDragDrop,
|
|
CdkDropList,
|
|
CdkDropListGroup,
|
|
moveItemInArray,
|
|
} from '@angular/cdk/drag-drop';
|
|
|
|
import { CommonModule } from '@angular/common';
|
|
import { WorldArea } from '../models/world-area';
|
|
import { Plan, PlanElement } from '../models/plan';
|
|
import { WorldAreaService } from '../services/world-area.service';
|
|
import { FormsModule } from '@angular/forms';
|
|
import { Fuzzr } from '../fuzzr/fuzzr';
|
|
import { from } from 'rxjs';
|
|
import { save } from '@tauri-apps/api/dialog';
|
|
import { PlanService } from '../services/plan.service';
|
|
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
|
|
import { EditNotesComponentDialog } from './notes/notes.component';
|
|
|
|
interface Act {
|
|
value: number;
|
|
name: string;
|
|
}
|
|
|
|
@Component({
|
|
selector: 'plan-editor',
|
|
templateUrl: './editor.component.html',
|
|
styleUrls: ['./editor.component.scss'],
|
|
standalone: true,
|
|
imports: [
|
|
CommonModule,
|
|
FormsModule,
|
|
CdkDropListGroup,
|
|
CdkDropList,
|
|
CdkDrag,
|
|
MatDialogModule
|
|
],
|
|
})
|
|
export class EditorComponent implements OnInit {
|
|
areas?: WorldArea[];
|
|
planAreas: WorldArea[];
|
|
plan: Plan;
|
|
areasMap?: Map<String, WorldArea>;
|
|
areaSearchString: string = "";
|
|
planSearchString: string = "";
|
|
planFuzzer: Fuzzr;
|
|
filterAct: Act;
|
|
planFilterAct: Act;
|
|
acts: Act[];
|
|
@ViewChild('planList') planListElement!: ElementRef;
|
|
autoScrollToEnd: boolean;
|
|
reverseDisplay: boolean;
|
|
disabledPlanDD: boolean;
|
|
|
|
|
|
constructor(public worldAreaService: WorldAreaService, private cdr: ChangeDetectorRef, private planService: PlanService, public dialog: MatDialog) {
|
|
this.plan = {
|
|
plan: [],
|
|
current: 0,
|
|
}
|
|
this.disabledPlanDD = false;
|
|
|
|
this.autoScrollToEnd = false;
|
|
|
|
this.planFuzzer = new Fuzzr(this.plan.plan, {
|
|
toString: (e: PlanElement) => {
|
|
return this.areasMap?.get(e.area_key)?.name;
|
|
}
|
|
});
|
|
|
|
this.planAreas = [];
|
|
|
|
this.reverseDisplay = false;
|
|
|
|
this.acts = [];
|
|
for (let i = 0; i <= 10; i++) {
|
|
if (i == 0) {
|
|
this.acts.push({ value: i, name: "All" });
|
|
} else {
|
|
this.acts.push({ value: i, name: "Act " + i.toString() });
|
|
}
|
|
}
|
|
|
|
this.filterAct = this.acts[0];
|
|
this.planFilterAct = this.acts[0];
|
|
}
|
|
|
|
ngOnInit(): void {
|
|
this.worldAreaService.getWorldAreas().subscribe(worldAreas => {
|
|
this.areas = [...worldAreas.values()];
|
|
this.areasMap = worldAreas;
|
|
});
|
|
}
|
|
|
|
dropHandler(event: CdkDragDrop<WorldArea[]> | CdkDragDrop<PlanElement[]>) {
|
|
if (event.previousContainer === event.container && !isWorldAreaEvent(event)) {
|
|
const realCurrent = this.plan.plan.indexOf(event.previousContainer.data[event.currentIndex]);
|
|
const realPrev = this.plan.plan.indexOf(event.previousContainer.data[event.previousIndex]);
|
|
moveItemInArray(this.plan.plan, realPrev, realCurrent);
|
|
} else
|
|
if (this.plan && this.areas && isWorldAreaEvent(event)) {
|
|
if (event.container.data.length > 0 && 'connections_world_areas_keys' in event.container.data[0]) {
|
|
return;
|
|
}
|
|
this.plan.plan.splice(event.currentIndex, 0, this.planItemFromArea(event.previousContainer.data[event.previousIndex]));
|
|
}
|
|
}
|
|
|
|
dropEndHandler(event: CdkDragDrop<WorldArea[]> | CdkDragDrop<PlanElement[]>) {
|
|
if (isWorldAreaEvent(event) && this.areas) {
|
|
this.plan.plan.splice(this.plan.plan.length, 0, this.planItemFromArea(event.previousContainer.data[event.previousIndex]));
|
|
this.scrollToEnd();
|
|
} else {
|
|
moveItemInArray(this.plan.plan, event.previousIndex, this.plan.plan.length);
|
|
this.scrollToEnd();
|
|
}
|
|
}
|
|
|
|
canDrop = () => {
|
|
return !this.disabledPlanDD;
|
|
}
|
|
|
|
planItemFromArea(area: WorldArea): PlanElement {
|
|
return {
|
|
area_key: area.named_id,
|
|
notes: undefined,
|
|
};
|
|
}
|
|
|
|
filterAreas() {
|
|
if (this.areaSearchString !== "" || this.filterAct.value != 0) {
|
|
return this.worldAreaService.matcher!.search(this.areaSearchString).map(({ item }) => {
|
|
return item[1];
|
|
}).filter(item => item.act == this.filterAct.value || this.filterAct.value == 0);
|
|
} else {
|
|
return this.areas!;
|
|
}
|
|
}
|
|
|
|
scrollToEnd() {
|
|
if (!this.autoScrollToEnd) {
|
|
return;
|
|
}
|
|
this.cdr.detectChanges();
|
|
if (!this.reverseDisplay) {
|
|
this.planListElement.nativeElement.scrollTop = this.planListElement.nativeElement.scrollHeight;
|
|
} else {
|
|
this.planListElement.nativeElement.scrollTop = 0;
|
|
}
|
|
}
|
|
|
|
doubleClickArea(item: WorldArea) {
|
|
this.plan.plan.splice(this.plan.plan.length, 0, this.planItemFromArea(item));
|
|
this.scrollToEnd();
|
|
}
|
|
|
|
filterPlanElements() {
|
|
const value = (): any[] => {
|
|
if (this.planSearchString !== "" || this.planFilterAct.value != 0) {
|
|
this.disabledPlanDD = true;
|
|
return this.planFuzzer.search(this.planSearchString).map(({ item }) => item).filter(item => {
|
|
return this.areasMap?.get(item.area_key)?.act == this.planFilterAct.value || this.planFilterAct.value == 0;
|
|
});
|
|
} else {
|
|
this.disabledPlanDD = false;
|
|
return this.plan.plan;
|
|
}
|
|
}
|
|
|
|
if (this.reverseDisplay) {
|
|
return value().slice().reverse();
|
|
} else {
|
|
return value();
|
|
}
|
|
}
|
|
|
|
planIndexOf(planElement: PlanElement) {
|
|
const index = this.plan.plan.indexOf(planElement);
|
|
return index;
|
|
}
|
|
|
|
clearPlan() {
|
|
this.plan.plan.length = 0;
|
|
this.cdr.detectChanges();
|
|
}
|
|
|
|
save() {
|
|
from(save({
|
|
filters: [{
|
|
name: 'JSON (.json)',
|
|
extensions: ['json']
|
|
}]
|
|
})).subscribe(file => {
|
|
if (file) {
|
|
this.planService.savePlan(file as string, this.plan);
|
|
}
|
|
});
|
|
}
|
|
|
|
addNote(event: MouseEvent, item: PlanElement) {
|
|
console.log("right click", event, item);
|
|
event.preventDefault();
|
|
|
|
const dialogRef = this.dialog.open(EditNotesComponentDialog, {
|
|
data: {
|
|
note: item.notes
|
|
}
|
|
})
|
|
|
|
dialogRef.afterClosed().subscribe(note => {
|
|
item.notes = note;
|
|
})
|
|
|
|
}
|
|
}
|
|
|
|
|
|
function isWorldAreaEvent(event: any): event is CdkDragDrop<WorldArea[]> {
|
|
return (event.previousContainer.data.length > 0 && 'connections_world_areas_keys' in event.previousContainer.data[0]);
|
|
} |