turbogui-angular 20.8.0 → 20.10.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.
@@ -620,6 +620,45 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImpor
620
620
  args: [MAT_DIALOG_DATA]
621
621
  }] }] });
622
622
 
623
+ /**
624
+ * TurboGUI is A library that helps with the most common and generic UI elements and functionalities
625
+ *
626
+ * Website : -> http://www.turbogui.org
627
+ * License : -> Licensed under the Apache License, Version 2.0. You may not use this file except in compliance with the License.
628
+ * License Url : -> http://www.apache.org/licenses/LICENSE-2.0
629
+ * CopyRight : -> Copyright 2018 Edertone Advanded Solutions. https://www.edertone.com
630
+ */
631
+ /**
632
+ * A dialog component with an image that can be used to display any picture url
633
+ *
634
+ * We must specify the url in the data parameter when opening the dialog, and we can also specify the title
635
+ * by placing it at the first position of the texts array.
636
+ */
637
+ class DialogImageComponent extends DialogBaseComponent {
638
+ static { this.DIALOG_CLASS_NAME = 'DialogImageComponent'; }
639
+ constructor(elementRef, dialogRef, sanitizer, data) {
640
+ super(elementRef, dialogRef);
641
+ this.elementRef = elementRef;
642
+ this.dialogRef = dialogRef;
643
+ this.sanitizer = sanitizer;
644
+ this.data = data;
645
+ this.title = '';
646
+ if (data.texts.length > 0) {
647
+ this.title = data.texts[0];
648
+ }
649
+ this.safeUrl = this.sanitizer.bypassSecurityTrustResourceUrl(data.data);
650
+ }
651
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: DialogImageComponent, deps: [{ token: i0.ElementRef }, { token: i1.MatDialogRef }, { token: i2$1.DomSanitizer }, { token: MAT_DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component }); }
652
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.5", type: DialogImageComponent, isStandalone: true, selector: "tg-dialog-image", providers: [], usesInheritance: true, ngImport: i0, template: "<h2 *ngIf=\"title !== ''\">{{title}}</h2>\r\n\r\n<img [src]=\"safeUrl\" title=\"title\" alt=\"{{title}}\" />", styles: [":host{display:block;width:100%;height:100%}h2{margin-top:0;margin-bottom:25px;width:82%}iframe{width:100%;height:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); }
653
+ }
654
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: DialogImageComponent, decorators: [{
655
+ type: Component,
656
+ args: [{ selector: 'tg-dialog-image', imports: [CommonModule], providers: [], template: "<h2 *ngIf=\"title !== ''\">{{title}}</h2>\r\n\r\n<img [src]=\"safeUrl\" title=\"title\" alt=\"{{title}}\" />", styles: [":host{display:block;width:100%;height:100%}h2{margin-top:0;margin-bottom:25px;width:82%}iframe{width:100%;height:100%}\n"] }]
657
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i1.MatDialogRef }, { type: i2$1.DomSanitizer }, { type: undefined, decorators: [{
658
+ type: Inject,
659
+ args: [MAT_DIALOG_DATA]
660
+ }] }] });
661
+
623
662
  /**
624
663
  * TurboGUI is A library that helps with the most common and generic UI elements and functionalities
625
664
  *
@@ -1003,7 +1042,7 @@ class DialogService extends SingletoneStrictClass {
1003
1042
  */
1004
1043
  addDialog(dialogComponentClass, properties) {
1005
1044
  if (!this._isEnabled) {
1006
- return Promise.reject(new Error('Dialog service is disabled'));
1045
+ return Promise.resolve({ index: -1 });
1007
1046
  }
1008
1047
  return new Promise((resolve) => {
1009
1048
  // Set the default values for non specified properties
@@ -1075,6 +1114,130 @@ class DialogService extends SingletoneStrictClass {
1075
1114
  });
1076
1115
  });
1077
1116
  }
1117
+ /**
1118
+ * Shows a native OS file browser dialog to let the user select a single file from their local file system.
1119
+ *
1120
+ * @param options An object containing options for the file browser dialog:
1121
+ * - accept: A string that defines the file types the file input should accept. For example: '.csv,.xlsx', 'image/*', '.pdf', 'image/jpeg, image/png'.
1122
+ * - maxFileSize: (Optional) The maximum file size in bytes allowed for the selected file. If the selected file exceeds this size, the promise will be rejected with an error
1123
+ * - loadData: (Optional) Defines how the file content should be read and returned.
1124
+ * 'no' (default): Returns the raw File object without its data.
1125
+ * 'ArrayBuffer': Returns the File object with its content read as a raw binary `ArrayBuffer` in the `data` property.
1126
+ * 'text': Returns the File object with its content read as a text string in the `data` property.
1127
+ * 'base64': Returns the File object with its content read as a Base64 encoded string in the `data` property.
1128
+ *
1129
+ * @returns A Promise that resolves with the selected `File` object (which may have an added `data` property), or `null` if the user cancels the dialog.
1130
+ * The promise will be rejected with an Error if the selected file exceeds the specified size limits.
1131
+ */
1132
+ async addFileBrowserDialog(options) {
1133
+ const files = await this._addFileBrowserDialogInternal({
1134
+ multiple: false,
1135
+ accept: options.accept,
1136
+ maxFileSize: options.maxFileSize,
1137
+ loadData: options.loadData
1138
+ });
1139
+ return files ? files[0] : null;
1140
+ }
1141
+ /**
1142
+ * Shows a native OS file browser dialog to let the user select one or more files from their local file system.
1143
+ *
1144
+ * @param options An object containing options for the file browser dialog:
1145
+ * - accept: A string that defines the file types the file input should accept. For example: '.csv,.xlsx', 'image/*', '.pdf', 'image/jpeg, image/png'.
1146
+ * - maxFileSize: (Optional) The maximum file size in bytes allowed for any single selected file. If a selected file exceeds this size, the promise will be rejected with an error.
1147
+ * - maxTotalSize: (Optional) The maximum total size in bytes for all selected files combined. If the total size of all files exceeds this limit, the promise will be rejected with an error.
1148
+ * - loadData: (Optional) Defines how the file content should be read and returned.
1149
+ * 'no' (default): Returns an array of `File` objects without their data.
1150
+ * 'ArrayBuffer': Returns an array of `File` objects, each with its content read as a raw binary `ArrayBuffer` in the `data` property.
1151
+ * 'text': Returns an array of `File` objects, each with its content read as a text string in the `data` property.
1152
+ * 'base64': Returns an array of `File` objects, each with its content read as a Base64 encoded string in the `data` property.
1153
+ *
1154
+ * @returns A Promise that resolves with an array of `File` objects (which may have an added `data` property), or `null` if the user cancels the dialog.
1155
+ * The promise will be rejected with an Error if the selected files exceed the specified size limits.
1156
+ */
1157
+ addFilesBrowserDialog(options) {
1158
+ return this._addFileBrowserDialogInternal({
1159
+ multiple: true,
1160
+ accept: options.accept,
1161
+ maxFileSize: options.maxFileSize,
1162
+ maxTotalSize: options.maxTotalSize,
1163
+ loadData: options.loadData
1164
+ });
1165
+ }
1166
+ /**
1167
+ * Auxiliary method that combines the logic for addFileBrowserDialog and addFilesBrowserDialog
1168
+ */
1169
+ async _addFileBrowserDialogInternal(options) {
1170
+ if (!this._isEnabled) {
1171
+ return null;
1172
+ }
1173
+ // Create a hidden input element to show the file browser dialog
1174
+ const input = this._renderer.createElement('input');
1175
+ this._renderer.setAttribute(input, 'type', 'file');
1176
+ this._renderer.setAttribute(input, 'accept', options.accept);
1177
+ this._renderer.setAttribute(input, 'id', 'turbogui-file-browser-input-hidden-dialog');
1178
+ if (options.multiple) {
1179
+ this._renderer.setAttribute(input, 'multiple', 'true');
1180
+ }
1181
+ this._renderer.setStyle(input, 'display', 'none');
1182
+ this._renderer.appendChild(document.body, input);
1183
+ try {
1184
+ const files = await new Promise((resolve) => {
1185
+ const onFocus = () => {
1186
+ setTimeout(() => {
1187
+ if (!input.files || input.files.length === 0) {
1188
+ resolve(null);
1189
+ }
1190
+ }, 600);
1191
+ };
1192
+ const onChange = (event) => {
1193
+ const fileList = event.target.files;
1194
+ resolve(fileList ? Array.from(fileList) : null);
1195
+ };
1196
+ input.addEventListener('change', onChange);
1197
+ window.addEventListener('focus', onFocus, { once: true });
1198
+ input.click();
1199
+ });
1200
+ if (!files || files.length === 0) {
1201
+ return null;
1202
+ }
1203
+ let totalSize = 0;
1204
+ for (const file of files) {
1205
+ if (options.maxFileSize !== undefined && file.size > options.maxFileSize) {
1206
+ throw new Error(`Max file size exceeded: "${file.name}" exceeds ${options.maxFileSize} bytes`);
1207
+ }
1208
+ totalSize += file.size;
1209
+ }
1210
+ if (options.maxTotalSize !== undefined && totalSize > options.maxTotalSize) {
1211
+ throw new Error(`Max total size exceeded: ${options.maxTotalSize} bytes`);
1212
+ }
1213
+ if (!options.loadData || options.loadData === 'no') {
1214
+ return files;
1215
+ }
1216
+ const fileReadPromises = files.map(async (file) => {
1217
+ switch (options.loadData) {
1218
+ case 'ArrayBuffer':
1219
+ file.data = await file.arrayBuffer();
1220
+ break;
1221
+ case 'text':
1222
+ file.data = await file.text();
1223
+ break;
1224
+ case 'base64':
1225
+ file.data = await new Promise((resolve, reject) => {
1226
+ const reader = new FileReader();
1227
+ reader.onload = () => resolve(reader.result.split(',')[1]);
1228
+ reader.onerror = () => reject(reader.error ?? new Error('Unknown FileReader error'));
1229
+ reader.readAsDataURL(file);
1230
+ });
1231
+ break;
1232
+ }
1233
+ return file;
1234
+ });
1235
+ return await Promise.all(fileReadPromises);
1236
+ }
1237
+ finally {
1238
+ this._renderer.removeChild(document.body, input);
1239
+ }
1240
+ }
1078
1241
  /**
1079
1242
  * Show a dialog with an iframe inside it, to show external web pages or web applications.
1080
1243
  *
@@ -1107,6 +1270,38 @@ class DialogService extends SingletoneStrictClass {
1107
1270
  }
1108
1271
  return null;
1109
1272
  }
1273
+ /**
1274
+ * Show a dialog with an image inside it, to load image files from a url.
1275
+ *
1276
+ * This method is a shortcut for addDialog() method using DialogImageComponent as the dialog component class
1277
+ *
1278
+ * @param properties An object containing the different visual and textual options that this dialog allows:
1279
+ * - url (mandatory): The url to load in the image
1280
+ * - title: The title to show at the top of the dialog
1281
+ * - id: see addDialog() docs
1282
+ * - width: see addDialog() docs
1283
+ * - maxWidth: see addDialog() docs
1284
+ * - height: see addDialog() docs
1285
+ * - maxHeight: see addDialog() docs
1286
+ * - modal: see addDialog() docs
1287
+ *
1288
+ * @returns A Promise that resolves once the user closes the dialog
1289
+ */
1290
+ async addImageDialog(properties) {
1291
+ if (this._isEnabled) {
1292
+ await this.addDialog(DialogImageComponent, {
1293
+ id: properties.id ?? undefined,
1294
+ data: properties.url,
1295
+ texts: properties.title ? [properties.title] : undefined,
1296
+ width: properties.width ?? "85vw",
1297
+ maxWidth: properties.maxWidth ?? "1200px",
1298
+ height: properties.height ?? "98vh",
1299
+ maxHeight: properties.maxHeight ?? "3000px",
1300
+ modal: properties.modal ?? false
1301
+ });
1302
+ }
1303
+ return null;
1304
+ }
1110
1305
  /**
1111
1306
  * Show a dialog with a pdf from a binary blob data.
1112
1307
  *
@@ -1151,7 +1346,7 @@ class DialogService extends SingletoneStrictClass {
1151
1346
  * - maxHeight: see addDialog() docs
1152
1347
  * - modal: see addDialog() docs
1153
1348
  * - title: The title to show at the top of the dialog
1154
- * - viewContainerRef: see addDialog() docs
1349
+ * - viewContainerRef: MANDATORY! or the component won't render. see addDialog() docs
1155
1350
  *
1156
1351
  * @returns A Promise that resolves to a Date() object selected by the user or null if no selection was made
1157
1352
  */
@@ -1972,6 +2167,38 @@ class RouterBaseService {
1972
2167
  }
1973
2168
  return currentRoute.params[key];
1974
2169
  }
2170
+ /**
2171
+ * Gets the value of a specific query parameter by its key from the current route.
2172
+ * For example, if the current route is `/search?query=angular`, and you call this method with `key` as `query`, it will return `angular`.
2173
+ *
2174
+ * @param key The key of the query parameter to retrieve.
2175
+ */
2176
+ getQueryParamValue(key) {
2177
+ let currentRoute = this.router.routerState.snapshot.root;
2178
+ while (currentRoute.firstChild) {
2179
+ currentRoute = currentRoute.firstChild;
2180
+ }
2181
+ return currentRoute.queryParams[key];
2182
+ }
2183
+ /**
2184
+ * Sets or updates the value of a specific query parameter in the current route.
2185
+ * For example, if the current route is `/search?query=angular`, and you call this method with `key` as `page` and `value` as `2`,
2186
+ * it will navigate to `/search?query=angular&page=2`.
2187
+ *
2188
+ * @param key The key of the query parameter to set or update.
2189
+ * @param value The value to set for the specified query parameter.
2190
+ */
2191
+ setQueryParamValue(key, value) {
2192
+ let currentRoute = this.router.routerState.root;
2193
+ while (currentRoute.firstChild) {
2194
+ currentRoute = currentRoute.firstChild;
2195
+ }
2196
+ this.router.navigate([], {
2197
+ relativeTo: currentRoute,
2198
+ queryParams: { [key]: value },
2199
+ queryParamsHandling: 'merge'
2200
+ });
2201
+ }
1975
2202
  /**
1976
2203
  * Initializes the title management feature to automatically refresh the browser title based on the current
1977
2204
  * URL route. It Must be called once, typically at application startup
@@ -3414,5 +3641,5 @@ class ValidatorsPlus extends Validators {
3414
3641
  * Generated bundle index. Do not edit.
3415
3642
  */
3416
3643
 
3417
- export { AutoFocusOnDisplayDirective, AutoSelectTextOnFocusDirective, BrowserService, BusyStateBaseComponent, ButtonContainerComponent, ButtonImageComponent, DelayedMethodCallManager, DialogBaseComponent, DialogDateSelectionComponent, DialogErrorComponent, DialogIFrameComponent, DialogMultipleOptionComponent, DialogService, DialogSingleInputComponent, DialogSingleOptionComponent, DialogSingleSelectionListComponent, DialogTwoOptionComponent, ElementClickOutsideDirective, ElementCreatedDirective, ElementDestroyedDirective, FadeAnimationClass, GUINotification, GlobalErrorService, HTTPService, HTTPServiceGetRequest, HTTPServicePostRequest, LocalesBaseService, NotificationService, RouterBaseService, SingletoneStrictClass, TurboApiService, TurboGuiAngularModule, ValidatorsPlus, View, ViewService };
3644
+ export { AutoFocusOnDisplayDirective, AutoSelectTextOnFocusDirective, BrowserService, BusyStateBaseComponent, ButtonContainerComponent, ButtonImageComponent, DelayedMethodCallManager, DialogBaseComponent, DialogDateSelectionComponent, DialogErrorComponent, DialogIFrameComponent, DialogImageComponent, DialogMultipleOptionComponent, DialogService, DialogSingleInputComponent, DialogSingleOptionComponent, DialogSingleSelectionListComponent, DialogTwoOptionComponent, ElementClickOutsideDirective, ElementCreatedDirective, ElementDestroyedDirective, FadeAnimationClass, GUINotification, GlobalErrorService, HTTPService, HTTPServiceGetRequest, HTTPServicePostRequest, LocalesBaseService, NotificationService, RouterBaseService, SingletoneStrictClass, TurboApiService, TurboGuiAngularModule, ValidatorsPlus, View, ViewService };
3418
3645
  //# sourceMappingURL=turbogui-angular.mjs.map