WIP
This commit is contained in:
parent
b8b35645ac
commit
46ec236ed5
@ -43,10 +43,12 @@ import { GridModule } from '@progress/kendo-angular-grid';
|
|||||||
import { DialogModule } from '@progress/kendo-angular-dialog';
|
import { DialogModule } from '@progress/kendo-angular-dialog';
|
||||||
import { InputsModule } from '@progress/kendo-angular-inputs';
|
import { InputsModule } from '@progress/kendo-angular-inputs';
|
||||||
import { DropDownsModule } from '@progress/kendo-angular-dropdowns';
|
import { DropDownsModule } from '@progress/kendo-angular-dropdowns';
|
||||||
|
import { LayoutModule } from '@progress/kendo-angular-layout';
|
||||||
import { ReactiveFormsModule } from '@angular/forms';
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
import { MD2MobInfoMaintenanceComponent } from './massive-darkness2/md2-mob-info-maintenance/md2-mob-info-maintenance.component';
|
import { MD2MobInfoMaintenanceComponent } from './massive-darkness2/md2-mob-info-maintenance/md2-mob-info-maintenance.component';
|
||||||
import { MD2MobInfoEditorComponent } from './massive-darkness2/md2-mob-info-maintenance/md2-mob-info-editor/md2-mob-info-editor.component';
|
import { MD2MobInfoEditorComponent } from './massive-darkness2/md2-mob-info-maintenance/md2-mob-info-editor/md2-mob-info-editor.component';
|
||||||
import { MD2MobInfoDetailComponent } from './massive-darkness2/md2-mob-info-maintenance/md2-mob-info-detail/md2-mob-info-detail.component';
|
import { MD2MobInfoDetailComponent } from './massive-darkness2/md2-mob-info-maintenance/md2-mob-info-detail/md2-mob-info-detail.component';
|
||||||
|
import { MD2MobSkillEditorComponent } from './massive-darkness2/md2-mob-info-maintenance/md2-mob-skill-editor/md2-mob-skill-editor.component';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@ -79,7 +81,8 @@ import { MD2MobInfoDetailComponent } from './massive-darkness2/md2-mob-info-main
|
|||||||
MD2IconPickerDlgComponent,
|
MD2IconPickerDlgComponent,
|
||||||
MD2MobInfoMaintenanceComponent,
|
MD2MobInfoMaintenanceComponent,
|
||||||
MD2MobInfoEditorComponent,
|
MD2MobInfoEditorComponent,
|
||||||
MD2MobInfoDetailComponent
|
MD2MobInfoDetailComponent,
|
||||||
|
MD2MobSkillEditorComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
@ -119,7 +122,8 @@ import { MD2MobInfoDetailComponent } from './massive-darkness2/md2-mob-info-main
|
|||||||
GridModule,
|
GridModule,
|
||||||
DialogModule,
|
DialogModule,
|
||||||
InputsModule,
|
InputsModule,
|
||||||
DropDownsModule
|
DropDownsModule,
|
||||||
|
LayoutModule
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class GamesModule { }
|
export class GamesModule { }
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<kendo-editor [value]="value" (valueChange)="onChange($event)" (blur)="onTouched()" [disabled]="disabled"
|
<kendo-editor [value]="value" (valueChange)="onChange($event)" (blur)="onTouched()" [disabled]="disabled"
|
||||||
[schema]="messageTemplateSchema" [iframe]="false">
|
[schema]="messageTemplateSchema" [iframe]="false" class="h-100">
|
||||||
<kendo-toolbar>
|
<kendo-toolbar>
|
||||||
<!-- Standard editing tools -->
|
<!-- Standard editing tools -->
|
||||||
<kendo-toolbar-buttongroup>
|
<kendo-toolbar-buttongroup>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Component, ElementRef, EventEmitter, Inject, Input, NgZone, Output, PLATFORM_ID, Renderer2, ViewChild, AfterViewInit } from '@angular/core';
|
import { Component, ElementRef, EventEmitter, Inject, Input, NgZone, Output, PLATFORM_ID, Renderer2, ViewChild, AfterViewInit, forwardRef, ChangeDetectorRef } from '@angular/core';
|
||||||
import { ControlValueAccessor, Validator, AbstractControl, ValidationErrors } from '@angular/forms';
|
import { ControlValueAccessor, Validator, AbstractControl, ValidationErrors, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||||
import { EditorComponent, NodeSpec, schema, Schema, FontSizeItem } from '@progress/kendo-angular-editor';
|
import { EditorComponent, NodeSpec, schema, Schema, FontSizeItem } from '@progress/kendo-angular-editor';
|
||||||
|
|
||||||
import { MsgBoxService } from '../../../services/msg-box.service';
|
import { MsgBoxService } from '../../../services/msg-box.service';
|
||||||
@ -10,10 +10,18 @@ import { MD2StateService } from '../../../services/MD2/md2-state.service';
|
|||||||
import { MD2IconPickerDlgComponent } from './md2-icon-picker-dlg.component';
|
import { MD2IconPickerDlgComponent } from './md2-icon-picker-dlg.component';
|
||||||
import { NbDialogService } from '@nebular/theme';
|
import { NbDialogService } from '@nebular/theme';
|
||||||
import { DOMParser as ProseMirrorDOMParser } from 'prosemirror-model';
|
import { DOMParser as ProseMirrorDOMParser } from 'prosemirror-model';
|
||||||
|
import { DialogService } from '@progress/kendo-angular-dialog';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'md2-html-editor',
|
selector: 'md2-html-editor',
|
||||||
templateUrl: './md2-html-editor.component.html',
|
templateUrl: './md2-html-editor.component.html',
|
||||||
styleUrl: './md2-html-editor.component.scss'
|
styleUrl: './md2-html-editor.component.scss',
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: NG_VALUE_ACCESSOR,
|
||||||
|
useExisting: forwardRef(() => MD2HtmlEditorComponent),
|
||||||
|
multi: true
|
||||||
|
}
|
||||||
|
]
|
||||||
})
|
})
|
||||||
export class MD2HtmlEditorComponent implements ControlValueAccessor, AfterViewInit {
|
export class MD2HtmlEditorComponent implements ControlValueAccessor, AfterViewInit {
|
||||||
@ViewChild(EditorComponent) editor: EditorComponent;
|
@ViewChild(EditorComponent) editor: EditorComponent;
|
||||||
@ -52,7 +60,8 @@ export class MD2HtmlEditorComponent implements ControlValueAccessor, AfterViewIn
|
|||||||
constructor(
|
constructor(
|
||||||
private msgBoxService: MsgBoxService,
|
private msgBoxService: MsgBoxService,
|
||||||
private md2StateService: MD2StateService,
|
private md2StateService: MD2StateService,
|
||||||
private dialogService: NbDialogService,
|
private dialogService: DialogService,
|
||||||
|
private cdr: ChangeDetectorRef,
|
||||||
elementRef: ElementRef, ngZone: NgZone, @Inject(PLATFORM_ID) platformId: Object) {
|
elementRef: ElementRef, ngZone: NgZone, @Inject(PLATFORM_ID) platformId: Object) {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -71,12 +80,38 @@ export class MD2HtmlEditorComponent implements ControlValueAccessor, AfterViewIn
|
|||||||
this.fontSizeDropdown.defaultItem = this.defaultFontSize;
|
this.fontSizeDropdown.defaultItem = this.defaultFontSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure the editor value is set if writeValue was called before view init
|
||||||
|
if (this.editor && this.value && this.editor.value !== this.value) {
|
||||||
|
this.editor.value = this.value;
|
||||||
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ControlValueAccessor implementation
|
// ControlValueAccessor implementation
|
||||||
writeValue(value: string): void {
|
writeValue(value: string | null | undefined): void {
|
||||||
this.value = value || '';
|
const newValue = value || '';
|
||||||
|
|
||||||
|
// Only update if the value actually changed to avoid unnecessary updates
|
||||||
|
if (this.value !== newValue) {
|
||||||
|
this.value = newValue;
|
||||||
|
|
||||||
|
// Angular's [value] binding will handle updating the editor
|
||||||
|
// But if editor is already initialized and value is out of sync, ensure sync
|
||||||
|
if (this.editor && this.editor.value !== this.value) {
|
||||||
|
// Use setTimeout to avoid ExpressionChangedAfterItHasBeenCheckedError
|
||||||
|
setTimeout(() => {
|
||||||
|
if (this.editor && this.editor.value !== this.value) {
|
||||||
|
this.editor.value = this.value;
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger change detection to ensure the binding updates
|
||||||
|
if (!this.cdr['destroyed']) {
|
||||||
|
this.cdr.markForCheck();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
registerOnChange(fn: (value: string) => void): void {
|
registerOnChange(fn: (value: string) => void): void {
|
||||||
@ -92,8 +127,11 @@ export class MD2HtmlEditorComponent implements ControlValueAccessor, AfterViewIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
onChange(value: string): void {
|
onChange(value: string): void {
|
||||||
this.value = value;
|
// Only update if value actually changed to prevent infinite loops
|
||||||
this.onChangeFn(value);
|
if (this.value !== value) {
|
||||||
|
this.value = value || '';
|
||||||
|
this.onChangeFn(this.value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onTouched(): void {
|
onTouched(): void {
|
||||||
@ -101,10 +139,12 @@ export class MD2HtmlEditorComponent implements ControlValueAccessor, AfterViewIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
showInsertMD2Icon() {
|
showInsertMD2Icon() {
|
||||||
this.dialogService.open(MD2IconPickerDlgComponent, {
|
this.dialogService.open({
|
||||||
closeOnBackdropClick: true,
|
title: 'Insert MD2 Icon',
|
||||||
closeOnEsc: true
|
content: MD2IconPickerDlgComponent,
|
||||||
}).onClose.pipe(first()).subscribe((html: string) => {
|
width: '800px',
|
||||||
|
height: 600
|
||||||
|
}).result.subscribe((html: string) => {
|
||||||
if (html && this.editor) {
|
if (html && this.editor) {
|
||||||
this.insertAfterSelection(html, true);
|
this.insertAfterSelection(html, true);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -2,16 +2,11 @@ import { Component, OnInit } from '@angular/core';
|
|||||||
import { NbDialogRef } from '@nebular/theme';
|
import { NbDialogRef } from '@nebular/theme';
|
||||||
import { MD2Icon } from '../massive-darkness2.model';
|
import { MD2Icon } from '../massive-darkness2.model';
|
||||||
import { MD2StateService } from '../../../services/MD2/md2-state.service';
|
import { MD2StateService } from '../../../services/MD2/md2-state.service';
|
||||||
|
import { DialogRef } from '@progress/kendo-angular-dialog';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'md2-icon-picker-dlg',
|
selector: 'md2-icon-picker-dlg',
|
||||||
template: `
|
template: ` <div class="md2-icon-grid">
|
||||||
<nb-card style="max-width: 800px;">
|
|
||||||
<nb-card-header>
|
|
||||||
<h5>Insert MD2 Icon</h5>
|
|
||||||
</nb-card-header>
|
|
||||||
<nb-card-body>
|
|
||||||
<div class="md2-icon-grid">
|
|
||||||
<div
|
<div
|
||||||
*ngFor="let iconData of iconList"
|
*ngFor="let iconData of iconList"
|
||||||
(click)="selectIcon(iconData)"
|
(click)="selectIcon(iconData)"
|
||||||
@ -19,13 +14,23 @@ import { MD2StateService } from '../../../services/MD2/md2-state.service';
|
|||||||
[innerHTML]="iconData.html">
|
[innerHTML]="iconData.html">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- <nb-card>
|
||||||
|
<nb-card-header>
|
||||||
|
<h5>Insert MD2 Icon</h5>
|
||||||
|
</nb-card-header>
|
||||||
|
<nb-card-body>
|
||||||
|
|
||||||
</nb-card-body>
|
</nb-card-body>
|
||||||
<nb-card-footer>
|
<nb-card-footer>
|
||||||
<button nbButton status="primary" (click)="cancel()">Cancel</button>
|
<button nbButton status="primary" (click)="cancel()">Cancel</button>
|
||||||
</nb-card-footer>
|
</nb-card-footer>
|
||||||
</nb-card>
|
</nb-card> -->
|
||||||
`,
|
`,
|
||||||
styles: [`
|
styles: [`
|
||||||
|
nb-card{
|
||||||
|
max-width: 800px;
|
||||||
|
z-index: 1050;
|
||||||
|
}
|
||||||
.md2-icon-grid {
|
.md2-icon-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(60px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(60px, 1fr));
|
||||||
@ -57,7 +62,7 @@ export class MD2IconPickerDlgComponent implements OnInit {
|
|||||||
iconList: Array<{ icon: MD2Icon, name: string, html: string }> = [];
|
iconList: Array<{ icon: MD2Icon, name: string, html: string }> = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private dlgRef: NbDialogRef<MD2IconPickerDlgComponent>,
|
private dlgRef: DialogRef,
|
||||||
private md2StateService: MD2StateService
|
private md2StateService: MD2StateService
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
<span class="MD2Icon {{iconName}} {{iconClass}} {{sizeClass}}"></span>
|
<span [innerHtml]="iconHtml" class="g-font-size-20 g-line-height-0 mx-2"></span>
|
||||||
@ -1,5 +1,6 @@
|
|||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
import { MD2Icon } from '../massive-darkness2.model';
|
import { MD2Icon } from '../massive-darkness2.model';
|
||||||
|
import { MD2StateService } from '../../../services/MD2/md2-state.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'md2-icon',
|
selector: 'md2-icon',
|
||||||
@ -10,13 +11,17 @@ export class MD2IconComponent implements OnInit {
|
|||||||
|
|
||||||
@Input() iconClass: string = 'mr-1';
|
@Input() iconClass: string = 'mr-1';
|
||||||
|
|
||||||
|
iconHtml: string;
|
||||||
private _icon: string | MD2Icon;
|
private _icon: string | MD2Icon;
|
||||||
|
|
||||||
@Input() public set icon(v: string | MD2Icon) {
|
@Input() public set icon(v: string | MD2Icon) {
|
||||||
if (this._icon != v) {
|
if (this._icon != v) {
|
||||||
this._icon = v;
|
this._icon = v;
|
||||||
|
//if it's string, convert it to MD2Icon
|
||||||
|
if (typeof v === 'string') {
|
||||||
|
v = MD2Icon[v];
|
||||||
|
}
|
||||||
|
this.iconHtml = this.md2StateService.iconHtml(v as MD2Icon);
|
||||||
}
|
}
|
||||||
if (this.isMD2Icon(v)) {
|
if (this.isMD2Icon(v)) {
|
||||||
this.iconName = MD2Icon[v].toLowerCase();
|
this.iconName = MD2Icon[v].toLowerCase();
|
||||||
@ -30,7 +35,7 @@ export class MD2IconComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
@Input() size: string = 'sm';
|
@Input() size: string = 'sm';
|
||||||
iconName: string;
|
iconName: string;
|
||||||
constructor() { }
|
constructor(private md2StateService: MD2StateService) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
}
|
}
|
||||||
|
|||||||
@ -158,12 +158,11 @@
|
|||||||
|
|
||||||
<kendo-grid #skillsGrid [data]="skillsData" [loading]="isLoading" [pageSize]="skillsState.take"
|
<kendo-grid #skillsGrid [data]="skillsData" [loading]="isLoading" [pageSize]="skillsState.take"
|
||||||
[skip]="skillsState.skip" [sortable]="true" [filterable]="true" [pageable]="true" [height]="400"
|
[skip]="skillsState.skip" [sortable]="true" [filterable]="true" [pageable]="true" [height]="400"
|
||||||
kendoGridTemplateEditing (save)="saveSkillHandler($event)" (remove)="removeSkillHandler($event)"
|
(remove)="removeSkillHandler($event)" (dataStateChange)="skillsState = $event">
|
||||||
(dataStateChange)="skillsState = $event">
|
|
||||||
|
|
||||||
<kendo-grid-column field="name" title="Name" [width]="150">
|
<kendo-grid-column field="name" title="Name" [width]="150">
|
||||||
<ng-template kendoGridEditTemplate let-dataItem="dataItem">
|
<ng-template kendoGridCellTemplate let-dataItem>
|
||||||
<input kendoTextBox [(ngModel)]="dataItem.name" name="name" placeholder="Enter skill name" />
|
{{ dataItem.name }}
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</kendo-grid-column>
|
</kendo-grid-column>
|
||||||
|
|
||||||
@ -171,55 +170,37 @@
|
|||||||
<ng-template kendoGridCellTemplate let-dataItem>
|
<ng-template kendoGridCellTemplate let-dataItem>
|
||||||
{{ getSkillTypeName(dataItem.type) }}
|
{{ getSkillTypeName(dataItem.type) }}
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template kendoGridEditTemplate let-dataItem="dataItem">
|
|
||||||
<kendo-dropdownlist [(ngModel)]="dataItem.type" name="type" [data]="skillTypes" [valueField]="'value'"
|
|
||||||
[textField]="'text'">
|
|
||||||
</kendo-dropdownlist>
|
|
||||||
</ng-template>
|
|
||||||
</kendo-grid-column>
|
</kendo-grid-column>
|
||||||
|
|
||||||
<kendo-grid-column field="skillTarget" title="Target" [width]="150">
|
<kendo-grid-column field="skillTarget" title="Target" [width]="150">
|
||||||
<ng-template kendoGridCellTemplate let-dataItem>
|
<ng-template kendoGridCellTemplate let-dataItem>
|
||||||
{{ getSkillTargetName(dataItem.skillTarget) }}
|
{{ getSkillTargetName(dataItem.skillTarget) }}
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template kendoGridEditTemplate let-dataItem="dataItem">
|
|
||||||
<kendo-dropdownlist [(ngModel)]="dataItem.skillTarget" name="skillTarget" [data]="skillTargets"
|
|
||||||
[valueField]="'value'" [textField]="'text'">
|
|
||||||
</kendo-dropdownlist>
|
|
||||||
</ng-template>
|
|
||||||
</kendo-grid-column>
|
</kendo-grid-column>
|
||||||
|
|
||||||
<kendo-grid-column field="clawRoll" title="Claw Roll" [width]="100">
|
<kendo-grid-column field="clawRoll" title="Claw Roll" [width]="100">
|
||||||
<ng-template kendoGridEditTemplate let-dataItem="dataItem">
|
<ng-template kendoGridCellTemplate let-dataItem>
|
||||||
<kendo-numerictextbox [(ngModel)]="dataItem.clawRoll" name="clawRoll" [min]="0">
|
{{ dataItem.clawRoll }}
|
||||||
</kendo-numerictextbox>
|
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</kendo-grid-column>
|
</kendo-grid-column>
|
||||||
|
|
||||||
<kendo-grid-column field="skillRoll" title="Skill Roll" [width]="100">
|
<kendo-grid-column field="skillRoll" title="Skill Roll" [width]="100">
|
||||||
<ng-template kendoGridEditTemplate let-dataItem="dataItem">
|
<ng-template kendoGridCellTemplate let-dataItem>
|
||||||
<kendo-numerictextbox [(ngModel)]="dataItem.skillRoll" name="skillRoll" [min]="0">
|
{{ dataItem.skillRoll }}
|
||||||
</kendo-numerictextbox>
|
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</kendo-grid-column>
|
</kendo-grid-column>
|
||||||
|
|
||||||
<kendo-grid-column field="description" title="Description" [width]="300">
|
<kendo-grid-column field="description" title="Description" [width]="300">
|
||||||
<ng-template kendoGridEditTemplate let-dataItem="dataItem">
|
<ng-template kendoGridCellTemplate let-dataItem>
|
||||||
<textarea kendoTextArea [(ngModel)]="dataItem.description" name="description"
|
<div [innerHTML]="dataItem.description"></div>
|
||||||
placeholder="Enter skill description" rows="3">
|
|
||||||
</textarea>
|
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</kendo-grid-column>
|
</kendo-grid-column>
|
||||||
|
|
||||||
<kendo-grid-command-column title="Actions" [width]="200">
|
<kendo-grid-command-column title="Actions" [width]="200">
|
||||||
<ng-template kendoGridCellTemplate let-isNew="isNew" let-dataItem="dataItem" let-rowIndex="rowIndex">
|
<ng-template kendoGridCellTemplate let-isNew="isNew" let-dataItem="dataItem" let-rowIndex="rowIndex">
|
||||||
<button kendoGridEditCommand [primary]="true">Edit</button>
|
<button kendoButton [primary]="true" (click)="editSkillHandler(dataItem)">Edit</button>
|
||||||
<button kendoGridRemoveCommand>Remove</button>
|
<button kendoGridRemoveCommand>Remove</button>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template kendoGridEditCommandTemplate let-isNew="isNew" let-rowIndex="rowIndex">
|
|
||||||
<button kendoGridSaveCommand>Save</button>
|
|
||||||
<button kendoGridCancelCommand>Cancel</button>
|
|
||||||
</ng-template>
|
|
||||||
</kendo-grid-command-column>
|
</kendo-grid-command-column>
|
||||||
</kendo-grid>
|
</kendo-grid>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Component, Input, OnInit, ViewChild } from '@angular/core';
|
import { Component, Input, OnInit, ViewChild } from '@angular/core';
|
||||||
import { DialogRef, DialogContentBase } from '@progress/kendo-angular-dialog';
|
import { DialogRef, DialogContentBase, DialogService } from '@progress/kendo-angular-dialog';
|
||||||
import { GridComponent, GridDataResult } from '@progress/kendo-angular-grid';
|
import { GridComponent, GridDataResult } from '@progress/kendo-angular-grid';
|
||||||
import { State } from '@progress/kendo-data-query';
|
import { State } from '@progress/kendo-data-query';
|
||||||
import { first } from 'rxjs/operators';
|
import { first } from 'rxjs/operators';
|
||||||
@ -8,6 +8,7 @@ import { MobType } from '../../massive-darkness2.model';
|
|||||||
import { MobSkillType } from '../../massive-darkness2.model.boss';
|
import { MobSkillType } from '../../massive-darkness2.model.boss';
|
||||||
import { MD2MobLevelInfoService, MD2MobSkillService } from '../../service/massive-darkness2.service';
|
import { MD2MobLevelInfoService, MD2MobSkillService } from '../../service/massive-darkness2.service';
|
||||||
import { MsgBoxService } from '../../../../services/msg-box.service';
|
import { MsgBoxService } from '../../../../services/msg-box.service';
|
||||||
|
import { MD2MobSkillEditorComponent } from '../md2-mob-skill-editor/md2-mob-skill-editor.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ngx-md2-mob-info-detail',
|
selector: 'ngx-md2-mob-info-detail',
|
||||||
@ -48,6 +49,7 @@ export class MD2MobInfoDetailComponent extends DialogContentBase implements OnIn
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public dialog: DialogRef,
|
public dialog: DialogRef,
|
||||||
|
private dialogService: DialogService,
|
||||||
private mobLevelInfoService: MD2MobLevelInfoService,
|
private mobLevelInfoService: MD2MobLevelInfoService,
|
||||||
private mobSkillService: MD2MobSkillService,
|
private mobSkillService: MD2MobSkillService,
|
||||||
private msgBoxService: MsgBoxService
|
private msgBoxService: MsgBoxService
|
||||||
@ -224,45 +226,64 @@ export class MD2MobInfoDetailComponent extends DialogContentBase implements OnIn
|
|||||||
description: ''
|
description: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.openSkillEditor(newSkill, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public editSkillHandler(dataItem: MD2MobSkill): void {
|
||||||
|
if (!this.selectedLevelInfo) return;
|
||||||
|
|
||||||
|
// Create a copy of the skill for editing
|
||||||
|
const skillCopy: MD2MobSkill = JSON.parse(JSON.stringify(dataItem));
|
||||||
|
this.openSkillEditor(skillCopy, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private openSkillEditor(skill: MD2MobSkill, isNew: boolean): void {
|
||||||
|
if (!this.selectedLevelInfo) return;
|
||||||
|
|
||||||
|
const dialogRef = this.dialogService.open({
|
||||||
|
title: isNew ? 'Add New Skill' : 'Edit Skill',
|
||||||
|
content: MD2MobSkillEditorComponent,
|
||||||
|
width: '80vw',
|
||||||
|
height: 700
|
||||||
|
});
|
||||||
|
|
||||||
|
const editor = dialogRef.content.instance;
|
||||||
|
editor.isAdding = isNew;
|
||||||
|
editor.data = skill;
|
||||||
|
editor.mobLevelInfoId = this.selectedLevelInfo.id;
|
||||||
|
|
||||||
|
// Force model re-initialization after data is set
|
||||||
|
setTimeout(() => {
|
||||||
|
editor.initializeModel();
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
dialogRef.result.subscribe(result => {
|
||||||
|
if (result && typeof result === 'object' && 'id' in result) {
|
||||||
|
this.handleSkillSaved(result as MD2MobSkill, isNew);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleSkillSaved(result: MD2MobSkill, isNew: boolean): void {
|
||||||
|
if (!this.selectedLevelInfo) return;
|
||||||
|
|
||||||
|
if (isNew) {
|
||||||
if (!this.selectedLevelInfo.skills) {
|
if (!this.selectedLevelInfo.skills) {
|
||||||
this.selectedLevelInfo.skills = [];
|
this.selectedLevelInfo.skills = [];
|
||||||
}
|
}
|
||||||
this.selectedLevelInfo.skills.push(newSkill);
|
this.selectedLevelInfo.skills.push(result);
|
||||||
|
} else {
|
||||||
|
const index = this.selectedLevelInfo.skills?.findIndex(s => s.id === result.id);
|
||||||
|
if (index !== undefined && index !== -1 && this.selectedLevelInfo.skills) {
|
||||||
|
this.selectedLevelInfo.skills[index] = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
this.loadSkills(this.selectedLevelInfo);
|
this.loadSkills(this.selectedLevelInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public saveSkillHandler({ dataItem, isNew }: any): void {
|
public saveSkillHandler({ dataItem, isNew }: any): void {
|
||||||
if (isNew) {
|
// This method is no longer used but kept for backward compatibility
|
||||||
dataItem.id = this.generateId();
|
// Skills are now edited via dialog
|
||||||
dataItem.mobLevelInfoId = this.selectedLevelInfo?.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isLoading = true;
|
|
||||||
this.mobSkillService.createOrUpdate(dataItem).pipe(first()).subscribe(result => {
|
|
||||||
this.isLoading = false;
|
|
||||||
if (this.selectedLevelInfo) {
|
|
||||||
if (isNew) {
|
|
||||||
if (!this.selectedLevelInfo.skills) {
|
|
||||||
this.selectedLevelInfo.skills = [];
|
|
||||||
}
|
|
||||||
const index = this.selectedLevelInfo.skills.findIndex(s => s.id === dataItem.id);
|
|
||||||
if (index !== -1) {
|
|
||||||
this.selectedLevelInfo.skills[index] = result;
|
|
||||||
} else {
|
|
||||||
this.selectedLevelInfo.skills.push(result);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const index = this.selectedLevelInfo.skills.findIndex(s => s.id === result.id);
|
|
||||||
if (index !== -1) {
|
|
||||||
this.selectedLevelInfo.skills[index] = result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.loadSkills(this.selectedLevelInfo);
|
|
||||||
}
|
|
||||||
}, error => {
|
|
||||||
this.isLoading = false;
|
|
||||||
console.error('Error saving skill:', error);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeSkillHandler({ dataItem }: { dataItem: MD2MobSkill }): void {
|
public removeSkillHandler({ dataItem }: { dataItem: MD2MobSkill }): void {
|
||||||
|
|||||||
@ -0,0 +1,64 @@
|
|||||||
|
<div class="k-dialog-content">
|
||||||
|
<form #form="ngForm" class="k-form">
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="k-label">Name</label>
|
||||||
|
<input kendoTextBox [(ngModel)]="model.name" name="name" class="k-input"
|
||||||
|
placeholder="Enter skill name" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="k-label">Type *</label>
|
||||||
|
<kendo-dropdownlist [(ngModel)]="selectedSkillType" name="type" [data]="skillTypes"
|
||||||
|
[valueField]="'value'" [textField]="'text'"
|
||||||
|
[defaultItem]="{ value: null, text: 'Select type...' }">
|
||||||
|
</kendo-dropdownlist>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="k-label">Target</label>
|
||||||
|
<kendo-dropdownlist [(ngModel)]="selectedSkillTarget" name="skillTarget" [data]="skillTargets"
|
||||||
|
[valueField]="'value'" [textField]="'text'">
|
||||||
|
</kendo-dropdownlist>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="k-label"><md2-icon icon="EnemyClaw"></md2-icon>Claw Roll</label>
|
||||||
|
<kendo-numerictextbox [(ngModel)]="model.clawRoll" name="clawRoll" [min]="0" [decimals]="0"
|
||||||
|
[format]="'n0'">
|
||||||
|
</kendo-numerictextbox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="k-label"><md2-icon icon="EnemySkill"></md2-icon>Skill Roll</label>
|
||||||
|
<kendo-numerictextbox [(ngModel)]="model.skillRoll" name="skillRoll" [min]="0" [decimals]="0"
|
||||||
|
[format]="'n0'">
|
||||||
|
</kendo-numerictextbox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="k-label">Description</label>
|
||||||
|
<md2-html-editor [(ngModel)]="model.description" name="description"
|
||||||
|
class="htmlEditor"></md2-html-editor>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<kendo-dialog-actions>
|
||||||
|
<button kendoButton (click)="close()">Cancel</button>
|
||||||
|
<button kendoButton [primary]="true" (click)="save()" [disabled]="!isValid || processing">
|
||||||
|
{{ processing ? 'Saving...' : 'Save' }}
|
||||||
|
</button>
|
||||||
|
</kendo-dialog-actions>
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
.k-label {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
md2-html-editor {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 300px;
|
||||||
|
}
|
||||||
@ -0,0 +1,115 @@
|
|||||||
|
import { Component, Input, OnInit, ViewChild, ChangeDetectorRef } from '@angular/core';
|
||||||
|
import { DialogRef, DialogContentBase } from '@progress/kendo-angular-dialog';
|
||||||
|
import { NgForm } from '@angular/forms';
|
||||||
|
import { first } from 'rxjs/operators';
|
||||||
|
import { MD2MobSkill, MobSkillTarget } from '../../massive-darkness2.db.model';
|
||||||
|
import { MobSkillType } from '../../massive-darkness2.model.boss';
|
||||||
|
import { MD2MobSkillService } from '../../service/massive-darkness2.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ngx-md2-mob-skill-editor',
|
||||||
|
templateUrl: './md2-mob-skill-editor.component.html',
|
||||||
|
styleUrls: ['./md2-mob-skill-editor.component.scss']
|
||||||
|
})
|
||||||
|
export class MD2MobSkillEditorComponent extends DialogContentBase implements OnInit {
|
||||||
|
@Input() public data: MD2MobSkill;
|
||||||
|
@Input() public mobLevelInfoId: string;
|
||||||
|
@Input() public isAdding: boolean = false;
|
||||||
|
@ViewChild('form') form: NgForm;
|
||||||
|
|
||||||
|
public model: MD2MobSkill;
|
||||||
|
public processing: boolean = false;
|
||||||
|
public skillTypes: Array<{ value: MobSkillType; text: string }> = [];
|
||||||
|
public skillTargets: Array<{ value: MobSkillTarget | null; text: string }> = [];
|
||||||
|
public selectedSkillType: { value: MobSkillType; text: string } | null = null;
|
||||||
|
public selectedSkillTarget: { value: MobSkillTarget | null; text: string } | null = null;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialog: DialogRef,
|
||||||
|
private mobSkillService: MD2MobSkillService,
|
||||||
|
private cdr: ChangeDetectorRef
|
||||||
|
) {
|
||||||
|
super(dialog);
|
||||||
|
this.initializeEnums();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.initializeModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public initializeModel(): void {
|
||||||
|
const typeValue = this.data?.type !== undefined && this.data?.type !== null ? this.data.type : MobSkillType.Combat;
|
||||||
|
const targetValue = this.data?.skillTarget !== undefined ? this.data.skillTarget : null;
|
||||||
|
|
||||||
|
this.model = {
|
||||||
|
id: this.data?.id || '',
|
||||||
|
mobLevelInfoId: this.mobLevelInfoId || this.data?.mobLevelInfoId || '',
|
||||||
|
type: typeValue,
|
||||||
|
skillTarget: targetValue,
|
||||||
|
clawRoll: this.data?.clawRoll ?? 0,
|
||||||
|
skillRoll: this.data?.skillRoll ?? 1,
|
||||||
|
name: this.data?.name || '',
|
||||||
|
description: this.data?.description || ''
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set selected objects for dropdowns
|
||||||
|
this.selectedSkillType = this.skillTypes.find(t => t.value === typeValue) || this.skillTypes[0] || null;
|
||||||
|
this.selectedSkillTarget = this.skillTargets.find(t => t.value === targetValue) || this.skillTargets[0] || null;
|
||||||
|
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
private initializeEnums(): void {
|
||||||
|
// Initialize MobSkillType options
|
||||||
|
Object.keys(MobSkillType).filter(key => isNaN(Number(key))).forEach(key => {
|
||||||
|
this.skillTypes.push({
|
||||||
|
value: MobSkillType[key] as MobSkillType,
|
||||||
|
text: key
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize MobSkillTarget options
|
||||||
|
this.skillTargets.push({ value: null, text: 'None' });
|
||||||
|
Object.keys(MobSkillTarget).filter(key => isNaN(Number(key))).forEach(key => {
|
||||||
|
this.skillTargets.push({
|
||||||
|
value: MobSkillTarget[key] as MobSkillTarget,
|
||||||
|
text: key
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public close(): void {
|
||||||
|
this.dialog.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public save(): void {
|
||||||
|
if (!this.processing) {
|
||||||
|
this.processing = true;
|
||||||
|
|
||||||
|
// Extract enum values from selected objects
|
||||||
|
const mobSkill: MD2MobSkill = {
|
||||||
|
...this.model,
|
||||||
|
type: this.selectedSkillType?.value ?? MobSkillType.Combat,
|
||||||
|
skillTarget: this.selectedSkillTarget?.value ?? null,
|
||||||
|
mobLevelInfoId: this.mobLevelInfoId || this.model.mobLevelInfoId
|
||||||
|
};
|
||||||
|
|
||||||
|
this.mobSkillService.createOrUpdate(mobSkill).pipe(first()).subscribe(result => {
|
||||||
|
this.processing = false;
|
||||||
|
this.dialog.close(result);
|
||||||
|
}, error => {
|
||||||
|
this.processing = false;
|
||||||
|
console.error('Error saving mob skill:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isValid(): boolean {
|
||||||
|
if (!this.model) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const typeValid = this.selectedSkillType !== null && this.selectedSkillType !== undefined;
|
||||||
|
return typeValid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user