diff --git a/package-lock.json b/package-lock.json
index 9bed70f..a6c9b71 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -69,6 +69,7 @@
"@angular/cli": "^17.3.3",
"@angular/compiler-cli": "^17.3.3",
"@angular/language-service": "17.3.3",
+ "@angular/localize": "^17.3.3",
"@compodoc/compodoc": "1.0.1",
"@fortawesome/fontawesome-free": "^5.2.0",
"@schematics/angular": "^14.1.3",
@@ -856,6 +857,30 @@
"node": "^18.13.0 || >=20.9.0"
}
},
+ "node_modules/@angular/localize": {
+ "version": "17.3.3",
+ "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-17.3.3.tgz",
+ "integrity": "sha512-gahGKy0VBZ+KP6MUULGQMoi5SN3REwslaPvtomizzz9fdmqHfR8PPd1vOJSNm2IEVlvm1hv1dDRjPcR4DJwvaQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/core": "7.23.9",
+ "@types/babel__core": "7.20.5",
+ "fast-glob": "3.3.2",
+ "yargs": "^17.2.1"
+ },
+ "bin": {
+ "localize-extract": "tools/bundles/src/extract/cli.js",
+ "localize-migrate": "tools/bundles/src/migrate/cli.js",
+ "localize-translate": "tools/bundles/src/translate/cli.js"
+ },
+ "engines": {
+ "node": "^18.13.0 || >=20.9.0"
+ },
+ "peerDependencies": {
+ "@angular/compiler": "17.3.3",
+ "@angular/compiler-cli": "17.3.3"
+ }
+ },
"node_modules/@angular/platform-browser": {
"version": "17.3.3",
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-17.3.3.tgz",
@@ -1325,18 +1350,18 @@
}
},
"node_modules/@babel/helper-string-parser": {
- "version": "7.24.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz",
- "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==",
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
- "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
+ "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
"dev": true,
"engines": {
"node": ">=6.9.0"
@@ -2687,14 +2712,13 @@
}
},
"node_modules/@babel/types": {
- "version": "7.24.0",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz",
- "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz",
+ "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==",
"dev": true,
"dependencies": {
- "@babel/helper-string-parser": "^7.23.4",
- "@babel/helper-validator-identifier": "^7.22.20",
- "to-fast-properties": "^2.0.0"
+ "@babel/helper-string-parser": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.28.5"
},
"engines": {
"node": ">=6.9.0"
@@ -12453,6 +12477,47 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/@types/babel__core": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
+ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/parser": "^7.20.7",
+ "@babel/types": "^7.20.7",
+ "@types/babel__generator": "*",
+ "@types/babel__template": "*",
+ "@types/babel__traverse": "*"
+ }
+ },
+ "node_modules/@types/babel__generator": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
+ "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__template": {
+ "version": "7.4.4",
+ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
+ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
+ "dev": true,
+ "dependencies": {
+ "@babel/parser": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__traverse": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
+ "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.28.2"
+ }
+ },
"node_modules/@types/body-parser": {
"version": "1.19.5",
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz",
@@ -29691,15 +29756,6 @@
"node": ">=0.6.0"
}
},
- "node_modules/to-fast-properties": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
- "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/to-object-path": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
@@ -32340,6 +32396,18 @@
"integrity": "sha512-OtdWNY0Syg4UvA8j2IhQJeq/UjWHYbRiyUcZjGKPRzuqIPjUhsmMyuW3zpi7Pwx2CpBzZXcik1Ra2WZ0gbwigg==",
"dev": true
},
+ "@angular/localize": {
+ "version": "17.3.3",
+ "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-17.3.3.tgz",
+ "integrity": "sha512-gahGKy0VBZ+KP6MUULGQMoi5SN3REwslaPvtomizzz9fdmqHfR8PPd1vOJSNm2IEVlvm1hv1dDRjPcR4DJwvaQ==",
+ "dev": true,
+ "requires": {
+ "@babel/core": "7.23.9",
+ "@types/babel__core": "7.20.5",
+ "fast-glob": "3.3.2",
+ "yargs": "^17.2.1"
+ }
+ },
"@angular/platform-browser": {
"version": "17.3.3",
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-17.3.3.tgz",
@@ -32679,15 +32747,15 @@
}
},
"@babel/helper-string-parser": {
- "version": "7.24.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz",
- "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==",
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
"dev": true
},
"@babel/helper-validator-identifier": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
- "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
+ "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
"dev": true
},
"@babel/helper-validator-option": {
@@ -33607,14 +33675,13 @@
}
},
"@babel/types": {
- "version": "7.24.0",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz",
- "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz",
+ "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==",
"dev": true,
"requires": {
- "@babel/helper-string-parser": "^7.23.4",
- "@babel/helper-validator-identifier": "^7.22.20",
- "to-fast-properties": "^2.0.0"
+ "@babel/helper-string-parser": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.28.5"
}
},
"@colors/colors": {
@@ -40050,6 +40117,47 @@
}
}
},
+ "@types/babel__core": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
+ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
+ "dev": true,
+ "requires": {
+ "@babel/parser": "^7.20.7",
+ "@babel/types": "^7.20.7",
+ "@types/babel__generator": "*",
+ "@types/babel__template": "*",
+ "@types/babel__traverse": "*"
+ }
+ },
+ "@types/babel__generator": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
+ "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@types/babel__template": {
+ "version": "7.4.4",
+ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
+ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
+ "dev": true,
+ "requires": {
+ "@babel/parser": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@types/babel__traverse": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
+ "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.28.2"
+ }
+ },
"@types/body-parser": {
"version": "1.19.5",
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz",
@@ -53452,12 +53560,6 @@
"os-tmpdir": "~1.0.2"
}
},
- "to-fast-properties": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
- "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
- "dev": true
- },
"to-object-path": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
diff --git a/package.json b/package.json
index 5ba83c5..5a560d5 100644
--- a/package.json
+++ b/package.json
@@ -89,6 +89,7 @@
"@angular/cli": "^17.3.3",
"@angular/compiler-cli": "^17.3.3",
"@angular/language-service": "17.3.3",
+ "@angular/localize": "^17.3.3",
"@compodoc/compodoc": "1.0.1",
"@fortawesome/fontawesome-free": "^5.2.0",
"@schematics/angular": "^14.1.3",
diff --git a/src/app/admin/cell-group-routine-events/cell-group-routine-events.component.ts b/src/app/admin/cell-group-routine-events/cell-group-routine-events.component.ts
index deef103..1c899b6 100644
--- a/src/app/admin/cell-group-routine-events/cell-group-routine-events.component.ts
+++ b/src/app/admin/cell-group-routine-events/cell-group-routine-events.component.ts
@@ -3,14 +3,12 @@ import { ActivatedRoute } from '@angular/router';
import { NbDialogService } from '@nebular/theme';
import { Observable } from 'rxjs';
import { first } from 'rxjs/operators';
-import { inherits } from 'util';
import { CellGroupRoutineEvents } from '../../entity/CellGroupRoutineEvents';
import { CellGroupRoutineEventsService } from '../../services/crudServices/cell-group-routine-events.service';
import { MsgBoxService } from '../../services/msg-box.service';
import { StateService } from '../../services/state.service';
import { FancySettings } from '../../ui/fancy-table/fancy-settings.model';
import { FancyTableComponent } from '../../ui/fancy-table/fancy-table.component';
-import { ObjectUtils } from '../../utilities/object-utils';
@Component({
selector: 'ngx-cell-group-routine-events',
diff --git a/src/app/cell-group/MyAppBase.ts b/src/app/cell-group/MyAppBase.ts
index e2a0bea..dec3d27 100644
--- a/src/app/cell-group/MyAppBase.ts
+++ b/src/app/cell-group/MyAppBase.ts
@@ -1,8 +1,5 @@
import { ActivatedRoute } from "@angular/router";
-import { basename } from "path";
import { Observable, Subject } from "rxjs";
-import { ScreenBase } from "../ScreenBase";
-import { ICrudService } from "../services/crudServices/crud.service";
import { PastoralDomainService } from "../services/crudServices/pastoral-domain.service";
import { StateService } from "../services/state.service";
import { first } from 'rxjs/operators';
diff --git a/src/app/games/massive-darkness2/massive-darkness2.component.html b/src/app/games/massive-darkness2/massive-darkness2.component.html
index ef90886..09e01bf 100644
--- a/src/app/games/massive-darkness2/massive-darkness2.component.html
+++ b/src/app/games/massive-darkness2/massive-darkness2.component.html
@@ -12,10 +12,10 @@
-
-->
+
diff --git a/src/app/games/massive-darkness2/massive-darkness2.component.ts b/src/app/games/massive-darkness2/massive-darkness2.component.ts
index 5bfdce5..5ae0385 100644
--- a/src/app/games/massive-darkness2/massive-darkness2.component.ts
+++ b/src/app/games/massive-darkness2/massive-darkness2.component.ts
@@ -25,7 +25,7 @@ import { NumberUtils } from '../../utilities/number-utils';
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MassiveDarkness2Component extends MD2Base implements OnInit {
- HeroClass: HeroClass
+ HeroClass = HeroClass;
constructor(
private fileService: FileService,
private initService: MD2InitService,
diff --git a/src/app/games/massive-darkness2/massive-darkness2.model.boss.ts b/src/app/games/massive-darkness2/massive-darkness2.model.boss.ts
index 342e9aa..836de74 100644
--- a/src/app/games/massive-darkness2/massive-darkness2.model.boss.ts
+++ b/src/app/games/massive-darkness2/massive-darkness2.model.boss.ts
@@ -1,4 +1,4 @@
-import { stringify } from "querystring"
+
import { Observable, Subject, Subscription } from "rxjs"
import { first } from "rxjs/operators"
import { MD2Service } from "../../services/MD2/md2.service"
diff --git a/src/app/games/massive-darkness2/md2-html-editor/md2-html-editor.component.html b/src/app/games/massive-darkness2/md2-html-editor/md2-html-editor.component.html
index 0f1f036..0712807 100644
--- a/src/app/games/massive-darkness2/md2-html-editor/md2-html-editor.component.html
+++ b/src/app/games/massive-darkness2/md2-html-editor/md2-html-editor.component.html
@@ -1,20 +1,50 @@
-
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- Insert Icon
-
+
\ No newline at end of file
diff --git a/src/app/games/massive-darkness2/md2-html-editor/md2-html-editor.component.ts b/src/app/games/massive-darkness2/md2-html-editor/md2-html-editor.component.ts
index dc92f09..fb0939a 100644
--- a/src/app/games/massive-darkness2/md2-html-editor/md2-html-editor.component.ts
+++ b/src/app/games/massive-darkness2/md2-html-editor/md2-html-editor.component.ts
@@ -1,6 +1,6 @@
-import { Component, ElementRef, EventEmitter, Inject, Input, NgZone, Output, PLATFORM_ID, Renderer2, ViewChild } from '@angular/core';
+import { Component, ElementRef, EventEmitter, Inject, Input, NgZone, Output, PLATFORM_ID, Renderer2, ViewChild, AfterViewInit } from '@angular/core';
import { ControlValueAccessor, Validator, AbstractControl, ValidationErrors } from '@angular/forms';
-import { EditorComponent } from '@progress/kendo-angular-editor';
+import { EditorComponent, NodeSpec, schema, Schema, FontSizeItem } from '@progress/kendo-angular-editor';
import { MsgBoxService } from '../../../services/msg-box.service';
import { DropDownOption } from '../../../entity/dropDownOption';
@@ -9,21 +9,42 @@ import { first } from 'rxjs/operators';
import { MD2StateService } from '../../../services/MD2/md2-state.service';
import { MD2IconPickerDlgComponent } from './md2-icon-picker-dlg.component';
import { NbDialogService } from '@nebular/theme';
-
+import { DOMParser as ProseMirrorDOMParser } from 'prosemirror-model';
@Component({
selector: 'md2-html-editor',
templateUrl: './md2-html-editor.component.html',
styleUrl: './md2-html-editor.component.scss'
})
-export class MD2HtmlEditorComponent implements ControlValueAccessor {
+export class MD2HtmlEditorComponent implements ControlValueAccessor, AfterViewInit {
@ViewChild(EditorComponent) editor: EditorComponent;
+ @ViewChild('fontSizeDropdown') fontSizeDropdown: any;
value: string = '';
disabled: boolean = false;
- messageTemplateSchema = this.createCustomSchema();
+ messageTemplateSchema = this.createCustomSchema();
customCssClass = '.MD2Icon{font-family: "Massive Darkness 2", sans-serif !important; font-size: 40px; margin-left:5px} body{font-size: 30px; }';
+ // Default font size: 30px
+ fontSizeData: FontSizeItem[] = [
+ { size: 30, text: '30px' },
+ { size: 8, text: '8px' },
+ { size: 10, text: '10px' },
+ { size: 12, text: '12px' },
+ { size: 14, text: '14px' },
+ { size: 16, text: '16px' },
+ { size: 18, text: '18px' },
+ { size: 20, text: '20px' },
+ { size: 24, text: '24px' },
+ { size: 30, text: '30px' },
+ { size: 36, text: '36px' },
+ { size: 48, text: '48px' },
+ { size: 60, text: '60px' },
+ { size: 72, text: '72px' }
+ ];
+
+ defaultFontSize: FontSizeItem = { size: 30, text: '30px' };
+
// ControlValueAccessor interface
private onChangeFn = (value: string) => { };
private onTouchedFn = () => { };
@@ -36,6 +57,23 @@ export class MD2HtmlEditorComponent implements ControlValueAccessor {
}
+ ngAfterViewInit(): void {
+ // Set default font size after view initialization
+ // The fontSizeDropdown is the EditorFontSizeComponent instance
+ setTimeout(() => {
+ if (this.fontSizeDropdown) {
+ // Access the fontSizeDropDownList component which has the defaultItem property
+ if (this.fontSizeDropdown.fontSizeDropDownList) {
+ this.fontSizeDropdown.fontSizeDropDownList.defaultItem = this.defaultFontSize;
+ }
+ // Also try setting it directly on the component if it has the property
+ if (this.fontSizeDropdown.defaultItem !== undefined) {
+ this.fontSizeDropdown.defaultItem = this.defaultFontSize;
+ }
+ }
+ }, 0);
+ }
+
// ControlValueAccessor implementation
writeValue(value: string): void {
this.value = value || '';
@@ -68,6 +106,8 @@ export class MD2HtmlEditorComponent implements ControlValueAccessor {
closeOnEsc: true
}).onClose.pipe(first()).subscribe((html: string) => {
if (html && this.editor) {
+ this.insertAfterSelection(html, true);
+ return;
// Insert the HTML content at the current cursor position
// Use ProseMirror's dispatch method to insert content at cursor
const view = this.editor.view;
@@ -110,303 +150,296 @@ export class MD2HtmlEditorComponent implements ControlValueAccessor {
}
});
}
-
- // Text manipulation methods for Kendo Editor
- /**
- * Parses HTML string to ProseMirror nodes
- * @param htmlContent - HTML string to parse
- * @returns ProseMirror Fragment
- */
- private parseHtmlContent(htmlContent: string): any {
- if (!this.editor || !this.editor.view) return null;
- const view = this.editor.view;
- const element = document.createElement('div');
- element.innerHTML = htmlContent;
+ // Text manipulation methods for Kendo Editor
+ /**
+ * Parses HTML string to ProseMirror nodes
+ * @param htmlContent - HTML string to parse
+ * @returns ProseMirror Fragment
+ */
+ private parseHtmlContent(htmlContent: string): any {
+ if (!this.editor || !this.editor.view) return null;
- // Use ProseMirror's DOMParser to parse HTML into nodes
- const parser = ProseMirrorDOMParser.fromSchema(view.state.schema);
- const slice = parser.parseSlice(element);
- return slice.content;
+ const view = this.editor.view;
+ const element = document.createElement('div');
+ element.innerHTML = htmlContent;
+
+ // Use ProseMirror's DOMParser to parse HTML into nodes
+ const parser = ProseMirrorDOMParser.fromSchema(view.state.schema);
+ const slice = parser.parseSlice(element);
+ return slice.content;
+ }
+
+ /**
+ * Inserts HTML content at the beginning of the editor
+ * @param content - HTML string to insert
+ * @param asHtml - If true, parses as HTML; if false, inserts as plain text
+ */
+ public insertAtBeginning(content: string, asHtml: boolean = false): void {
+ if (!this.editor || !this.editor.view) return;
+
+ const view = this.editor.view;
+ const contentNode = asHtml ? this.parseHtmlContent(content) : view.state.schema.text(content);
+
+ if (contentNode) {
+ const transaction = view.state.tr.insert(0, contentNode);
+ view.dispatch(transaction);
+ this.onChange(this.editor.value);
+ }
+ }
+
+ /**
+ * Inserts HTML content at the end of the editor
+ * @param content - HTML string to insert
+ * @param asHtml - If true, parses as HTML; if false, inserts as plain text
+ */
+ public insertAtEnd(content: string, asHtml: boolean = false): void {
+ if (!this.editor || !this.editor.view) return;
+
+ const view = this.editor.view;
+ const endPos = view.state.doc.content.size;
+ const contentNode = asHtml ? this.parseHtmlContent(content) : view.state.schema.text(content);
+
+ if (contentNode) {
+ const transaction = view.state.tr.insert(endPos, contentNode);
+ view.dispatch(transaction);
+ this.onChange(this.editor.value);
+ }
+ }
+
+ /**
+ * Inserts HTML content before the current selection
+ * @param content - HTML string to insert
+ * @param asHtml - If true, parses as HTML; if false, inserts as plain text
+ */
+ public insertBeforeSelection(content: string, asHtml: boolean = false): void {
+ if (!this.editor || !this.editor.view) return;
+
+ const view = this.editor.view;
+ const { from } = view.state.selection;
+ const contentNode = asHtml ? this.parseHtmlContent(content) : view.state.schema.text(content);
+
+ if (contentNode) {
+ const transaction = view.state.tr.insert(from, contentNode);
+ view.dispatch(transaction);
+ this.onChange(this.editor.value);
+ }
+ }
+
+ /**
+ * Inserts HTML content after the current selection
+ * @param content - HTML string to insert
+ * @param asHtml - If true, parses as HTML; if false, inserts as plain text
+ */
+ public insertAfterSelection(content: string, asHtml: boolean = false): void {
+ if (!this.editor || !this.editor.view) return;
+
+ const view = this.editor.view;
+ const { to } = view.state.selection;
+ const contentNode = asHtml ? this.parseHtmlContent(content) : view.state.schema.text(content);
+
+ if (contentNode) {
+ const transaction = view.state.tr.insert(to, contentNode);
+ view.dispatch(transaction);
+ this.onChange(this.editor.value);
+ }
+ }
+
+ /**
+ * Replaces the currently selected text with new content
+ * @param content - HTML string to replace selection with
+ * @param asHtml - If true, parses as HTML; if false, inserts as plain text
+ */
+ public replaceSelectedText(content: string, asHtml: boolean = false): void {
+ if (!this.editor || !this.editor.view) return;
+
+ const view = this.editor.view;
+ const { from, to } = view.state.selection;
+ const contentNode = asHtml ? this.parseHtmlContent(content) : view.state.schema.text(content);
+
+ if (!contentNode) return;
+
+ // If there's no selection, just insert at cursor position
+ if (from === to) {
+ const transaction = view.state.tr.insert(from, contentNode);
+ view.dispatch(transaction);
+ } else {
+ // Replace the selected content
+ const transaction = view.state.tr.replaceWith(from, to, contentNode);
+ view.dispatch(transaction);
+ }
+ this.onChange(this.editor.value);
+ }
+
+ /**
+ * Gets the currently selected text in the editor
+ * @returns The selected text as a string
+ */
+ public getSelectedText(): string {
+ if (!this.editor) return '';
+ return this.editor.selectionText || '';
+ }
+ public getSelectionTextOrWholeText(): string {
+ if (!this.editor) return '';
+
+ // If there's selected text, return it
+ if (this.editor.selectionText && this.editor.selectionText.trim().length > 0) {
+ return this.editor.selectionText;
}
- /**
- * Inserts HTML content at the beginning of the editor
- * @param content - HTML string to insert
- * @param asHtml - If true, parses as HTML; if false, inserts as plain text
- */
- public insertAtBeginning(content: string, asHtml: boolean = false): void {
- if (!this.editor || !this.editor.view) return;
-
- const view = this.editor.view;
- const contentNode = asHtml ? this.parseHtmlContent(content) : view.state.schema.text(content);
-
- if (contentNode) {
- const transaction = view.state.tr.insert(0, contentNode);
- view.dispatch(transaction);
- this.onValueChanged(this.editor.value);
- }
+ // Otherwise, get the whole text content from the editor's document
+ if (this.editor.view && this.editor.view.state) {
+ return this.editor.view.state.doc.textContent;
}
- /**
- * Inserts HTML content at the end of the editor
- * @param content - HTML string to insert
- * @param asHtml - If true, parses as HTML; if false, inserts as plain text
- */
- public insertAtEnd(content: string, asHtml: boolean = false): void {
- if (!this.editor || !this.editor.view) return;
+ // Fallback: strip HTML tags and return plain text
+ const div = document.createElement('div');
+ div.innerHTML = this.editor.value;
+ return div.textContent || div.innerText || '';
+ }
- const view = this.editor.view;
- const endPos = view.state.doc.content.size;
- const contentNode = asHtml ? this.parseHtmlContent(content) : view.state.schema.text(content);
+ /**
+ * Gets the current cursor position or selection range
+ * @returns Object with 'from' and 'to' positions
+ */
+ public getSelectionRange(): { from: number; to: number } | null {
+ if (!this.editor || !this.editor.view) return null;
- if (contentNode) {
- const transaction = view.state.tr.insert(endPos, contentNode);
- view.dispatch(transaction);
- this.onValueChanged(this.editor.value);
- }
+ const { from, to } = this.editor.view.state.selection;
+ return { from, to };
+ }
+
+ /**
+ * Inserts HTML content at a specific position
+ * @param content - HTML string to insert
+ * @param position - Position to insert at (0 = beginning)
+ * @param asHtml - If true, parses as HTML; if false, inserts as plain text
+ */
+ public insertAtPosition(content: string, position: number, asHtml: boolean = false): void {
+ if (!this.editor || !this.editor.view) return;
+
+ const view = this.editor.view;
+ const maxPos = view.state.doc.content.size;
+ const safePos = Math.min(Math.max(0, position), maxPos);
+ const contentNode = asHtml ? this.parseHtmlContent(content) : view.state.schema.text(content);
+
+ if (contentNode) {
+ const transaction = view.state.tr.insert(safePos, contentNode);
+ view.dispatch(transaction);
+ this.onChange(this.editor.value);
}
+ }
- /**
- * Inserts HTML content before the current selection
- * @param content - HTML string to insert
- * @param asHtml - If true, parses as HTML; if false, inserts as plain text
- */
- public insertBeforeSelection(content: string, asHtml: boolean = false): void {
- if (!this.editor || !this.editor.view) return;
+ /**
+ * Replaces text in a specific range
+ * @param content - HTML string to insert
+ * @param from - Start position
+ * @param to - End position
+ * @param asHtml - If true, parses as HTML; if false, inserts as plain text
+ */
+ public replaceRange(content: string, from: number, to: number, asHtml: boolean = false): void {
+ if (!this.editor || !this.editor.view) return;
- const view = this.editor.view;
- const { from } = view.state.selection;
- const contentNode = asHtml ? this.parseHtmlContent(content) : view.state.schema.text(content);
+ const view = this.editor.view;
+ const maxPos = view.state.doc.content.size;
+ const safeFrom = Math.min(Math.max(0, from), maxPos);
+ const safeTo = Math.min(Math.max(safeFrom, to), maxPos);
+ const contentNode = asHtml ? this.parseHtmlContent(content) : view.state.schema.text(content);
- if (contentNode) {
- const transaction = view.state.tr.insert(from, contentNode);
- view.dispatch(transaction);
- this.onValueChanged(this.editor.value);
- }
- }
-
- /**
- * Inserts HTML content after the current selection
- * @param content - HTML string to insert
- * @param asHtml - If true, parses as HTML; if false, inserts as plain text
- */
- public insertAfterSelection(content: string, asHtml: boolean = false): void {
- if (!this.editor || !this.editor.view) return;
-
- const view = this.editor.view;
- const { to } = view.state.selection;
- const contentNode = asHtml ? this.parseHtmlContent(content) : view.state.schema.text(content);
-
- if (contentNode) {
- const transaction = view.state.tr.insert(to, contentNode);
- view.dispatch(transaction);
- this.onValueChanged(this.editor.value);
- }
- }
-
- /**
- * Replaces the currently selected text with new content
- * @param content - HTML string to replace selection with
- * @param asHtml - If true, parses as HTML; if false, inserts as plain text
- */
- public replaceSelectedText(content: string, asHtml: boolean = false): void {
- if (!this.editor || !this.editor.view) return;
-
- const view = this.editor.view;
- const { from, to } = view.state.selection;
- const contentNode = asHtml ? this.parseHtmlContent(content) : view.state.schema.text(content);
-
- if (!contentNode) return;
-
- // If there's no selection, just insert at cursor position
- if (from === to) {
- const transaction = view.state.tr.insert(from, contentNode);
- view.dispatch(transaction);
- } else {
- // Replace the selected content
- const transaction = view.state.tr.replaceWith(from, to, contentNode);
- view.dispatch(transaction);
- }
- this.onValueChanged(this.editor.value);
- }
-
- /**
- * Gets the currently selected text in the editor
- * @returns The selected text as a string
- */
- public getSelectedText(): string {
- if (!this.editor) return '';
- return this.editor.selectionText || '';
- }
- public getSelectionTextOrWholeText(): string {
- if (!this.editor) return '';
-
- // If there's selected text, return it
- if (this.editor.selectionText && this.editor.selectionText.trim().length > 0) {
- return this.editor.selectionText;
- }
-
- // Otherwise, get the whole text content from the editor's document
- if (this.editor.view && this.editor.view.state) {
- return this.editor.view.state.doc.textContent;
- }
-
- // Fallback: strip HTML tags and return plain text
- const div = document.createElement('div');
- div.innerHTML = this.editor.value;
- return div.textContent || div.innerText || '';
- }
-
- /**
- * Gets the current cursor position or selection range
- * @returns Object with 'from' and 'to' positions
- */
- public getSelectionRange(): { from: number; to: number } | null {
- if (!this.editor || !this.editor.view) return null;
-
- const { from, to } = this.editor.view.state.selection;
- return { from, to };
- }
-
- /**
- * Inserts HTML content at a specific position
- * @param content - HTML string to insert
- * @param position - Position to insert at (0 = beginning)
- * @param asHtml - If true, parses as HTML; if false, inserts as plain text
- */
- public insertAtPosition(content: string, position: number, asHtml: boolean = false): void {
- if (!this.editor || !this.editor.view) return;
-
- const view = this.editor.view;
- const maxPos = view.state.doc.content.size;
- const safePos = Math.min(Math.max(0, position), maxPos);
- const contentNode = asHtml ? this.parseHtmlContent(content) : view.state.schema.text(content);
-
- if (contentNode) {
- const transaction = view.state.tr.insert(safePos, contentNode);
- view.dispatch(transaction);
- this.onValueChanged(this.editor.value);
- }
- }
-
- /**
- * Replaces text in a specific range
- * @param content - HTML string to insert
- * @param from - Start position
- * @param to - End position
- * @param asHtml - If true, parses as HTML; if false, inserts as plain text
- */
- public replaceRange(content: string, from: number, to: number, asHtml: boolean = false): void {
- if (!this.editor || !this.editor.view) return;
-
- const view = this.editor.view;
- const maxPos = view.state.doc.content.size;
- const safeFrom = Math.min(Math.max(0, from), maxPos);
- const safeTo = Math.min(Math.max(safeFrom, to), maxPos);
- const contentNode = asHtml ? this.parseHtmlContent(content) : view.state.schema.text(content);
-
- if (contentNode) {
- const transaction = view.state.tr.replaceWith(safeFrom, safeTo, contentNode);
- view.dispatch(transaction);
- this.onValueChanged(this.editor.value);
- }
+ if (contentNode) {
+ const transaction = view.state.tr.replaceWith(safeFrom, safeTo, contentNode);
+ view.dispatch(transaction);
+ this.onChange(this.editor.value);
}
+ }
- showVariablePicker() {
- this.easyEditorService.openTableMultiPicker(this.variables, this.variableTableSettings, "Please select a variable").pipe(first()).subscribe(result => {
- if (result) {
- result.forEach(c => {
- this.insertAfterSelection(`<${RbjTagNode} class="rbj-tag" ${RbjTagIdAttribute}="${c.name}" ${RbjTagValueAttribute}="${c.name}">${c.name}${RbjTagNode}>`, true);
- });
- }
- });
- }
+ // showVariablePicker() {
+ // this.easyEditorService.openTableMultiPicker(this.variables, this.variableTableSettings, "Please select a variable").pipe(first()).subscribe(result => {
+ // if (result) {
+ // result.forEach(c => {
+ // this.insertAfterSelection(`<${RbjTagNode} class="rbj-tag" ${RbjTagIdAttribute}="${c.name}" ${RbjTagValueAttribute}="${c.name}">${c.name}${RbjTagNode}>`, true);
+ // });
+ // }
+ // });
+ // }
- // Private methods
- private createCustomSchema(): Schema {
- let nodes = schema.spec.nodes.addBefore("div", "rbjTag", rbjTagNodeSpec);
- let marks = schema.spec.marks;
- //marks = marks.addToStart("rbjSpanTag", rbjTagMarkSpec);
- return new Schema({
- nodes: nodes,
- marks: marks
- });
- }
+ // Private methods
+ private createCustomSchema(): Schema {
+ let nodes = schema.spec.nodes.addBefore("div", "rbjTag", rbjTagNodeSpec);
+ let marks = schema.spec.marks;
+ //marks = marks.addToStart("rbjSpanTag", rbjTagMarkSpec);
+ return new Schema({
+ nodes: nodes,
+ marks: marks
+ });
+ }
}
// Define the custom node specification for the rbj-tag element.
export const rbjTagNodeSpec: NodeSpec = {
- // Define the node attributes for the tag
- attrs: {
- "rbj-tag-id": { default: "" },
- "tag-value": { default: "" },
- "tag-preview": { default: "" }
- },
- // Specify that this node should be treated as an inline element
- inline: true,
- // Allow the node to be part of inline content
- group: "inline",
- // Make it atomic (non-editable, treated as a single unit)
- atom: true,
+ // Define the node attributes for the tag
+ attrs: {
+ "md2-icon": { default: "" },
+ "class": { default: "" },
+ // "tag-value": { default: "" },
+ // "tag-preview": { default: "" }
+ },
+ // Specify that this node should be treated as an inline element
+ inline: true,
+ // Allow the node to be part of inline content
+ group: "inline",
+ // Make it atomic (non-editable, treated as a single unit)
+ atom: true,
- // Define how the node should be rendered in the DOM
- toDOM: (node) => {
- let tagPreview = node.attrs["tag-preview"];
- let displayValue = tagPreview == 'true' ? node.attrs["tag-value"] : node.attrs["rbj-tag-id"];
+ // Define how the node should be rendered in the DOM
+ toDOM: (node) => {
+ let md2IconText = node.attrs["md2-icon"] as string;
+ let classValue = node.attrs["class"] as string;
+ if (classValue.includes('dice')) {
+ md2IconText = '';
+ }
+ // let displayValue = tagPreview == 'true' ? node.attrs["tag-value"] : node.attrs["rbj-tag-id"];
- return [
- "span",
- {
- class: "rbj-tag",
- "rbj-tag-id": node.attrs["rbj-tag-id"],
- "tag-marker": node.attrs["tag-marker"],
- "tag-value": node.attrs["tag-value"],
- "tag-preview": node.attrs["tag-preview"],
- //contenteditable: "false",
- //spellcheck: "false",
- style: "display: inline;"
- },
- //node.attrs["tag-marker"] + node.attrs["tag-value"] // Display the tag content directly
- displayValue
- ];
- },
+ return [
+ "span",
+ {
+ class: classValue,
+ // "rbj-tag-id": node.attrs["rbj-tag-id"],
+ // "tag-marker": node.attrs["tag-marker"],
+ // "tag-value": node.attrs["tag-value"],
+ // "tag-preview": node.attrs["tag-preview"],
+ contenteditable: "false",
+ //spellcheck: "false", style="font-size: 36px;"
+ style: "display: inline;"
+ },
+ //node.attrs["tag-marker"] + node.attrs["tag-value"] // Display the tag content directly
+ md2IconText
+ ];
+ },
- // Define how to parse the node from existing DOM elements
- parseDOM: [
- {
- // Look for span elements with class rbj-tag (higher priority)
- tag: "span[rbj-tag-id]",
- priority: 51, // Higher priority to catch before other parsers
- // Extract attributes from the DOM element
- getAttrs: (dom) => {
- const element = dom as HTMLElement;
- // Must have rbj-tag-id attribute to be valid
- if (!element.hasAttribute("rbj-tag-id")) {
- return false;
- }
- return {
- "rbj-tag-id": element.getAttribute("rbj-tag-id") || "",
- "tag-preview": element.getAttribute("tag-preview") || "false",
- "tag-value": element.getAttribute("tag-value") || element.getAttribute("rbj-tag-id")
- };
- }
- },
- {
- // Look for div elements with rbj-tag-id attribute (for backward compatibility)
- tag: "div[rbj-tag-id]",
- // Extract attributes from the DOM element
- getAttrs: (dom) => {
- const element = dom as HTMLElement;
- return {
- "rbj-tag-id": element.getAttribute("rbj-tag-id") || "",
- "tag-preview": element.getAttribute("tag-preview") || "false",
- "tag-value": element.getAttribute("tag-value") || element.getAttribute("rbj-tag-id")
- };
- }
+ // Define how to parse the node from existing DOM elements
+ parseDOM: [
+ {
+ // Look for span elements with class rbj-tag (higher priority)
+ tag: "span[md2-icon]",
+ priority: 51, // Higher priority to catch before other parsers
+ // Extract attributes from the DOM element
+ getAttrs: (dom) => {
+ const element = dom as HTMLElement;
+ // Must have rbj-tag-id attribute to be valid
+ if (!element.hasAttribute("md2-icon")) {
+ return false;
}
- ]
+ return {
+ "md2-icon": element.getAttribute("md2-icon") || "",
+ "class": element.className || "",
+ // "tag-preview": element.getAttribute("tag-preview") || "false",
+ // "tag-value": element.getAttribute("tag-value") || element.getAttribute("rbj-tag-id")
+ };
+ }
+ }
+ ]
};
\ No newline at end of file
diff --git a/src/app/games/massive-darkness2/md2-html-editor/md2-icon-picker-dlg.component.ts b/src/app/games/massive-darkness2/md2-html-editor/md2-icon-picker-dlg.component.ts
index a0aefe5..c41703d 100644
--- a/src/app/games/massive-darkness2/md2-html-editor/md2-icon-picker-dlg.component.ts
+++ b/src/app/games/massive-darkness2/md2-html-editor/md2-icon-picker-dlg.component.ts
@@ -4,18 +4,18 @@ import { MD2Icon } from '../massive-darkness2.model';
import { MD2StateService } from '../../../services/MD2/md2-state.service';
@Component({
- selector: 'md2-icon-picker-dlg',
- template: `
+ selector: 'md2-icon-picker-dlg',
+ template: `
Insert MD2 Icon
-
+
@@ -25,13 +25,14 @@ import { MD2StateService } from '../../../services/MD2/md2-state.service';
`,
- styles: [`
- .icon-grid {
+ styles: [`
+ .md2-icon-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(60px, 1fr));
gap: 10px;
max-height: 400px;
overflow-y: auto;
+ width:400px;
}
.icon-item {
cursor: pointer;
@@ -42,40 +43,41 @@ import { MD2StateService } from '../../../services/MD2/md2-state.service';
border: 1px solid #ddd;
border-radius: 4px;
transition: all 0.2s;
+ font-size: 30px;
}
.icon-item:hover {
background-color: #f0f0f0;
border-color: #007bff;
- transform: scale(1.1);
+ //transform: scale(1.1);
}
`]
})
export class MD2IconPickerDlgComponent implements OnInit {
- iconList: Array<{ icon: MD2Icon, name: string, html: string }> = [];
+ iconList: Array<{ icon: MD2Icon, name: string, html: string }> = [];
- constructor(
- private dlgRef: NbDialogRef
,
- private md2StateService: MD2StateService
- ) { }
+ constructor(
+ private dlgRef: NbDialogRef,
+ private md2StateService: MD2StateService
+ ) { }
- ngOnInit(): void {
- // Get all icons
- for (let icon of Object.values(MD2Icon).filter(val => typeof val === 'number') as MD2Icon[]) {
- this.iconList.push({
- icon: icon,
- name: MD2Icon[icon],
- html: this.md2StateService.iconHtml(icon)
- });
- }
+ ngOnInit(): void {
+ // Get all icons
+ for (let icon of Object.values(MD2Icon).filter(val => typeof val === 'number') as MD2Icon[]) {
+ this.iconList.push({
+ icon: icon,
+ name: MD2Icon[icon],
+ html: this.md2StateService.iconHtml(icon)
+ });
}
+ }
- selectIcon(iconData: { icon: MD2Icon, name: string, html: string }) {
- this.dlgRef.close(iconData.html);
- }
+ selectIcon(iconData: { icon: MD2Icon, name: string, html: string }) {
+ this.dlgRef.close(iconData.html);
+ }
- cancel() {
- this.dlgRef.close(null);
- }
+ cancel() {
+ this.dlgRef.close(null);
+ }
}
diff --git a/src/app/games/massive-darkness2/mobs/mobs.component.ts b/src/app/games/massive-darkness2/mobs/mobs.component.ts
index e33c853..7190cd1 100644
--- a/src/app/games/massive-darkness2/mobs/mobs.component.ts
+++ b/src/app/games/massive-darkness2/mobs/mobs.component.ts
@@ -1,7 +1,6 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { NbDialogService } from '@nebular/theme';
-import { stringify } from 'querystring';
import { first } from 'rxjs/operators';
import { DropDownOption } from '../../../entity/dropDownOption';
import { FileService } from '../../../services/file.service';
@@ -10,7 +9,6 @@ import { MD2Service } from '../../../services/MD2/md2.service';
import { MsgBoxService } from '../../../services/msg-box.service';
import { StateService } from '../../../services/state.service';
import { ADIcon } from '../../../ui/alert-dlg/alert-dlg.model';
-import { ArrayUtils } from '../../../utilities/array-utils';
import { NumberUtils } from '../../../utilities/number-utils';
import { StringUtils } from '../../../utilities/string-utils';
import { CoreGameMobFactories } from '../factorys/mobs/CoreGame';
diff --git a/src/app/services/MD2/md2-state.service.ts b/src/app/services/MD2/md2-state.service.ts
index 1f1c7a0..3ed0f90 100644
--- a/src/app/services/MD2/md2-state.service.ts
+++ b/src/app/services/MD2/md2-state.service.ts
@@ -31,9 +31,9 @@ export class MD2StateService {
cssClass += ' g-color-aqua ';
}
if (icon < MD2Icon.RedDice) {
- return `${String.fromCharCode(65 + icon)}`
+ return `${String.fromCharCode(65 + icon)}`
} else {
- return ``;
+ return ``;
}
}
diff --git a/src/app/services/crudServices/crud.service.ts b/src/app/services/crudServices/crud.service.ts
index ee372a5..b4f1592 100644
--- a/src/app/services/crudServices/crud.service.ts
+++ b/src/app/services/crudServices/crud.service.ts
@@ -177,166 +177,166 @@ export class CombinedKeyCrudService implements ICrudService {
);
}
-}
-// Type definitions
-type TextResponse = { message: string };
-/**
-* Base CRUD service that targets the provided controller path.
-*
-* It mirrors the endpoints of CrudBaseApiController:
-* GET /api/{controller}
-* GET /api/{controller}/{id}
-* POST /api/{controller} -> string
-* POST /api/{controller}/batch -> string[]
-* PUT /api/{controller}
-* PUT /api/{controller}/batch -> number
-* DELETE /api/{controller}/{id}
-* DELETE /api/{controller}/batch -> text summary
-* GET /api/{controller}/{id}/exists -> boolean
-* GET /api/{controller}/count -> number
-*/
-@Injectable({ providedIn: 'root' })
-export class CrudBaseApiService {
- /**
- * Example: baseUrl = 'https://your-api', controller = 'Customer' →
- * endpoint = 'https://your-api/api/Customer'
- */
- protected readonly endpoint: string;
-
-
- /**
- * @param http Angular HttpClient
- * @param baseUrl API root without trailing slash (e.g., environment.apiBaseUrl)
- * @param controllerName Controller name (e.g., 'Customer', 'Orders')
- */
- constructor(
- protected http: HttpClient,
- protected apiConfig: ApiConfigService,
- @Inject(String) private controllerName: string
- ) {
- this.endpoint = apiConfig.getApiUrl(this.controllerName);
- }
-
-
- /** Optional default headers (JSON). Override in subclasses if needed. */
- protected get jsonHeaders(): HttpHeaders {
- return new HttpHeaders({ 'Content-Type': 'application/json' });
- }
-
-
- /** Shared error handler that surfaces useful messages. */
- protected handleError(error: HttpErrorResponse): Observable {
- let msg = 'Unknown error';
- if (error.error instanceof Blob) {
- // In case backend returns text/plain; charset=utf-8 as Blob
- return throwError(() => new Error('Server returned an error blob'));
- }
- if (typeof error.error === 'string') msg = error.error;
- else if (error.error?.message) msg = error.error.message;
- else if (error.message) msg = error.message;
- return throwError(() => new Error(msg));
- }
- /** Prepare the response for the given entity. Override in subclasses if needed. */
- protected prepareResponse(response: T): T {
- // Do nothing by default
- return response;
- }
-
- /** GET /api/{controller} */
- getAll(): Observable {
- return this.http
- .get(this.endpoint)
- .pipe(
- map(response => {
-
- for (let i = 0; i < response.length; i++) {
- const element = response[i];
- response[i] = this.prepareResponse(element);
- }
- return response;
- }),
- catchError(err => this.handleError(err)));
- }
-
-
- /** GET /api/{controller}/{id} */
- getById(id: string): Observable {
- return this.http
- .get(`${this.endpoint}/${id}`)
- .pipe(
- map(response => this.prepareResponse(response)),
- catchError(err => this.handleError(err)));
- }
-
-
-
- /** POST /api/{controller} -> string */
- create(entity: T): Observable {
- return this.http
- .post(this.endpoint, entity, { headers: this.jsonHeaders })
- .pipe(catchError(err => this.handleError(err)));
- }
-
-
- /** POST /api/{controller}/batch -> string[] */
- createRange(entities: T[]): Observable {
- return this.http
- .post(`${this.endpoint}/batch`, entities, { headers: this.jsonHeaders })
- .pipe(catchError(err => this.handleError(err)));
- }
-
-
- /** PUT /api/{controller} */
- update(entity: T): Observable {
- return this.http
- .put(this.endpoint, entity, { headers: this.jsonHeaders })
- .pipe(catchError(err => this.handleError(err)));
- }
-
-
- /** PUT /api/{controller}/batch -> number (updated count) */
- updateRange(entities: T[]): Observable {
- return this.http
- .put(`${this.endpoint}/batch`, entities, { headers: this.jsonHeaders })
- .pipe(catchError(err => this.handleError(err)));
- }
-
-
- /** DELETE /api/{controller}/{id} */
- delete(id: string): Observable {
- return this.http
- .delete(`${this.endpoint}/${id}`)
- .pipe(catchError(err => this.handleError(err)));
- }
-
-
- /** DELETE /api/{controller}/batch -> text summary */
- deleteRange(ids: string[]): Observable {
- // API returns a plain text message; map it into a TextResponse for convenience
- return this.http
- .delete(`${this.endpoint}/batch`, {
- body: ids,
- headers: this.jsonHeaders
- })
- .pipe(
- map((response: any) => ({ message: response || 'Batch delete completed' })),
- catchError(err => this.handleError(err))
- );
- }
-
-
- /** GET /api/{controller}/{id}/exists -> boolean */
- exists(id: string): Observable {
- return this.http
- .get(`${this.endpoint}/${id}/exists`)
- .pipe(catchError(err => this.handleError(err)));
- }
-
-
- /** GET /api/{controller}/count -> number */
- count(): Observable {
- return this.http
- .get(`${this.endpoint}/count`)
- .pipe(catchError(err => this.handleError(err)));
- }
}
+// // Type definitions
+// type TextResponse = { message: string };
+// /**
+// * Base CRUD service that targets the provided controller path.
+// *
+// * It mirrors the endpoints of CrudBaseApiController:
+// * GET /api/{controller}
+// * GET /api/{controller}/{id}
+// * POST /api/{controller} -> string
+// * POST /api/{controller}/batch -> string[]
+// * PUT /api/{controller}
+// * PUT /api/{controller}/batch -> number
+// * DELETE /api/{controller}/{id}
+// * DELETE /api/{controller}/batch -> text summary
+// * GET /api/{controller}/{id}/exists -> boolean
+// * GET /api/{controller}/count -> number
+// */
+// @Injectable({ providedIn: 'root' })
+// export class CrudBaseApiService {
+// /**
+// * Example: baseUrl = 'https://your-api', controller = 'Customer' →
+// * endpoint = 'https://your-api/api/Customer'
+// */
+// protected readonly endpoint: string;
+
+
+// /**
+// * @param http Angular HttpClient
+// * @param baseUrl API root without trailing slash (e.g., environment.apiBaseUrl)
+// * @param controllerName Controller name (e.g., 'Customer', 'Orders')
+// */
+// constructor(
+// protected http: HttpClient,
+// protected apiConfig: ApiConfigService,
+// @Inject(String) private controllerName: string
+// ) {
+// this.endpoint = apiConfig.getApiUrl(this.controllerName);
+// }
+
+
+// /** Optional default headers (JSON). Override in subclasses if needed. */
+// protected get jsonHeaders(): HttpHeaders {
+// return new HttpHeaders({ 'Content-Type': 'application/json' });
+// }
+
+
+// /** Shared error handler that surfaces useful messages. */
+// protected handleError(error: HttpErrorResponse): Observable {
+// let msg = 'Unknown error';
+// if (error.error instanceof Blob) {
+// // In case backend returns text/plain; charset=utf-8 as Blob
+// return throwError(() => new Error('Server returned an error blob'));
+// }
+// if (typeof error.error === 'string') msg = error.error;
+// else if (error.error?.message) msg = error.error.message;
+// else if (error.message) msg = error.message;
+// return throwError(() => new Error(msg));
+// }
+// /** Prepare the response for the given entity. Override in subclasses if needed. */
+// protected prepareResponse(response: T): T {
+// // Do nothing by default
+// return response;
+// }
+
+// /** GET /api/{controller} */
+// getAll(): Observable {
+// return this.http
+// .get(this.endpoint)
+// .pipe(
+// map(response => {
+
+// for (let i = 0; i < response.length; i++) {
+// const element = response[i];
+// response[i] = this.prepareResponse(element);
+// }
+// return response;
+// }),
+// catchError(err => this.handleError(err)));
+// }
+
+
+// /** GET /api/{controller}/{id} */
+// getById(id: string): Observable {
+// return this.http
+// .get(`${this.endpoint}/${id}`)
+// .pipe(
+// map(response => this.prepareResponse(response)),
+// catchError(err => this.handleError(err)));
+// }
+
+
+
+// /** POST /api/{controller} -> string */
+// create(entity: T): Observable {
+// return this.http
+// .post(this.endpoint, entity, { headers: this.jsonHeaders })
+// .pipe(catchError(err => this.handleError(err)));
+// }
+
+
+// /** POST /api/{controller}/batch -> string[] */
+// createRange(entities: T[]): Observable {
+// return this.http
+// .post(`${this.endpoint}/batch`, entities, { headers: this.jsonHeaders })
+// .pipe(catchError(err => this.handleError(err)));
+// }
+
+
+// /** PUT /api/{controller} */
+// update(entity: T): Observable {
+// return this.http
+// .put(this.endpoint, entity, { headers: this.jsonHeaders })
+// .pipe(catchError(err => this.handleError(err)));
+// }
+
+
+// /** PUT /api/{controller}/batch -> number (updated count) */
+// updateRange(entities: T[]): Observable {
+// return this.http
+// .put(`${this.endpoint}/batch`, entities, { headers: this.jsonHeaders })
+// .pipe(catchError(err => this.handleError(err)));
+// }
+
+
+// /** DELETE /api/{controller}/{id} */
+// delete(id: string): Observable {
+// return this.http
+// .delete(`${this.endpoint}/${id}`)
+// .pipe(catchError(err => this.handleError(err)));
+// }
+
+
+// /** DELETE /api/{controller}/batch -> text summary */
+// deleteRange(ids: string[]): Observable {
+// // API returns a plain text message; map it into a TextResponse for convenience
+// return this.http
+// .delete(`${this.endpoint}/batch`, {
+// body: ids,
+// headers: this.jsonHeaders
+// })
+// .pipe(
+// map((response: any) => ({ message: response || 'Batch delete completed' })),
+// catchError(err => this.handleError(err))
+// );
+// }
+
+
+// /** GET /api/{controller}/{id}/exists -> boolean */
+// exists(id: string): Observable {
+// return this.http
+// .get(`${this.endpoint}/${id}/exists`)
+// .pipe(catchError(err => this.handleError(err)));
+// }
+
+
+// /** GET /api/{controller}/count -> number */
+// count(): Observable {
+// return this.http
+// .get(`${this.endpoint}/count`)
+// .pipe(catchError(err => this.handleError(err)));
+// }
+// }
diff --git a/src/app/utilities/string-utils.ts b/src/app/utilities/string-utils.ts
index e46bba8..ead02be 100644
--- a/src/app/utilities/string-utils.ts
+++ b/src/app/utilities/string-utils.ts
@@ -1,7 +1,6 @@
//import { FtTagType } from "../components/fancy-table/fancy-row-column.model";
//import { AddressInfo } from "../models/contactInfo.model";
-import { stringify } from "querystring";
import { AddressInfo } from "../entity/PastoralDomain";
export class StringUtils {
diff --git a/src/assets/styles/md2.scss b/src/assets/styles/md2.scss
index 818aeae..2d1f32e 100644
--- a/src/assets/styles/md2.scss
+++ b/src/assets/styles/md2.scss
@@ -41,6 +41,7 @@
}
.MD2Icon {
font-family: "Massive Darkness 2", sans-serif !important;
+ //font-size: 20px;
//font-size: 50px;
&.attack::before {
diff --git a/src/index.html b/src/index.html
index 4059b9a..a48fc8f 100644
--- a/src/index.html
+++ b/src/index.html
@@ -31,6 +31,9 @@
+
+
+
diff --git a/src/main.ts b/src/main.ts
index 8fd0e9d..ebfedc1 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -1,3 +1,5 @@
+///
+
/**
* @license
* Copyright Akveo. All Rights Reserved.
diff --git a/src/polyfills.ts b/src/polyfills.ts
index 9ca8e90..8aeb789 100644
--- a/src/polyfills.ts
+++ b/src/polyfills.ts
@@ -40,7 +40,7 @@ import 'zone.js'; // Included with Angular CLI.
*/
import 'core-js/es7/array';
import 'core-js/es7/object';
-
+import '@angular/localize/init';
if (typeof SVGElement.prototype.contains === 'undefined') {
SVGElement.prototype.contains = HTMLDivElement.prototype.contains;
}
diff --git a/src/tsconfig.app.json b/src/tsconfig.app.json
index ba21981..ab90245 100644
--- a/src/tsconfig.app.json
+++ b/src/tsconfig.app.json
@@ -2,7 +2,10 @@
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
- "baseUrl": "./"
+ "baseUrl": "./",
+ "types": [
+ "@angular/localize"
+ ]
},
"files": [
"main.ts",
diff --git a/src/tsconfig.spec.json b/src/tsconfig.spec.json
index c89454b..aff19d9 100644
--- a/src/tsconfig.spec.json
+++ b/src/tsconfig.spec.json
@@ -5,7 +5,8 @@
"baseUrl": "./",
"types": [
"jasmine",
- "node"
+ "node",
+ "@angular/localize"
]
},
"files": [