ngx-emfular-tool 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # NgxEmfularHelper
2
+
3
+ This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 19.2.0.
4
+
5
+ ## Code scaffolding
6
+
7
+ Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
8
+
9
+ ```bash
10
+ ng generate component component-name
11
+ ```
12
+
13
+ For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
14
+
15
+ ```bash
16
+ ng generate --help
17
+ ```
18
+
19
+ ## Building
20
+
21
+ To build the library, run:
22
+
23
+ ```bash
24
+ ng build tool
25
+ ```
26
+
27
+ This command will compile your project, and the build artifacts will be placed in the `dist/` directory.
28
+
29
+ ### Publishing the Library
30
+
31
+ Once the project is built, you can publish your library by following these steps:
32
+
33
+ 1. Navigate to the `dist` directory:
34
+ ```bash
35
+ cd dist/tool
36
+ ```
37
+
38
+ 2. Run the `npm publish` command to publish your library to the npm registry:
39
+ ```bash
40
+ npm publish
41
+ ```
42
+
43
+ ## Running unit tests
44
+
45
+ To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
46
+
47
+ ```bash
48
+ ng test
49
+ ```
50
+
51
+ ## Running end-to-end tests
52
+
53
+ For end-to-end (e2e) testing, run:
54
+
55
+ ```bash
56
+ ng e2e
57
+ ```
58
+
59
+ Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
60
+
61
+ ## Additional Resources
62
+
63
+ For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
@@ -0,0 +1,333 @@
1
+ import { __decorate, __param } from 'tslib';
2
+ import { BehaviorSubject } from 'rxjs';
3
+ import * as i0 from '@angular/core';
4
+ import { Inject, PLATFORM_ID, Component, Injectable } from '@angular/core';
5
+ import { isPlatformBrowser } from '@angular/common';
6
+ import { MatIcon } from '@angular/material/icon';
7
+ import * as i1 from '@angular/material/dialog';
8
+
9
+ let HistoryService = class HistoryService {
10
+ // history in a circular buffer
11
+ //bufferSize entries: entries are 0 to bufferSize-1, -1 is not defined
12
+ prefix;
13
+ bufferSize;
14
+ oldestEntryName;
15
+ newestEntryName;
16
+ currentEntryName;
17
+ oldestEntry = -1;
18
+ newestEntry = -1;
19
+ currentEntry = -1;
20
+ stateSubject = new BehaviorSubject(null);
21
+ state$ = this.stateSubject.asObservable();
22
+ constructor(prefix = 'history_', bufferSize = 50, platformId) {
23
+ this.prefix = prefix;
24
+ this.oldestEntryName = prefix + 'oldestEntry';
25
+ this.newestEntryName = prefix + 'newestEntry';
26
+ this.currentEntryName = prefix + 'currentEntry';
27
+ this.bufferSize = bufferSize;
28
+ if (isPlatformBrowser(platformId)) {
29
+ this.init();
30
+ }
31
+ }
32
+ init() {
33
+ this.oldestEntry = this.readNumber(this.oldestEntryName);
34
+ this.newestEntry = this.readNumber(this.newestEntryName);
35
+ this.currentEntry = this.readNumber(this.currentEntryName);
36
+ if (this.oldestEntry == -1 || this.newestEntry == -1 || this.currentEntry == -1) {
37
+ this.clearHistory();
38
+ }
39
+ else {
40
+ let entry = this.loadFromStorage(this.currentEntry);
41
+ this.stateSubject.next(entry);
42
+ }
43
+ }
44
+ clearHistory() {
45
+ this.oldestEntry = -1;
46
+ this.newestEntry = -1;
47
+ this.currentEntry = -1;
48
+ this.saveNumber(this.oldestEntryName, this.oldestEntry);
49
+ this.saveNumber(this.newestEntryName, this.newestEntry);
50
+ this.saveNumber(this.currentEntryName, this.currentEntry);
51
+ for (let i = 1; i < this.bufferSize; i++) {
52
+ this.deleteEntry(i);
53
+ }
54
+ }
55
+ save(elem) {
56
+ // needs to invalidate any element between the newest Entry and the current Entry, then save new Entry
57
+ this.invalidateTooYoungEntries();
58
+ // also remove one oldest entry if you need to make space
59
+ let next = this.incrementNumber(this.currentEntry);
60
+ if (next == this.oldestEntry || this.oldestEntry == -1) {
61
+ this.invalidateOldestEntry();
62
+ }
63
+ this.newestEntry = next;
64
+ this.currentEntry = next;
65
+ this.saveNumber(this.newestEntryName, this.newestEntry);
66
+ this.saveNumber(this.currentEntryName, this.currentEntry);
67
+ this.saveToStorage(next, elem);
68
+ }
69
+ undo() {
70
+ if (this.currentEntry == this.oldestEntry) { //current Entry is oldest, no decrement possible
71
+ console.error("Cannot undo - already reached oldest entry");
72
+ return null;
73
+ }
74
+ else {
75
+ this.currentEntry = this.decrementNumber(this.currentEntry);
76
+ this.saveNumber(this.currentEntryName, this.currentEntry);
77
+ let entry = this.loadFromStorage(this.currentEntry);
78
+ this.stateSubject.next(entry);
79
+ return entry;
80
+ }
81
+ }
82
+ isUndoNotPossible() {
83
+ return (this.currentEntry == this.oldestEntry);
84
+ }
85
+ redo() {
86
+ if (this.currentEntry == this.newestEntry) {
87
+ console.error("Cannot redo - already reached newest entry");
88
+ return null;
89
+ }
90
+ else {
91
+ this.currentEntry = this.incrementNumber(this.currentEntry);
92
+ this.saveNumber(this.currentEntryName, this.currentEntry);
93
+ let entry = this.loadFromStorage(this.currentEntry);
94
+ this.stateSubject.next(entry);
95
+ return entry;
96
+ }
97
+ }
98
+ isRedoNotPossible() {
99
+ return (this.currentEntry == this.newestEntry);
100
+ }
101
+ loadFromStorage(index) {
102
+ let itemString = localStorage.getItem(this.prefix + index);
103
+ if (itemString == null) {
104
+ return null;
105
+ }
106
+ else {
107
+ return JSON.parse(itemString);
108
+ }
109
+ }
110
+ saveToStorage(index, elem) {
111
+ localStorage.setItem(this.prefix + index, JSON.stringify(elem));
112
+ }
113
+ deleteEntry(index) {
114
+ localStorage.removeItem(this.prefix + index);
115
+ }
116
+ invalidateTooYoungEntries() {
117
+ while (this.newestEntry != this.currentEntry) {
118
+ this.deleteEntry(this.newestEntry);
119
+ this.newestEntry = this.decrementNumber(this.newestEntry);
120
+ }
121
+ this.saveNumber(this.newestEntryName, this.newestEntry);
122
+ }
123
+ invalidateOldestEntry() {
124
+ this.deleteEntry(this.oldestEntry);
125
+ this.oldestEntry = this.incrementNumber(this.oldestEntry);
126
+ this.saveNumber(this.oldestEntryName, this.oldestEntry);
127
+ }
128
+ readNumber(name) {
129
+ let maybeN = localStorage.getItem(name);
130
+ if (maybeN) {
131
+ return parseInt(maybeN, 10);
132
+ }
133
+ else {
134
+ return -1;
135
+ }
136
+ }
137
+ saveNumber(name, num) {
138
+ localStorage.setItem(name, num.toString(10));
139
+ }
140
+ decrementNumber(num) {
141
+ if (num === 0)
142
+ return this.bufferSize - 1;
143
+ else
144
+ return num - 1;
145
+ }
146
+ incrementNumber(num) {
147
+ if (num === this.bufferSize - 1)
148
+ return 0;
149
+ else
150
+ return num + 1;
151
+ }
152
+ };
153
+ HistoryService = __decorate([
154
+ __param(2, Inject(PLATFORM_ID))
155
+ ], HistoryService);
156
+
157
+ class AlertComponent {
158
+ dialogRef;
159
+ message;
160
+ constructor(dialogRef) {
161
+ this.dialogRef = dialogRef;
162
+ }
163
+ closeMe() {
164
+ this.dialogRef.close();
165
+ }
166
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: AlertComponent, deps: [{ token: i1.MatDialogRef }], target: i0.ɵɵFactoryTarget.Component });
167
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.25", type: AlertComponent, isStandalone: true, selector: "alert-component", ngImport: i0, template: "<div style=\"text-align: center\">\n <h3>Warning</h3>\n <p>{{message}}</p>\n <button class=\"tool-button-text\" (click)=\"closeMe()\">\n <mat-icon aria-hidden=\"false\" fontIcon=\"check\"></mat-icon>\n Ok\n </button>\n</div>\n", styles: [".tool-button-text{margin:1rem;text-align:center;vertical-align:middle;color:orange;height:3rem;width:6rem;background:#fff;border:2px solid orange;border-radius:4px}.tool-button-text:hover{box-shadow:0 12px 16px #0000003d,0 17px 50px #00000030}\n"], dependencies: [{ kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] });
168
+ }
169
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: AlertComponent, decorators: [{
170
+ type: Component,
171
+ args: [{ selector: 'alert-component', imports: [
172
+ MatIcon,
173
+ ], template: "<div style=\"text-align: center\">\n <h3>Warning</h3>\n <p>{{message}}</p>\n <button class=\"tool-button-text\" (click)=\"closeMe()\">\n <mat-icon aria-hidden=\"false\" fontIcon=\"check\"></mat-icon>\n Ok\n </button>\n</div>\n", styles: [".tool-button-text{margin:1rem;text-align:center;vertical-align:middle;color:orange;height:3rem;width:6rem;background:#fff;border:2px solid orange;border-radius:4px}.tool-button-text:hover{box-shadow:0 12px 16px #0000003d,0 17px 50px #00000030}\n"] }]
174
+ }], ctorParameters: () => [{ type: i1.MatDialogRef }] });
175
+
176
+ class AlertService {
177
+ dialog;
178
+ static instance;
179
+ constructor(dialog) {
180
+ this.dialog = dialog;
181
+ AlertService.instance = this;
182
+ }
183
+ alert(msg) {
184
+ const dialogRef = this.dialog.open(AlertComponent, { width: '20%', height: '30%' });
185
+ dialogRef.componentInstance.message = msg;
186
+ }
187
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: AlertService, deps: [{ token: i1.MatDialog }], target: i0.ɵɵFactoryTarget.Injectable });
188
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: AlertService, providedIn: 'root' });
189
+ }
190
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: AlertService, decorators: [{
191
+ type: Injectable,
192
+ args: [{
193
+ providedIn: 'root'
194
+ }]
195
+ }], ctorParameters: () => [{ type: i1.MatDialog }] });
196
+
197
+ class InputHandler {
198
+ //helps with converting an event from a number input (!) into a number...
199
+ // should be called on (input) while (ngModelChange) delivers the value immediately on $event
200
+ static getNewValueFromEvent($event) {
201
+ const input = $event.target;
202
+ return Number(input.value);
203
+ }
204
+ // this needs to be called on all input elements to allow them to accept the same value twice
205
+ static clearElem(event) {
206
+ let target = event.target;
207
+ target.value = '';
208
+ }
209
+ }
210
+
211
+ class IoService {
212
+ constructor() { }
213
+ async loadStringFromFile(event) {
214
+ const target = event.target;
215
+ const files = target.files;
216
+ return files[0].text();
217
+ }
218
+ saveFile(contentBlob, fileName) {
219
+ const link = document.createElement('a');
220
+ link.style.display = 'none';
221
+ // Attach the content to the anchor
222
+ link.href = URL.createObjectURL(contentBlob);
223
+ link.download = fileName;
224
+ // Append to DOM and simulate click (this will trigger the download)
225
+ document.body.appendChild(link);
226
+ link.click();
227
+ // Cleanup
228
+ document.body.removeChild(link);
229
+ }
230
+ saveJson(json, title) {
231
+ const contentBlob = new Blob([json], { type: 'application/json' });
232
+ this.saveFile(contentBlob, title + '.json');
233
+ }
234
+ cleanCopySVGAsBlob(svg) {
235
+ const clonedSvg = svg.cloneNode(true);
236
+ clonedSvg.removeAttribute('ng-version'); // remove Angular artifacts
237
+ const svgText = new XMLSerializer().serializeToString(clonedSvg);
238
+ return new Blob([svgText], { type: 'image/svg+xml' });
239
+ }
240
+ saveSVG(svgContent, title) {
241
+ const contentBlob = this.cleanCopySVGAsBlob(svgContent);
242
+ this.saveFile(contentBlob, title + '.svg');
243
+ }
244
+ saveSvgAsPng(svgContent, title) {
245
+ const contentBlob = this.cleanCopySVGAsBlob(svgContent);
246
+ this.convertSvgBlobToPngOrJpegAndDownload(contentBlob, title, true);
247
+ }
248
+ saveSvgAsJpeg(svgContent, title) {
249
+ const contentBlob = this.cleanCopySVGAsBlob(svgContent);
250
+ this.convertSvgBlobToPngOrJpegAndDownload(contentBlob, title, false);
251
+ }
252
+ convertSvgBlobToPngOrJpegAndDownload(svgBlob, title, usePng) {
253
+ const reader = new FileReader();
254
+ reader.onload = () => {
255
+ const svgText = reader.result;
256
+ const img = new Image();
257
+ const svgBase64 = btoa(new TextEncoder()
258
+ .encode(svgText)
259
+ .reduce((data, byte) => data + String.fromCharCode(byte), ''));
260
+ img.src = `data:image/svg+xml;base64,${svgBase64}`;
261
+ img.onload = () => {
262
+ this.loadImgToCanvas(img, title, usePng);
263
+ };
264
+ img.onerror = (err) => {
265
+ console.error('Error loading SVG image:', err);
266
+ };
267
+ };
268
+ reader.onerror = (err) => {
269
+ console.error('Error reading SVG blob:', err);
270
+ };
271
+ reader.readAsText(svgBlob);
272
+ }
273
+ canvasToPng(canvas, fileName) {
274
+ canvas.toBlob((pngBlob) => {
275
+ if (!pngBlob) {
276
+ console.error('Failed to convert canvas to PNG blob');
277
+ return;
278
+ }
279
+ else {
280
+ this.saveFile(pngBlob, fileName + '.png');
281
+ }
282
+ }, 'image/png');
283
+ }
284
+ canvasToJpeg(canvas, fileName) {
285
+ canvas.toBlob((jpgBlob) => {
286
+ if (!jpgBlob) {
287
+ console.error('Failed to convert canvas to JPEG blob');
288
+ return;
289
+ }
290
+ else {
291
+ this.saveFile(jpgBlob, fileName + '.jpeg');
292
+ }
293
+ }, 'image/jpeg', 1);
294
+ }
295
+ loadImgToCanvas(img, fileName, usePng = true) {
296
+ const canvas = document.createElement('canvas');
297
+ canvas.width = img.width;
298
+ canvas.height = img.height;
299
+ const ctx = canvas.getContext('2d');
300
+ if (!ctx) {
301
+ console.error('Canvas context not available');
302
+ return;
303
+ }
304
+ ctx.fillStyle = '#ffffff'; // white
305
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
306
+ ctx.drawImage(img, 0, 0);
307
+ if (usePng) {
308
+ this.canvasToPng(canvas, fileName);
309
+ }
310
+ else {
311
+ this.canvasToJpeg(canvas, fileName);
312
+ }
313
+ }
314
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: IoService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
315
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: IoService, providedIn: 'root' });
316
+ }
317
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: IoService, decorators: [{
318
+ type: Injectable,
319
+ args: [{
320
+ providedIn: 'root'
321
+ }]
322
+ }], ctorParameters: () => [] });
323
+
324
+ /*
325
+ * Public API Surface of tool
326
+ */
327
+
328
+ /**
329
+ * Generated bundle index. Do not edit.
330
+ */
331
+
332
+ export { AlertComponent, AlertService, HistoryService, InputHandler, IoService };
333
+ //# sourceMappingURL=ngx-emfular-tool.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngx-emfular-tool.mjs","sources":["../../src/lib/history/history.service.ts","../../src/lib/alerting/alert/alert.component.ts","../../src/lib/alerting/alert/alert.component.html","../../src/lib/alerting/alert.service.ts","../../src/lib/io/input-handler.ts","../../src/lib/io/io.service.ts","../../src/public-api.ts","../../src/ngx-emfular-tool.ts"],"sourcesContent":["import {BehaviorSubject} from \"rxjs\";\nimport {Inject, PLATFORM_ID} from \"@angular/core\";\nimport { isPlatformBrowser } from \"@angular/common\";\n\nexport class HistoryService<T> {\n\n // history in a circular buffer\n //bufferSize entries: entries are 0 to bufferSize-1, -1 is not defined\n\n private readonly prefix: string;\n private readonly bufferSize: number;\n readonly oldestEntryName: string;\n readonly newestEntryName: string;\n readonly currentEntryName: string;\n private oldestEntry: number = -1;\n private newestEntry: number = -1;\n private currentEntry: number = -1;\n\n private stateSubject = new BehaviorSubject<T | null>(null);\n state$ = this.stateSubject.asObservable();\n\n constructor(\n prefix: string = 'history_',\n bufferSize: number = 50,\n @Inject(PLATFORM_ID) platformId: Object\n ) {\n this.prefix = prefix;\n this.oldestEntryName = prefix + 'oldestEntry';\n this.newestEntryName = prefix + 'newestEntry';\n this.currentEntryName = prefix + 'currentEntry';\n this.bufferSize = bufferSize;\n if (isPlatformBrowser(platformId)) {\n this.init()\n }\n }\n\n init() {\n this.oldestEntry = this.readNumber(this.oldestEntryName)\n this.newestEntry = this.readNumber(this.newestEntryName)\n this.currentEntry = this.readNumber(this.currentEntryName)\n if (this.oldestEntry == -1 || this.newestEntry == -1 || this.currentEntry == -1) {\n this.clearHistory()\n } else {\n let entry = this.loadFromStorage(this.currentEntry)\n this.stateSubject.next(entry)\n }\n }\n\n clearHistory() {\n this.oldestEntry = -1;\n this.newestEntry = -1;\n this.currentEntry = -1;\n this.saveNumber(this.oldestEntryName, this.oldestEntry)\n this.saveNumber(this.newestEntryName, this.newestEntry)\n this.saveNumber(this.currentEntryName, this.currentEntry)\n for (let i = 1; i < this.bufferSize; i++) {\n this.deleteEntry(i);\n }\n }\n\n save(elem: T) {\n // needs to invalidate any element between the newest Entry and the current Entry, then save new Entry\n this.invalidateTooYoungEntries()\n // also remove one oldest entry if you need to make space\n let next = this.incrementNumber(this.currentEntry)\n\n if (next == this.oldestEntry || this.oldestEntry == -1) {\n this.invalidateOldestEntry()\n }\n this.newestEntry = next\n this.currentEntry = next\n this.saveNumber(this.newestEntryName, this.newestEntry)\n this.saveNumber(this.currentEntryName, this.currentEntry)\n this.saveToStorage(next, elem)\n }\n\n undo(): T | null {\n if (this.currentEntry == this.oldestEntry) { //current Entry is oldest, no decrement possible\n console.error(\"Cannot undo - already reached oldest entry\")\n return null\n } else {\n this.currentEntry = this.decrementNumber(this.currentEntry)\n this.saveNumber(this.currentEntryName, this.currentEntry)\n let entry = this.loadFromStorage(this.currentEntry)\n this.stateSubject.next(entry)\n return entry\n }\n }\n\n isUndoNotPossible(): boolean {\n return (this.currentEntry == this.oldestEntry)\n }\n\n redo(): T | null {\n if (this.currentEntry == this.newestEntry) {\n console.error(\"Cannot redo - already reached newest entry\")\n return null\n } else {\n this.currentEntry = this.incrementNumber(this.currentEntry)\n this.saveNumber(this.currentEntryName, this.currentEntry)\n let entry = this.loadFromStorage(this.currentEntry)\n this.stateSubject.next(entry)\n return entry\n }\n }\n\n isRedoNotPossible(): boolean {\n return (this.currentEntry == this.newestEntry)\n }\n\n private loadFromStorage(index: number): T | null {\n let itemString = localStorage.getItem(this.prefix + index)\n if (itemString == null) {\n return null\n } else {\n return JSON.parse(itemString)\n }\n }\n\n private saveToStorage(index: number, elem: T): void {\n localStorage.setItem(this.prefix + index, JSON.stringify(elem))\n }\n\n private deleteEntry(index: number): void {\n localStorage.removeItem(this.prefix + index)\n }\n\n private invalidateTooYoungEntries(): void {\n while (this.newestEntry != this.currentEntry) {\n this.deleteEntry(this.newestEntry);\n this.newestEntry = this.decrementNumber(this.newestEntry)\n }\n this.saveNumber(this.newestEntryName, this.newestEntry)\n }\n\n private invalidateOldestEntry(): void {\n this.deleteEntry(this.oldestEntry)\n this.oldestEntry = this.incrementNumber(this.oldestEntry)\n this.saveNumber(this.oldestEntryName, this.oldestEntry)\n }\n\n private readNumber(name: string): number {\n let maybeN = localStorage.getItem(name)\n if (maybeN) {\n return parseInt(maybeN, 10)\n } else {\n return -1\n }\n }\n\n private saveNumber(name: string, num: number): void {\n localStorage.setItem(name, num.toString(10))\n }\n\n private decrementNumber(num: number): number {\n if (num === 0) return this.bufferSize-1\n else return num-1\n }\n\n private incrementNumber(num: number): number {\n if (num === this.bufferSize-1) return 0\n else return num+1\n }\n}\n","import { Component } from '@angular/core';\nimport {MatDialogRef} from \"@angular/material/dialog\";\nimport {MatIcon} from \"@angular/material/icon\";\n\n@Component({\n selector: 'alert-component',\n imports: [\n MatIcon,\n ],\n templateUrl: './alert.component.html',\n styleUrl: './alert.component.css'\n})\nexport class AlertComponent {\n\n public message!: string;\n\n constructor(\n public dialogRef: MatDialogRef<AlertComponent>\n ) {}\n\n closeMe(): void {\n this.dialogRef.close();\n }\n}\n","<div style=\"text-align: center\">\n <h3>Warning</h3>\n <p>{{message}}</p>\n <button class=\"tool-button-text\" (click)=\"closeMe()\">\n <mat-icon aria-hidden=\"false\" fontIcon=\"check\"></mat-icon>\n Ok\n </button>\n</div>\n","import { Injectable } from '@angular/core';\nimport {MatDialog} from \"@angular/material/dialog\";\nimport {AlertComponent} from \"./alert/alert.component\";\n\n@Injectable({\n providedIn: 'root'\n})\nexport class AlertService {\n\n static instance: AlertService;\n constructor(\n private dialog: MatDialog,\n ) {\n AlertService.instance = this;\n }\n\n\n alert(msg: string) {\n const dialogRef = this.dialog.open(\n AlertComponent,\n {width: '20%', height: '30%'}\n )\n dialogRef.componentInstance.message = msg;\n }\n}\n","export class InputHandler {\n\n //helps with converting an event from a number input (!) into a number...\n // should be called on (input) while (ngModelChange) delivers the value immediately on $event\n static getNewValueFromEvent($event: Event): number {\n const input = $event.target as HTMLInputElement;\n return Number(input.value);\n }\n\n // this needs to be called on all input elements to allow them to accept the same value twice\n static clearElem(event: Event) {\n let target = event.target as HTMLInputElement;\n target.value = ''\n }\n}\n","import {Injectable} from '@angular/core';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class IoService {\n\n constructor() { }\n\n async loadStringFromFile(event: Event): Promise<string> {\n const target = event.target as HTMLInputElement;\n const files = target.files as FileList;\n return files[0].text();\n }\n\n saveFile(contentBlob: Blob, fileName: string) {\n const link = document.createElement('a')\n link.style.display = 'none'\n // Attach the content to the anchor\n link.href = URL.createObjectURL(contentBlob);\n link.download = fileName;\n // Append to DOM and simulate click (this will trigger the download)\n document.body.appendChild(link);\n link.click();\n // Cleanup\n document.body.removeChild(link);\n }\n\n saveJson(json: string, title: string) {\n const contentBlob = new Blob([json], {type: 'application/json'});\n this.saveFile(contentBlob, title+'.json');\n }\n\n cleanCopySVGAsBlob(svg: SVGElement): Blob {\n const clonedSvg = svg.cloneNode(true) as SVGElement;\n clonedSvg.removeAttribute('ng-version'); // remove Angular artifacts\n const svgText = new XMLSerializer().serializeToString(clonedSvg);\n return new Blob([svgText], { type: 'image/svg+xml' });\n }\n\n saveSVG(svgContent: SVGElement, title: string) {\n const contentBlob = this.cleanCopySVGAsBlob(svgContent);\n this.saveFile(contentBlob, title+'.svg');\n }\n\n saveSvgAsPng(svgContent: SVGElement, title: string) {\n const contentBlob = this.cleanCopySVGAsBlob(svgContent);\n this.convertSvgBlobToPngOrJpegAndDownload(contentBlob, title, true);\n }\n\n saveSvgAsJpeg(svgContent: SVGElement, title: string) {\n const contentBlob = this.cleanCopySVGAsBlob(svgContent);\n this.convertSvgBlobToPngOrJpegAndDownload(contentBlob, title, false);\n }\n\n private convertSvgBlobToPngOrJpegAndDownload(svgBlob: Blob, title: string, usePng?: boolean): void {\n const reader = new FileReader();\n\n reader.onload = () => {\n const svgText = reader.result as string;\n\n const img = new Image();\n const svgBase64 = btoa(\n new TextEncoder()\n .encode(svgText)\n .reduce((data, byte) => data + String.fromCharCode(byte), '')\n )\n img.src = `data:image/svg+xml;base64,${svgBase64}`;\n\n img.onload = () => {\n this.loadImgToCanvas(img, title, usePng)\n }\n\n img.onerror = (err) => {\n console.error('Error loading SVG image:', err);\n };\n };\n\n reader.onerror = (err) => {\n console.error('Error reading SVG blob:', err);\n };\n\n reader.readAsText(svgBlob);\n }\n\n private canvasToPng(canvas: HTMLCanvasElement, fileName: string) {\n canvas.toBlob((pngBlob) => {\n if (!pngBlob) {\n console.error('Failed to convert canvas to PNG blob');\n return;\n } else {\n this.saveFile(pngBlob, fileName+'.png')\n }\n }, 'image/png');\n }\n\n private canvasToJpeg(canvas: HTMLCanvasElement, fileName: string) {\n canvas.toBlob((jpgBlob) => {\n if (!jpgBlob) {\n console.error('Failed to convert canvas to JPEG blob');\n return;\n } else {\n this.saveFile(jpgBlob, fileName+'.jpeg')\n }\n }, 'image/jpeg', 1);\n }\n\n private loadImgToCanvas(img: HTMLImageElement, fileName: string, usePng=true) {\n const canvas = document.createElement('canvas');\n canvas.width = img.width;\n canvas.height = img.height;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n console.error('Canvas context not available');\n return;\n }\n\n ctx.fillStyle = '#ffffff'; // white\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n ctx.drawImage(img, 0, 0);\n\n if(usePng) {\n this.canvasToPng(canvas, fileName);\n } else {\n this.canvasToJpeg(canvas, fileName);\n }\n }\n}\n","/*\n * Public API Surface of tool\n */\nexport * from './lib/history/history.service';\n\nexport * from './lib/alerting/alert.service';\nexport * from './lib/alerting/alert/alert.component';\n\nexport * from './lib/io/input-handler';\nexport * from './lib/io/io.service'","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
package/index.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ /// <amd-module name="ngx-emfular-tool" />
5
+ export * from './public-api';
@@ -0,0 +1,10 @@
1
+ import { MatDialogRef } from "@angular/material/dialog";
2
+ import * as i0 from "@angular/core";
3
+ export declare class AlertComponent {
4
+ dialogRef: MatDialogRef<AlertComponent>;
5
+ message: string;
6
+ constructor(dialogRef: MatDialogRef<AlertComponent>);
7
+ closeMe(): void;
8
+ static ɵfac: i0.ɵɵFactoryDeclaration<AlertComponent, never>;
9
+ static ɵcmp: i0.ɵɵComponentDeclaration<AlertComponent, "alert-component", never, {}, {}, never, never, true, never>;
10
+ }
@@ -0,0 +1,10 @@
1
+ import { MatDialog } from "@angular/material/dialog";
2
+ import * as i0 from "@angular/core";
3
+ export declare class AlertService {
4
+ private dialog;
5
+ static instance: AlertService;
6
+ constructor(dialog: MatDialog);
7
+ alert(msg: string): void;
8
+ static ɵfac: i0.ɵɵFactoryDeclaration<AlertService, never>;
9
+ static ɵprov: i0.ɵɵInjectableDeclaration<AlertService>;
10
+ }
@@ -0,0 +1,29 @@
1
+ export declare class HistoryService<T> {
2
+ private readonly prefix;
3
+ private readonly bufferSize;
4
+ readonly oldestEntryName: string;
5
+ readonly newestEntryName: string;
6
+ readonly currentEntryName: string;
7
+ private oldestEntry;
8
+ private newestEntry;
9
+ private currentEntry;
10
+ private stateSubject;
11
+ state$: import("rxjs").Observable<T>;
12
+ constructor(prefix: string, bufferSize: number, platformId: Object);
13
+ init(): void;
14
+ clearHistory(): void;
15
+ save(elem: T): void;
16
+ undo(): T | null;
17
+ isUndoNotPossible(): boolean;
18
+ redo(): T | null;
19
+ isRedoNotPossible(): boolean;
20
+ private loadFromStorage;
21
+ private saveToStorage;
22
+ private deleteEntry;
23
+ private invalidateTooYoungEntries;
24
+ private invalidateOldestEntry;
25
+ private readNumber;
26
+ private saveNumber;
27
+ private decrementNumber;
28
+ private incrementNumber;
29
+ }
@@ -0,0 +1,4 @@
1
+ export declare class InputHandler {
2
+ static getNewValueFromEvent($event: Event): number;
3
+ static clearElem(event: Event): void;
4
+ }
@@ -0,0 +1,17 @@
1
+ import * as i0 from "@angular/core";
2
+ export declare class IoService {
3
+ constructor();
4
+ loadStringFromFile(event: Event): Promise<string>;
5
+ saveFile(contentBlob: Blob, fileName: string): void;
6
+ saveJson(json: string, title: string): void;
7
+ cleanCopySVGAsBlob(svg: SVGElement): Blob;
8
+ saveSVG(svgContent: SVGElement, title: string): void;
9
+ saveSvgAsPng(svgContent: SVGElement, title: string): void;
10
+ saveSvgAsJpeg(svgContent: SVGElement, title: string): void;
11
+ private convertSvgBlobToPngOrJpegAndDownload;
12
+ private canvasToPng;
13
+ private canvasToJpeg;
14
+ private loadImgToCanvas;
15
+ static ɵfac: i0.ɵɵFactoryDeclaration<IoService, never>;
16
+ static ɵprov: i0.ɵɵInjectableDeclaration<IoService>;
17
+ }
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "ngx-emfular-tool",
3
+ "version": "1.0.0",
4
+ "description": "Small Angular library with helper schematics for EMFular, currently alerting, history, and io facilities",
5
+ "keywords": [
6
+ "EMFular",
7
+ "Angular",
8
+ "IO",
9
+ "alert"
10
+ ],
11
+ "author": {
12
+ "name": "Susanne Göbel",
13
+ "email": "goebel@uni-koblenz.de"
14
+ },
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/softlang/EMFular-tool"
18
+ },
19
+ "peerDependencies": {
20
+ "@angular/cdk": "^19.2.7",
21
+ "@angular/common": "^19.2.7",
22
+ "@angular/core": "^19.2.7",
23
+ "@angular/forms": "^19.2.7",
24
+ "@types/uuid": "^10.0.0",
25
+ "@angular/material": "^19.2.7"
26
+ },
27
+ "dependencies": {
28
+ "tslib": "^2.3.0"
29
+ },
30
+ "sideEffects": false,
31
+ "module": "fesm2022/ngx-emfular-tool.mjs",
32
+ "typings": "index.d.ts",
33
+ "exports": {
34
+ "./package.json": {
35
+ "default": "./package.json"
36
+ },
37
+ ".": {
38
+ "types": "./index.d.ts",
39
+ "default": "./fesm2022/ngx-emfular-tool.mjs"
40
+ }
41
+ }
42
+ }
@@ -0,0 +1,5 @@
1
+ export * from './lib/history/history.service';
2
+ export * from './lib/alerting/alert.service';
3
+ export * from './lib/alerting/alert/alert.component';
4
+ export * from './lib/io/input-handler';
5
+ export * from './lib/io/io.service';